|
|
@@ -1,13 +1,23 @@
|
|
|
/* tslint:disable:no-console */
|
|
|
import chalk from 'chalk';
|
|
|
import program from 'commander';
|
|
|
+import detectPort from 'detect-port';
|
|
|
import fs from 'fs-extra';
|
|
|
import Listr from 'listr';
|
|
|
import os from 'os';
|
|
|
import path from 'path';
|
|
|
+import { Observable } from 'rxjs';
|
|
|
|
|
|
import { gatherUserResponses } from './gather-user-responses';
|
|
|
-import { checkNodeVersion, checkThatNpmCanReadCwd, getDependencies, installPackages, isSafeToCreateProjectIn, shouldUseYarn } from './helpers';
|
|
|
+import {
|
|
|
+ checkNodeVersion,
|
|
|
+ checkThatNpmCanReadCwd,
|
|
|
+ getDependencies,
|
|
|
+ installPackages,
|
|
|
+ isSafeToCreateProjectIn,
|
|
|
+ shouldUseYarn,
|
|
|
+} from './helpers';
|
|
|
+import { LogLevel } from './types';
|
|
|
|
|
|
// tslint:disable-next-line:no-var-requires
|
|
|
const packageJson = require('../package.json');
|
|
|
@@ -23,17 +33,25 @@ program
|
|
|
.action(name => {
|
|
|
projectName = name;
|
|
|
})
|
|
|
- .option('--verbose', 'print additional logs')
|
|
|
- .option('--use-npm')
|
|
|
+ .option(
|
|
|
+ '-log-level <logLevel>',
|
|
|
+ 'Log level, either \'silent\', \'info\', or \'verbose\'',
|
|
|
+ /^(silent|info|verbose)$/i,
|
|
|
+ 'silent',
|
|
|
+ )
|
|
|
+ .option('--use-npm', 'Uses npm rather than Yarn as the default package manager')
|
|
|
.parse(process.argv);
|
|
|
|
|
|
-createApp(projectName, program.useNpm, program.verbose);
|
|
|
+createApp(projectName, program.useNpm, program.logLevel || 'silent');
|
|
|
|
|
|
-async function createApp(name: string | undefined, useNpm: boolean, verbose: boolean) {
|
|
|
+async function createApp(name: string | undefined, useNpm: boolean, logLevel: LogLevel) {
|
|
|
if (!runPreChecks(name, useNpm)) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ console.log(`Let's configure a new Vendure project. First a few questions:`);
|
|
|
+ console.log();
|
|
|
+
|
|
|
const root = path.resolve(name);
|
|
|
const appName = path.basename(root);
|
|
|
const { dbType, usingTs, configSource, indexSource, populateProducts } = await gatherUserResponses(root);
|
|
|
@@ -53,58 +71,101 @@ async function createApp(name: string | undefined, useNpm: boolean, verbose: boo
|
|
|
process.exit(1);
|
|
|
}
|
|
|
|
|
|
+ console.log();
|
|
|
+ console.log(`Setting up your new Vendure project in ${chalk.green(root)}`);
|
|
|
+ console.log('This may take a few minutes...');
|
|
|
+ console.log();
|
|
|
+
|
|
|
const tasks = new Listr([
|
|
|
{
|
|
|
title: 'Installing dependencies',
|
|
|
- task: async () => {
|
|
|
- fs.writeFileSync(
|
|
|
- path.join(root, 'package.json'),
|
|
|
- JSON.stringify(packageJsonContents, null, 2) + os.EOL,
|
|
|
- );
|
|
|
- const { dependencies, devDependencies } = getDependencies(usingTs, dbType);
|
|
|
- await installPackages(root, useYarn, dependencies, false, verbose);
|
|
|
- await installPackages(root, useYarn, devDependencies, true, verbose);
|
|
|
- },
|
|
|
+ task: (() => {
|
|
|
+ return new Observable(subscriber => {
|
|
|
+ fs.writeFileSync(
|
|
|
+ path.join(root, 'package.json'),
|
|
|
+ JSON.stringify(packageJsonContents, null, 2) + os.EOL,
|
|
|
+ );
|
|
|
+ subscriber.next('Created package.json');
|
|
|
+ const { dependencies, devDependencies } = getDependencies(usingTs, dbType);
|
|
|
+
|
|
|
+ installPackages(root, useYarn, dependencies, false, logLevel)
|
|
|
+ .then(() => subscriber.next(`Installed ${dependencies.join(', ')}`))
|
|
|
+ .then(() => {
|
|
|
+ if (devDependencies.length) {
|
|
|
+ return installPackages(root, useYarn, devDependencies, true, logLevel)
|
|
|
+ .then(() => subscriber.next(`Installed ${devDependencies.join(', ')}`));
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .then(() => subscriber.complete());
|
|
|
+ });
|
|
|
+ }) as any,
|
|
|
},
|
|
|
{
|
|
|
title: 'Generating app scaffold',
|
|
|
- task: async (ctx) => {
|
|
|
- const assetPath = (fileName: string) => path.join(__dirname, '../assets', fileName);
|
|
|
- const rootPathScript = (fileName: string): string => path.join(root, `${fileName}.${usingTs ? 'ts' : 'js'}`);
|
|
|
- ctx.configFile = rootPathScript('vendure-config');
|
|
|
- await fs.writeFile(ctx.configFile, configSource);
|
|
|
- await fs.writeFile(rootPathScript('index'), indexSource);
|
|
|
- if (usingTs) {
|
|
|
- await fs.copyFile(assetPath('tsconfig.template.json'), path.join(root, 'tsconfig.json'));
|
|
|
- }
|
|
|
- await createDirectoryStructure(root);
|
|
|
- await copyEmailTemplates(root);
|
|
|
+ task: ctx => {
|
|
|
+ return new Observable(subscriber => {
|
|
|
+ const assetPath = (fileName: string) => path.join(__dirname, '../assets', fileName);
|
|
|
+ const rootPathScript = (fileName: string): string =>
|
|
|
+ path.join(root, `${fileName}.${usingTs ? 'ts' : 'js'}`);
|
|
|
+ ctx.configFile = rootPathScript('vendure-config');
|
|
|
+
|
|
|
+ fs.writeFile(ctx.configFile, configSource)
|
|
|
+ .then(() => {
|
|
|
+ subscriber.next(`Created config`);
|
|
|
+ return fs.writeFile(rootPathScript('index'), indexSource);
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ subscriber.next(`Created index`);
|
|
|
+ if (usingTs) {
|
|
|
+ return fs.copyFile(assetPath('tsconfig.template.json'), path.join(root, 'tsconfig.json'));
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .then(() => createDirectoryStructure(root))
|
|
|
+ .then(() => {
|
|
|
+ subscriber.next(`Created directory structure`);
|
|
|
+ return copyEmailTemplates(root);
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ subscriber.next(`Copied email templates`);
|
|
|
+ subscriber.complete();
|
|
|
+ });
|
|
|
+ });
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
title: 'Initializing server',
|
|
|
- task: async (ctx) => {
|
|
|
+ task: async ctx => {
|
|
|
try {
|
|
|
if (usingTs) {
|
|
|
// register ts-node so that the config file can be loaded
|
|
|
require(path.join(root, 'node_modules/ts-node')).register();
|
|
|
}
|
|
|
- const { populate } = await import(path.join(root, 'node_modules/@vendure/core/dist/cli/populate'));
|
|
|
- const { bootstrap } = await import(path.join(root, 'node_modules/@vendure/core/dist/bootstrap'));
|
|
|
+ const { populate } = await import(path.join(
|
|
|
+ root,
|
|
|
+ 'node_modules/@vendure/core/dist/cli/populate',
|
|
|
+ ));
|
|
|
+ const { bootstrap } = await import(path.join(
|
|
|
+ root,
|
|
|
+ 'node_modules/@vendure/core/dist/bootstrap',
|
|
|
+ ));
|
|
|
const { config } = await import(ctx.configFile);
|
|
|
const assetsDir = path.join(__dirname, '../assets');
|
|
|
|
|
|
const initialDataPath = path.join(assetsDir, 'initial-data.json');
|
|
|
- const bootstrapFn = () => bootstrap({
|
|
|
- ...config,
|
|
|
- dbConnectionOptions: {
|
|
|
- ...config.dbConnectionOptions,
|
|
|
- synchronize: true,
|
|
|
- },
|
|
|
- importExportOptions: {
|
|
|
- importAssetsDir: path.join(assetsDir, 'images'),
|
|
|
- },
|
|
|
- });
|
|
|
+ const port = await detectPort(3000);
|
|
|
+ const bootstrapFn = () =>
|
|
|
+ bootstrap({
|
|
|
+ ...config,
|
|
|
+ port,
|
|
|
+ silent: logLevel === 'silent',
|
|
|
+ dbConnectionOptions: {
|
|
|
+ ...config.dbConnectionOptions,
|
|
|
+ synchronize: true,
|
|
|
+ },
|
|
|
+ importExportOptions: {
|
|
|
+ importAssetsDir: path.join(assetsDir, 'images'),
|
|
|
+ },
|
|
|
+ });
|
|
|
let app: any;
|
|
|
if (populateProducts) {
|
|
|
app = await populate(
|
|
|
@@ -114,10 +175,7 @@ async function createApp(name: string | undefined, useNpm: boolean, verbose: boo
|
|
|
path.join(assetsDir, 'images'),
|
|
|
);
|
|
|
} else {
|
|
|
- app = await populate(
|
|
|
- bootstrapFn,
|
|
|
- initialDataPath,
|
|
|
- );
|
|
|
+ app = await populate(bootstrapFn, initialDataPath);
|
|
|
}
|
|
|
await app.close();
|
|
|
} catch (e) {
|
|
|
@@ -133,6 +191,16 @@ async function createApp(name: string | undefined, useNpm: boolean, verbose: boo
|
|
|
} catch (e) {
|
|
|
console.error(chalk.red(e));
|
|
|
}
|
|
|
+ const startCommand = useYarn ? 'yarn start' : 'npm run start';
|
|
|
+ console.log();
|
|
|
+ console.log(chalk.green(`Success! Created a new Vendure server at ${root}`));
|
|
|
+ console.log();
|
|
|
+ console.log(`We suggest that you start by typing:`);
|
|
|
+ console.log();
|
|
|
+ console.log(chalk.green(` cd ${name}`));
|
|
|
+ console.log(chalk.green(` ${startCommand}`));
|
|
|
+ console.log();
|
|
|
+ console.log('Happy hacking!');
|
|
|
process.exit(0);
|
|
|
}
|
|
|
|
|
|
@@ -143,9 +211,7 @@ async function createApp(name: string | undefined, useNpm: boolean, verbose: boo
|
|
|
function runPreChecks(name: string | undefined, useNpm: boolean): name is string {
|
|
|
if (typeof name === 'undefined') {
|
|
|
console.error('Please specify the project directory:');
|
|
|
- console.log(
|
|
|
- ` ${chalk.cyan(program.name())} ${chalk.green('<project-directory>')}`,
|
|
|
- );
|
|
|
+ console.log(` ${chalk.cyan(program.name())} ${chalk.green('<project-directory>')}`);
|
|
|
console.log();
|
|
|
console.log('For example:');
|
|
|
console.log(` ${chalk.cyan(program.name())} ${chalk.green('my-vendure-app')}`);
|
|
|
@@ -158,8 +224,6 @@ function runPreChecks(name: string | undefined, useNpm: boolean): name is string
|
|
|
if (!isSafeToCreateProjectIn(root, name)) {
|
|
|
process.exit(1);
|
|
|
}
|
|
|
- console.log(`Creating a new Vendure app in ${chalk.green(root)}.`);
|
|
|
- console.log();
|
|
|
return true;
|
|
|
}
|
|
|
|