From 746abff9d319687a40b4a876e1ed7db7cfe811dc Mon Sep 17 00:00:00 2001 From: Michael Bromley Date: Wed, 16 Oct 2019 10:33:56 +0200 Subject: [PATCH] feat(create): Rework folder structure, add build & migration scripts Closes #175 --- packages/create/src/create-vendure-app.ts | 47 +++++++++++++------ packages/create/src/gather-user-responses.ts | 23 +++++++-- packages/create/src/types.ts | 1 + packages/create/templates/migration.hbs | 27 +++++++++++ .../create/templates/tsconfig.template.json | 2 +- packages/create/templates/vendure-config.hbs | 10 ++-- 6 files changed, 85 insertions(+), 25 deletions(-) create mode 100644 packages/create/templates/migration.hbs diff --git a/packages/create/src/create-vendure-app.ts b/packages/create/src/create-vendure-app.ts index c6e2dbe0e2..d4ea864009 100644 --- a/packages/create/src/create-vendure-app.ts +++ b/packages/create/src/create-vendure-app.ts @@ -69,9 +69,15 @@ async function createApp( const root = path.resolve(name); const appName = path.basename(root); - const { dbType, usingTs, configSource, indexSource, indexWorkerSource, populateProducts } = isCi - ? await gatherCiUserResponses(root) - : await gatherUserResponses(root); + const { + dbType, + usingTs, + configSource, + indexSource, + indexWorkerSource, + migrationSource, + populateProducts, + } = isCi ? await gatherCiUserResponses(root) : await gatherUserResponses(root); const useYarn = useNpm ? false : shouldUseYarn(); const originalDirectory = process.cwd(); @@ -85,9 +91,13 @@ async function createApp( version: '0.1.0', private: true, scripts: { - 'run:server': usingTs ? 'ts-node index.ts' : 'node index.js', - 'run:worker': usingTs ? 'ts-node index-worker.ts' : 'node index-worker.js', + 'run:server': usingTs ? 'ts-node ./src/index.ts' : 'node ./src/index.js', + 'run:worker': usingTs ? 'ts-node ./src/index-worker.ts' : 'node ./src/index-worker.js', start: useYarn ? 'concurrently yarn:run:*' : 'concurrently npm:run:*', + ...(usingTs ? { build: 'tsc' } : undefined), + 'migration:generate': usingTs ? 'ts-node migration generate' : 'node migration generate', + 'migration:run': usingTs ? 'ts-node migration run' : 'node migration run', + 'migration:revert': usingTs ? 'ts-node migration revert' : 'node migration revert', }, }; @@ -129,22 +139,29 @@ async function createApp( title: 'Generating app scaffold', task: ctx => { return new Observable(subscriber => { + fs.ensureDirSync(path.join(root, 'src')); const assetPath = (fileName: string) => path.join(__dirname, '../assets', fileName); + const srcPathScript = (fileName: string): string => + path.join(root, 'src', `${fileName}.${usingTs ? 'ts' : 'js'}`); const rootPathScript = (fileName: string): string => path.join(root, `${fileName}.${usingTs ? 'ts' : 'js'}`); - ctx.configFile = rootPathScript('vendure-config'); + ctx.configFile = srcPathScript('vendure-config'); fs.writeFile(ctx.configFile, configSource) .then(() => { - subscriber.next(`Created config`); - return fs.writeFile(rootPathScript('index'), indexSource); + subscriber.next(`Created config file`); + return fs.writeFile(srcPathScript('index'), indexSource); }) .then(() => { - subscriber.next(`Created index`); - return fs.writeFile(rootPathScript('index-worker'), indexWorkerSource); + subscriber.next(`Created index file`); + return fs.writeFile(srcPathScript('index-worker'), indexWorkerSource); }) .then(() => { - subscriber.next(`Created worker`); + subscriber.next(`Created worker file`); + return fs.writeFile(rootPathScript('migration'), migrationSource); + }) + .then(() => { + subscriber.next(`Created migration file`); if (usingTs) { return fs.copyFile( assetPath('tsconfig.template.json'), @@ -274,9 +291,9 @@ function runPreChecks(name: string | undefined, useNpm: boolean): name is string * Generate the default directory structure for a new Vendure project */ async function createDirectoryStructure(root: string) { - await fs.ensureDir(path.join(root, 'vendure', 'email', 'test-emails')); - await fs.ensureDir(path.join(root, 'vendure', 'import-assets')); - await fs.ensureDir(path.join(root, 'vendure', 'assets')); + await fs.ensureDir(path.join(root, 'static', 'email', 'test-emails')); + await fs.ensureDir(path.join(root, 'static', 'import-assets')); + await fs.ensureDir(path.join(root, 'static', 'assets')); } /** @@ -285,7 +302,7 @@ async function createDirectoryStructure(root: string) { async function copyEmailTemplates(root: string) { const templateDir = path.join(root, 'node_modules/@vendure/email-plugin/templates'); try { - await fs.copy(templateDir, path.join(root, 'vendure', 'email', 'templates')); + await fs.copy(templateDir, path.join(root, 'static', 'email', 'templates')); } catch (err) { console.error(chalk.red(`Failed to copy email templates.`)); } diff --git a/packages/create/src/gather-user-responses.ts b/packages/create/src/gather-user-responses.ts index 3666921c7e..5aafd55149 100644 --- a/packages/create/src/gather-user-responses.ts +++ b/packages/create/src/gather-user-responses.ts @@ -94,11 +94,15 @@ export async function gatherUserResponses(root: string): Promise process.exit(0); } - const { indexSource, indexWorkerSource, configSource } = await generateSources(root, answers); + const { indexSource, indexWorkerSource, configSource, migrationSource } = await generateSources( + root, + answers, + ); return { indexSource, indexWorkerSource, configSource, + migrationSource, usingTs: answers.language === 'ts', dbType: answers.dbType, populateProducts: answers.populateProducts, @@ -119,11 +123,15 @@ export async function gatherCiUserResponses(root: string): Promise { +): Promise<{ + indexSource: string; + indexWorkerSource: string; + configSource: string; + migrationSource: string; +}> { const assetPath = (fileName: string) => path.join(__dirname, '../assets', fileName); const templateContext = { @@ -155,7 +168,9 @@ async function generateSources( const indexSource = Handlebars.compile(indexTemplate)(templateContext); const indexWorkerTemplate = await fs.readFile(assetPath('index-worker.hbs'), 'utf-8'); const indexWorkerSource = Handlebars.compile(indexWorkerTemplate)(templateContext); - return { indexSource, indexWorkerSource, configSource }; + const migrationTemplate = await fs.readFile(assetPath('migration.hbs'), 'utf-8'); + const migrationSource = Handlebars.compile(migrationTemplate)(templateContext); + return { indexSource, indexWorkerSource, configSource, migrationSource }; } function defaultDBPort(dbType: DbType): number { diff --git a/packages/create/src/types.ts b/packages/create/src/types.ts index af6dcc0938..312045a8cb 100644 --- a/packages/create/src/types.ts +++ b/packages/create/src/types.ts @@ -7,6 +7,7 @@ export interface UserResponses { indexSource: string; indexWorkerSource: string; configSource: string; + migrationSource: string; } export type CliLogLevel = 'silent' | 'info' | 'verbose'; diff --git a/packages/create/templates/migration.hbs b/packages/create/templates/migration.hbs new file mode 100644 index 0000000000..e2922e0ce3 --- /dev/null +++ b/packages/create/templates/migration.hbs @@ -0,0 +1,27 @@ +{{#if isTs }}import { generateMigration, revertLastMigration, runMigrations } from '@vendure/core';{{else}}const { generateMigration, revertLastMigration, runMigrations } = require('@vendure/core');{{/if}} +{{#if isTs }}import program from 'commander';{{else}}const program = require('commander');{{/if}} + +{{#if isTs }}import { config } from './src/vendure-config';{{else}}const { config } = require('./src/vendure-config');{{/if}} + +program + .command('generate ') + .description('Generate a new migration file with the given name') + .action(name => { + return generateMigration(config, { name, outputDir: './migrations' }); + }); + +program + .command('run') + .description('Run all pending migrations') + .action(() => { + return runMigrations(config); + }); + +program + .command('revert') + .description('Revert the last applied migration') + .action(() => { + return revertLastMigration(config); + }); + +program.parse(process.argv); diff --git a/packages/create/templates/tsconfig.template.json b/packages/create/templates/tsconfig.template.json index 0bfbb95ea4..5ce23d64f0 100644 --- a/packages/create/templates/tsconfig.template.json +++ b/packages/create/templates/tsconfig.template.json @@ -11,5 +11,5 @@ "outDir": "./dist", "baseUrl": "./" }, - "exclude": ["node_modules"] + "exclude": ["node_modules", "migration.ts"] } diff --git a/packages/create/templates/vendure-config.hbs b/packages/create/templates/vendure-config.hbs index 576c87ccc2..5b8afd41f3 100644 --- a/packages/create/templates/vendure-config.hbs +++ b/packages/create/templates/vendure-config.hbs @@ -39,7 +39,7 @@ const path = require('path'); synchronize: false, // not working with SQLite/SQL.js, see https://github.com/typeorm/typeorm/issues/2576 {{/if}} logging: false, - database: {{#if isSQLjs}}new Uint8Array([]){{else if isSQLite}}path.join(__dirname, 'vendure.sqlite'){{else}}'{{ dbName }}'{{/if}}, + database: {{#if isSQLjs}}new Uint8Array([]){{else if isSQLite}}path.join(__dirname, '../vendure.sqlite'){{else}}'{{ dbName }}'{{/if}}, {{#if isSQLjs}} location: path.join(__dirname, 'vendure.sqlite'), autoSave: true, @@ -50,7 +50,7 @@ const path = require('path'); username: '{{ dbUserName }}', password: '{{ dbPassword }}', {{/if}} - migrations: [path.join(__dirname, 'migrations/*.ts')], + migrations: [path.join(__dirname, '../migrations/*.ts')], }, paymentOptions: { paymentMethodHandlers: [examplePaymentHandler], @@ -59,16 +59,16 @@ const path = require('path'); plugins: [ AssetServerPlugin.init({ route: 'assets', - assetUploadDir: path.join(__dirname, 'vendure/assets'), + assetUploadDir: path.join(__dirname, '../static/assets'), port: 3001, }), DefaultSearchPlugin, EmailPlugin.init({ devMode: true, - outputPath: path.join(__dirname, 'vendure/email/test-emails'), + outputPath: path.join(__dirname, '../static/email/test-emails'), mailboxPort: 3003, handlers: defaultEmailHandlers, - templatePath: path.join(__dirname, 'vendure/email/templates'), + templatePath: path.join(__dirname, '../static/email/templates'), globalTemplateVars: { // The following variables will change depending on your storefront implementation fromAddress: '"example" ',