import * as fs from 'fs'; import * as path from 'path'; import * as dotenv from 'dotenv'; import * as log from 'npmlog'; import type { ExecutorContext } from '@nrwl/devkit'; import devServerExecutor, { WebDevServerOptions, } from '@nrwl/web/src/executors/dev-server/dev-server.impl'; type Schema = WebDevServerOptions & { env?: string; }; const LOGGER_SCOPE = 'tools/executors/serve'; const logEnvData = ( envMap: Record, envFiles: string[], env?: string, defaultEnvFile?: string ) => { if (env && !envMap[env]) { log.warn(LOGGER_SCOPE, `No environment called "${env}" found.`); log.info( LOGGER_SCOPE, envFiles.length > 0 ? `You can create a new environment by putting an ".env.${env}" file in your project root, or you can use the following available ones: ${envFiles.join( ', ' )}.` : 'To get started with environments, you can create an ".env" file in your project root with the desired variables.' ); } if (!envMap[env]) { log.info( LOGGER_SCOPE, defaultEnvFile ? `Using "${defaultEnvFile}" as the default project environment.` : 'Serving the project only using the environment variables scoped to your CLI.' ); } else { log.info( LOGGER_SCOPE, `Using "${envMap[env]}" as the default project environment.` ); } }; const filenameToEnv = (filename: string) => filename.replace('.env.', ''); const getDefaultEnvFile = (envMap: Record) => { return envMap['local'] || envMap['.env']; }; const getEnvFile = (env: string, envFiles: string[]) => { const envMap = envFiles.reduce( (acc, filename) => ({ ...acc, [filenameToEnv(filename)]: filename, }), {} ); const defaultEnvFile = getDefaultEnvFile(envMap); logEnvData(envMap, envFiles, env, defaultEnvFile); return envMap[env] || defaultEnvFile; }; export default async function* serve( options: Schema, context: ExecutorContext ): ReturnType { const { env, ...dsOptions } = options; const { root } = context.workspace.projects[context.projectName]; const workspacePath = path.join(context.cwd, root); const files = await fs.promises.readdir(workspacePath); const envFile = getEnvFile( env, files.filter((f) => f.startsWith('.env')) ); if (env && envFile) { dotenv.config({ path: path.join(workspacePath, envFile), override: true }); } return yield* devServerExecutor(dsOptions, context); }