Просмотр исходного кода

feat(create): Use dotenv to handle env vars

Michael Bromley 3 лет назад
Родитель
Сommit
4fdc8aa6ea

+ 4 - 0
packages/create/src/create-vendure-app.ts

@@ -88,6 +88,8 @@ async function createApp(
     const {
         dbType,
         configSource,
+        envSource,
+        envDtsSource,
         indexSource,
         indexWorkerSource,
         migrationSource,
@@ -173,6 +175,8 @@ async function createApp(
                         ctx.configFile = srcPathScript('vendure-config');
 
                         fs.writeFile(ctx.configFile, configSource)
+                            .then(() => fs.writeFile(path.join(root, '.env'), envSource))
+                            .then(() => fs.writeFile(srcPathScript('environment.d'), envDtsSource))
                             .then(() => fs.writeFile(srcPathScript('index'), indexSource))
                             .then(() => fs.writeFile(srcPathScript('index-worker'), indexWorkerSource))
                             .then(() => fs.writeFile(rootPathScript('migration'), migrationSource))

+ 19 - 15
packages/create/src/gather-user-responses.ts

@@ -104,14 +104,8 @@ export async function gatherUserResponses(root: string, alreadyRanScaffold: bool
         },
     });
 
-    const { indexSource, indexWorkerSource, configSource, migrationSource, readmeSource } =
-        await generateSources(root, answers);
     return {
-        indexSource,
-        indexWorkerSource,
-        configSource,
-        migrationSource,
-        readmeSource,
+        ...(await generateSources(root, answers)),
         dbType: answers.dbType,
         populateProducts: answers.populateProducts,
         superadminIdentifier: answers.superadminIdentifier,
@@ -134,14 +128,9 @@ export async function gatherCiUserResponses(root: string): Promise<UserResponses
         superadminIdentifier: SUPER_ADMIN_USER_IDENTIFIER,
         superadminPassword: SUPER_ADMIN_USER_PASSWORD,
     };
-    const { indexSource, indexWorkerSource, configSource, migrationSource, readmeSource } =
-        await generateSources(root, ciAnswers);
+
     return {
-        indexSource,
-        indexWorkerSource,
-        configSource,
-        migrationSource,
-        readmeSource,
+        ...(await generateSources(root, ciAnswers)),
         dbType: ciAnswers.dbType,
         populateProducts: ciAnswers.populateProducts,
         superadminIdentifier: ciAnswers.superadminIdentifier,
@@ -159,6 +148,8 @@ async function generateSources(
     indexSource: string;
     indexWorkerSource: string;
     configSource: string;
+    envSource: string;
+    envDtsSource: string;
     migrationSource: string;
     readmeSource: string;
 }> {
@@ -180,9 +171,14 @@ async function generateSources(
         isSQLite: answers.dbType === 'sqlite',
         isSQLjs: answers.dbType === 'sqljs',
         requiresConnection: answers.dbType !== 'sqlite' && answers.dbType !== 'sqljs',
+        cookieSecret: Math.random().toString(36).substr(2),
     };
     const configTemplate = await fs.readFile(assetPath('vendure-config.hbs'), 'utf-8');
     const configSource = Handlebars.compile(configTemplate, { noEscape: true })(templateContext);
+    const envTemplate = await fs.readFile(assetPath('.env.hbs'), 'utf-8');
+    const envSource = Handlebars.compile(envTemplate, { noEscape: true })(templateContext);
+    const envDtsTemplate = await fs.readFile(assetPath('environment.d.hbs'), 'utf-8');
+    const envDtsSource = Handlebars.compile(envDtsTemplate, { noEscape: true })(templateContext);
     const indexTemplate = await fs.readFile(assetPath('index.hbs'), 'utf-8');
     const indexSource = Handlebars.compile(indexTemplate)(templateContext);
     const indexWorkerTemplate = await fs.readFile(assetPath('index-worker.hbs'), 'utf-8');
@@ -191,7 +187,15 @@ async function generateSources(
     const migrationSource = Handlebars.compile(migrationTemplate)(templateContext);
     const readmeTemplate = await fs.readFile(assetPath('readme.hbs'), 'utf-8');
     const readmeSource = Handlebars.compile(readmeTemplate)(templateContext);
-    return { indexSource, indexWorkerSource, configSource, migrationSource, readmeSource };
+    return {
+        indexSource,
+        indexWorkerSource,
+        configSource,
+        envSource,
+        envDtsSource,
+        migrationSource,
+        readmeSource,
+    };
 }
 
 function defaultDBPort(dbType: DbType): number {

+ 1 - 1
packages/create/src/helpers.ts

@@ -250,7 +250,7 @@ export function getDependencies(
         dbDriverPackage(dbType),
         `typescript@${TYPESCRIPT_VERSION}`,
     ];
-    const devDependencies = ['concurrently', 'ts-node'];
+    const devDependencies = ['concurrently', 'dotenv', 'ts-node'];
     return { dependencies, devDependencies };
 }
 

+ 2 - 0
packages/create/src/types.ts

@@ -6,6 +6,8 @@ export interface UserResponses {
     indexSource: string;
     indexWorkerSource: string;
     configSource: string;
+    envSource: string;
+    envDtsSource: string;
     migrationSource: string;
     readmeSource: string;
     superadminIdentifier: string;

+ 14 - 0
packages/create/templates/.env.hbs

@@ -0,0 +1,14 @@
+APP_ENV=dev
+COOKIE_SECRET={{ cookieSecret }}
+SUPERADMIN_USERNAME={{{ escapeSingle superadminIdentifier }}}
+SUPERADMIN_PASSWORD={{{ escapeSingle superadminPassword }}}
+{{#if requiresConnection}}
+DB_HOST={{ dbHost }}
+DB_PORT={{ dbPort }}
+DB_NAME={{{ escapeSingle dbName }}}
+DB_USERNAME={{{ escapeSingle dbUserName }}}
+DB_PASSWORD={{{ escapeSingle dbPassword }}}
+{{/if}}
+{{#if dbSchema}}
+DB_SCHEMA={{ dbSchema }}
+{{/if}}

+ 24 - 0
packages/create/templates/environment.d.hbs

@@ -0,0 +1,24 @@
+export {};
+
+// Here we declare the members of the process.env object, so that we
+// can use them in our application code in a type-safe manner.
+declare global {
+    namespace NodeJS {
+        interface ProcessEnv {
+            APP_ENV: string;
+            COOKIE_SECRET: string;
+            SUPERADMIN_USERNAME: string;
+            SUPERADMIN_PASSWORD: string;
+            {{#if requiresConnection}}
+            DB_HOST: string;
+            DB_PORT: number;
+            DB_NAME: string;
+            DB_USERNAME: string;
+            DB_PASSWORD: string;
+            {{/if}}
+            {{#if dbSchema}}
+            DB_SCHEMA: string;
+            {{/if}}
+        }
+    }
+}

+ 5 - 1
packages/create/templates/tsconfig.template.json

@@ -8,8 +8,12 @@
     "target": "es2017",
     "strict": true,
     "sourceMap": false,
+    "skipLibCheck": true,
     "outDir": "./dist",
     "baseUrl": "./"
   },
-  "exclude": ["node_modules", "migration.ts"]
+  "exclude": ["node_modules", "migration.ts"],
+  "ts-node": {
+    "files": true
+  }
 }

+ 25 - 22
packages/create/templates/vendure-config.hbs

@@ -7,52 +7,54 @@ import {
 import { defaultEmailHandlers, EmailPlugin } from '@vendure/email-plugin';
 import { AssetServerPlugin } from '@vendure/asset-server-plugin';
 import { AdminUiPlugin } from '@vendure/admin-ui-plugin';
+import 'dotenv/config';
 import path from 'path';
 
+const IS_DEV = process.env.APP_ENV === 'dev';
+
 export const config: VendureConfig = {
     apiOptions: {
         port: 3000,
         adminApiPath: 'admin-api',
-        adminApiPlayground: {
-            settings: {
-                'request.credentials': 'include',
-            } as any,
-        },// turn this off for production
-        adminApiDebug: true, // turn this off for production
         shopApiPath: 'shop-api',
-        shopApiPlayground: {
-            settings: {
-                'request.credentials': 'include',
-            } as any,
-        },// turn this off for production
-        shopApiDebug: true,// turn this off for production
+        ...(IS_DEV ? {
+            adminApiPlayground: {
+                settings: { 'request.credentials': 'include' } as any,
+            },
+            adminApiDebug: true,
+            shopApiPlayground: {
+                settings: { 'request.credentials': 'include' } as any,
+            },
+            shopApiDebug: true,
+        } : {}),
     },
     authOptions: {
+        tokenMethod: ['bearer', 'cookie'],
         superadminCredentials: {
-            identifier: '{{{ escapeSingle superadminIdentifier }}}',
-            password: '{{{ escapeSingle superadminPassword }}}',
+            identifier: process.env.SUPERADMIN_USERNAME,
+            password: process.env.SUPERADMIN_PASSWORD,
         },
         cookieOptions: {
-          secret: process.env.COOKIE_SECRET || 'cookie-secret',
+          secret: process.env.COOKIE_SECRET,
         },
     },
     dbConnectionOptions: {
         type: '{{ dbType }}',
         synchronize: true, // turn this off for production
         logging: false,
-        database: {{#if isSQLjs}}new Uint8Array([]){{else if isSQLite}}path.join(__dirname, '../vendure.sqlite'){{else}}'{{{ escapeSingle dbName }}}'{{/if}},
+        database: {{#if isSQLjs}}new Uint8Array([]){{else if isSQLite}}path.join(__dirname, '../vendure.sqlite'){{else}}process.env.DB_NAME{{/if}},
         {{#if dbSchema}}
-        schema: '{{ dbSchema }}',
+        schema: process.env.DB_SCHEMA,
         {{/if}}
         {{#if isSQLjs}}
         location: path.join(__dirname, 'vendure.sqlite'),
         autoSave: true,
         {{/if}}
         {{#if requiresConnection}}
-        host: '{{ dbHost }}',
-        port: {{ dbPort }},
-        username: '{{{ escapeSingle dbUserName }}}',
-        password: '{{{ escapeSingle dbPassword }}}',
+        host: process.env.DB_HOST,
+        port: +process.env.DB_PORT,
+        username: process.env.DB_USERNAME,
+        password: process.env.DB_PASSWORD,
         {{/if}}
         migrations: [path.join(__dirname, '../migrations/*.ts')],
     },
@@ -74,7 +76,8 @@ export const config: VendureConfig = {
             handlers: defaultEmailHandlers,
             templatePath: path.join(__dirname, '../static/email/templates'),
             globalTemplateVars: {
-                // The following variables will change depending on your storefront implementation
+                // The following variables will change depending on your storefront implementation.
+                // Here we are assuming a storefront running at http://localhost:8080.
                 fromAddress: '"example" <noreply@example.com>',
                 verifyEmailAddressUrl: 'http://localhost:8080/verify',
                 passwordResetUrl: 'http://localhost:8080/password-reset',