diff --git a/packages/@expo/env/CHANGELOG.md b/packages/@expo/env/CHANGELOG.md index cd3ed065c8ccf..3dd4ed5b18a9a 100644 --- a/packages/@expo/env/CHANGELOG.md +++ b/packages/@expo/env/CHANGELOG.md @@ -10,6 +10,8 @@ ### 💡 Others +- Warn instead of error when `NODE_ENV` is set to non-conventional value. ([#27111](https://github.com/expo/expo/pull/27111) by [@byCedric](https://github.com/byCedric)) + ## 0.2.1 — 2023-12-15 _This version does not introduce any user-facing changes._ diff --git a/packages/@expo/env/build/env.js b/packages/@expo/env/build/env.js index dd0f167f4db74..528a3c94719dd 100644 --- a/packages/@expo/env/build/env.js +++ b/packages/@expo/env/build/env.js @@ -216,7 +216,11 @@ function getFiles(mode, { } } if (mode && !['development', 'test', 'production'].includes(mode)) { - throw new Error(`Environment variable "NODE_ENV=${mode}" is invalid. Valid values are "development", "test", and "production`); + if (silent) { + debug(`NODE_ENV="${mode}" is non-conventional and might cause development code to run in production. Use "development", "test", or "production" instead.`); + } else { + console.warn(_chalk().default.yellow(`"NODE_ENV=${mode}" is non-conventional and might cause development code to run in production. Use "development", "test", or "production" instead`)); + } } if (!mode) { // Support environments that don't respect NODE_ENV diff --git a/packages/@expo/env/build/env.js.map b/packages/@expo/env/build/env.js.map index e9f782862f8cd..78e7b0f191d4a 100644 --- a/packages/@expo/env/build/env.js.map +++ b/packages/@expo/env/build/env.js.map @@ -1 +1 @@ -{"version":3,"file":"env.js","names":["_chalk","data","_interopRequireDefault","require","dotenv","_interopRequireWildcard","_dotenvExpand","fs","_getenv","path","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","prototype","hasOwnProperty","call","i","set","obj","debug","isEnabled","boolish","createControlledEnvironment","userDefinedEnvironment","undefined","memo","_getForce","projectRoot","options","env","files","process","dotenvFiles","getFiles","NODE_ENV","parsedEnv","loadedEnvFiles","reverse","forEach","dotenvFile","absoluteDotenvFile","resolve","existsSync","result","parse","readFileSync","push","key","keys","error","Error","console","message","length","_expandEnv","expandedEnv","allExpandedEnv","dotenvExpand","parsed","ignoreProcessEnv","force","load","envInfo","log","chalk","gray","map","file","basename","join","mode","silent","red","includes","filter","Boolean"],"sources":["../src/env.ts"],"sourcesContent":["/**\n * Copyright © 2023 650 Industries.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\nimport chalk from 'chalk';\nimport * as dotenv from 'dotenv';\nimport { expand as dotenvExpand } from 'dotenv-expand';\nimport * as fs from 'fs';\nimport { boolish } from 'getenv';\nimport * as path from 'path';\n\ntype LoadOptions = {\n silent?: boolean;\n force?: boolean;\n};\n\nconst debug = require('debug')('expo:env') as typeof console.log;\n\nexport function isEnabled(): boolean {\n return !boolish('EXPO_NO_DOTENV', false);\n}\n\nexport function createControlledEnvironment() {\n let userDefinedEnvironment: NodeJS.ProcessEnv | undefined = undefined;\n let memo: { env: NodeJS.ProcessEnv; files: string[] } | undefined = undefined;\n\n function _getForce(\n projectRoot: string,\n options: LoadOptions = {}\n ): { env: Record; files: string[] } {\n if (!isEnabled()) {\n debug(`Skipping .env files because EXPO_NO_DOTENV is defined`);\n return { env: {}, files: [] };\n }\n\n if (!userDefinedEnvironment) {\n userDefinedEnvironment = { ...process.env };\n }\n\n // https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use\n const dotenvFiles = getFiles(process.env.NODE_ENV, options);\n\n // Load environment variables from .env* files. Suppress warnings using silent\n // if this file is missing. Dotenv will only parse the environment variables,\n // `@expo/env` will set the resulting variables to the current process.\n // Variable expansion is supported in .env files, and executed as final step.\n // https://github.com/motdotla/dotenv\n // https://github.com/motdotla/dotenv-expand\n const parsedEnv: dotenv.DotenvParseOutput = {};\n const loadedEnvFiles: string[] = [];\n\n // Iterate over each dotenv file in lowest prio to highest prio order.\n // This step won't write to the process.env, but will overwrite the parsed envs.\n dotenvFiles.reverse().forEach((dotenvFile) => {\n const absoluteDotenvFile = path.resolve(projectRoot, dotenvFile);\n if (!fs.existsSync(absoluteDotenvFile)) {\n return;\n }\n\n try {\n const result = dotenv.parse(fs.readFileSync(absoluteDotenvFile, 'utf-8'));\n\n if (!result) {\n debug(`Failed to load environment variables from: ${absoluteDotenvFile}%s`);\n } else {\n loadedEnvFiles.push(absoluteDotenvFile);\n debug(`Loaded environment variables from: ${absoluteDotenvFile}`);\n\n for (const key of Object.keys(result)) {\n if (typeof userDefinedEnvironment?.[key] !== 'undefined') {\n debug(`\"${key}\" is already defined and IS NOT overwritten by: ${absoluteDotenvFile}`);\n } else {\n if (typeof parsedEnv[key] !== 'undefined') {\n debug(`\"${key}\" is already defined and overwritten by: ${absoluteDotenvFile}`);\n }\n\n parsedEnv[key] = result[key];\n }\n }\n }\n } catch (error: unknown) {\n if (error instanceof Error) {\n console.error(\n `Failed to load environment variables from ${absoluteDotenvFile}: ${error.message}`\n );\n } else {\n throw error;\n }\n }\n });\n\n if (!loadedEnvFiles.length) {\n debug(`No environment variables loaded from .env files.`);\n }\n\n return { env: _expandEnv(parsedEnv), files: loadedEnvFiles.reverse() };\n }\n\n /** Expand environment variables based on the current and parsed envs */\n function _expandEnv(parsedEnv: Record) {\n const expandedEnv: Record = {};\n\n // When not ignoring `process.env`, values from the parsed env are overwritten by the current env if defined.\n // We handle this ourselves, expansion should always use the current state of \"current + parsed env\".\n const allExpandedEnv = dotenvExpand({\n parsed: { ...process.env, ...parsedEnv } as Record,\n ignoreProcessEnv: true,\n });\n\n if (allExpandedEnv.error) {\n console.error(\n `Failed to expand environment variables, using non-expanded environment variables: ${allExpandedEnv.error}`\n );\n return parsedEnv;\n }\n\n for (const key of Object.keys(parsedEnv)) {\n if (allExpandedEnv.parsed?.[key]) {\n expandedEnv[key] = allExpandedEnv.parsed[key];\n }\n }\n\n return expandedEnv;\n }\n\n /** Get the environment variables without mutating the environment. This returns memoized values unless the `force` property is provided. */\n function get(\n projectRoot: string,\n options: LoadOptions = {}\n ): { env: Record; files: string[] } {\n if (!isEnabled()) {\n debug(`Skipping .env files because EXPO_NO_DOTENV is defined`);\n return { env: {}, files: [] };\n }\n if (!options.force && memo) {\n return memo;\n }\n memo = _getForce(projectRoot, options);\n return memo;\n }\n\n /** Load environment variables from .env files and mutate the current `process.env` with the results. */\n function load(projectRoot: string, options: LoadOptions = {}) {\n if (!isEnabled()) {\n debug(`Skipping .env files because EXPO_NO_DOTENV is defined`);\n return process.env;\n }\n\n const envInfo = get(projectRoot, options);\n\n if (!options.force) {\n const keys = Object.keys(envInfo.env);\n if (keys.length) {\n console.log(\n chalk.gray('env: load', envInfo.files.map((file) => path.basename(file)).join(' '))\n );\n console.log(chalk.gray('env: export', keys.join(' ')));\n }\n }\n\n for (const key of Object.keys(envInfo.env)) {\n // Avoid creating a new object, mutate it instead as this causes problems in Bun\n process.env[key] = envInfo.env[key];\n }\n\n return process.env;\n }\n\n return {\n load,\n get,\n _getForce,\n };\n}\n\nexport function getFiles(\n mode: string | undefined,\n { silent = false }: Pick = {}\n): string[] {\n if (!isEnabled()) {\n debug(`Skipping .env files because EXPO_NO_DOTENV is defined`);\n return [];\n }\n\n if (!mode) {\n if (silent) {\n debug('NODE_ENV is not defined, proceeding without mode-specific .env');\n } else {\n console.error(\n chalk.red(\n 'The NODE_ENV environment variable is required but was not specified. Ensure the project is bundled with Expo CLI or NODE_ENV is set.'\n )\n );\n console.error(chalk.red('Proceeding without mode-specific .env'));\n }\n }\n\n if (mode && !['development', 'test', 'production'].includes(mode)) {\n throw new Error(\n `Environment variable \"NODE_ENV=${mode}\" is invalid. Valid values are \"development\", \"test\", and \"production`\n );\n }\n\n if (!mode) {\n // Support environments that don't respect NODE_ENV\n return [`.env.local`, '.env'];\n }\n // https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use\n const dotenvFiles = [\n `.env.${mode}.local`,\n // Don't include `.env.local` for `test` environment\n // since normally you expect tests to produce the same\n // results for everyone\n mode !== 'test' && `.env.local`,\n `.env.${mode}`,\n '.env',\n ].filter(Boolean) as string[];\n\n return dotenvFiles;\n}\n"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"env.js","names":["_chalk","data","_interopRequireDefault","require","dotenv","_interopRequireWildcard","_dotenvExpand","fs","_getenv","path","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","prototype","hasOwnProperty","call","i","set","obj","debug","isEnabled","boolish","createControlledEnvironment","userDefinedEnvironment","undefined","memo","_getForce","projectRoot","options","env","files","process","dotenvFiles","getFiles","NODE_ENV","parsedEnv","loadedEnvFiles","reverse","forEach","dotenvFile","absoluteDotenvFile","resolve","existsSync","result","parse","readFileSync","push","key","keys","error","Error","console","message","length","_expandEnv","expandedEnv","allExpandedEnv","dotenvExpand","parsed","ignoreProcessEnv","force","load","envInfo","log","chalk","gray","map","file","basename","join","mode","silent","red","includes","warn","yellow","filter","Boolean"],"sources":["../src/env.ts"],"sourcesContent":["/**\n * Copyright © 2023 650 Industries.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\nimport chalk from 'chalk';\nimport * as dotenv from 'dotenv';\nimport { expand as dotenvExpand } from 'dotenv-expand';\nimport * as fs from 'fs';\nimport { boolish } from 'getenv';\nimport * as path from 'path';\n\ntype LoadOptions = {\n silent?: boolean;\n force?: boolean;\n};\n\nconst debug = require('debug')('expo:env') as typeof console.log;\n\nexport function isEnabled(): boolean {\n return !boolish('EXPO_NO_DOTENV', false);\n}\n\nexport function createControlledEnvironment() {\n let userDefinedEnvironment: NodeJS.ProcessEnv | undefined = undefined;\n let memo: { env: NodeJS.ProcessEnv; files: string[] } | undefined = undefined;\n\n function _getForce(\n projectRoot: string,\n options: LoadOptions = {}\n ): { env: Record; files: string[] } {\n if (!isEnabled()) {\n debug(`Skipping .env files because EXPO_NO_DOTENV is defined`);\n return { env: {}, files: [] };\n }\n\n if (!userDefinedEnvironment) {\n userDefinedEnvironment = { ...process.env };\n }\n\n // https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use\n const dotenvFiles = getFiles(process.env.NODE_ENV, options);\n\n // Load environment variables from .env* files. Suppress warnings using silent\n // if this file is missing. Dotenv will only parse the environment variables,\n // `@expo/env` will set the resulting variables to the current process.\n // Variable expansion is supported in .env files, and executed as final step.\n // https://github.com/motdotla/dotenv\n // https://github.com/motdotla/dotenv-expand\n const parsedEnv: dotenv.DotenvParseOutput = {};\n const loadedEnvFiles: string[] = [];\n\n // Iterate over each dotenv file in lowest prio to highest prio order.\n // This step won't write to the process.env, but will overwrite the parsed envs.\n dotenvFiles.reverse().forEach((dotenvFile) => {\n const absoluteDotenvFile = path.resolve(projectRoot, dotenvFile);\n if (!fs.existsSync(absoluteDotenvFile)) {\n return;\n }\n\n try {\n const result = dotenv.parse(fs.readFileSync(absoluteDotenvFile, 'utf-8'));\n\n if (!result) {\n debug(`Failed to load environment variables from: ${absoluteDotenvFile}%s`);\n } else {\n loadedEnvFiles.push(absoluteDotenvFile);\n debug(`Loaded environment variables from: ${absoluteDotenvFile}`);\n\n for (const key of Object.keys(result)) {\n if (typeof userDefinedEnvironment?.[key] !== 'undefined') {\n debug(`\"${key}\" is already defined and IS NOT overwritten by: ${absoluteDotenvFile}`);\n } else {\n if (typeof parsedEnv[key] !== 'undefined') {\n debug(`\"${key}\" is already defined and overwritten by: ${absoluteDotenvFile}`);\n }\n\n parsedEnv[key] = result[key];\n }\n }\n }\n } catch (error: unknown) {\n if (error instanceof Error) {\n console.error(\n `Failed to load environment variables from ${absoluteDotenvFile}: ${error.message}`\n );\n } else {\n throw error;\n }\n }\n });\n\n if (!loadedEnvFiles.length) {\n debug(`No environment variables loaded from .env files.`);\n }\n\n return { env: _expandEnv(parsedEnv), files: loadedEnvFiles.reverse() };\n }\n\n /** Expand environment variables based on the current and parsed envs */\n function _expandEnv(parsedEnv: Record) {\n const expandedEnv: Record = {};\n\n // When not ignoring `process.env`, values from the parsed env are overwritten by the current env if defined.\n // We handle this ourselves, expansion should always use the current state of \"current + parsed env\".\n const allExpandedEnv = dotenvExpand({\n parsed: { ...process.env, ...parsedEnv } as Record,\n ignoreProcessEnv: true,\n });\n\n if (allExpandedEnv.error) {\n console.error(\n `Failed to expand environment variables, using non-expanded environment variables: ${allExpandedEnv.error}`\n );\n return parsedEnv;\n }\n\n for (const key of Object.keys(parsedEnv)) {\n if (allExpandedEnv.parsed?.[key]) {\n expandedEnv[key] = allExpandedEnv.parsed[key];\n }\n }\n\n return expandedEnv;\n }\n\n /** Get the environment variables without mutating the environment. This returns memoized values unless the `force` property is provided. */\n function get(\n projectRoot: string,\n options: LoadOptions = {}\n ): { env: Record; files: string[] } {\n if (!isEnabled()) {\n debug(`Skipping .env files because EXPO_NO_DOTENV is defined`);\n return { env: {}, files: [] };\n }\n if (!options.force && memo) {\n return memo;\n }\n memo = _getForce(projectRoot, options);\n return memo;\n }\n\n /** Load environment variables from .env files and mutate the current `process.env` with the results. */\n function load(projectRoot: string, options: LoadOptions = {}) {\n if (!isEnabled()) {\n debug(`Skipping .env files because EXPO_NO_DOTENV is defined`);\n return process.env;\n }\n\n const envInfo = get(projectRoot, options);\n\n if (!options.force) {\n const keys = Object.keys(envInfo.env);\n if (keys.length) {\n console.log(\n chalk.gray('env: load', envInfo.files.map((file) => path.basename(file)).join(' '))\n );\n console.log(chalk.gray('env: export', keys.join(' ')));\n }\n }\n\n for (const key of Object.keys(envInfo.env)) {\n // Avoid creating a new object, mutate it instead as this causes problems in Bun\n process.env[key] = envInfo.env[key];\n }\n\n return process.env;\n }\n\n return {\n load,\n get,\n _getForce,\n };\n}\n\nexport function getFiles(\n mode: string | undefined,\n { silent = false }: Pick = {}\n): string[] {\n if (!isEnabled()) {\n debug(`Skipping .env files because EXPO_NO_DOTENV is defined`);\n return [];\n }\n\n if (!mode) {\n if (silent) {\n debug('NODE_ENV is not defined, proceeding without mode-specific .env');\n } else {\n console.error(\n chalk.red(\n 'The NODE_ENV environment variable is required but was not specified. Ensure the project is bundled with Expo CLI or NODE_ENV is set.'\n )\n );\n console.error(chalk.red('Proceeding without mode-specific .env'));\n }\n }\n\n if (mode && !['development', 'test', 'production'].includes(mode)) {\n if (silent) {\n debug(\n `NODE_ENV=\"${mode}\" is non-conventional and might cause development code to run in production. Use \"development\", \"test\", or \"production\" instead.`\n );\n } else {\n console.warn(\n chalk.yellow(\n `\"NODE_ENV=${mode}\" is non-conventional and might cause development code to run in production. Use \"development\", \"test\", or \"production\" instead`\n )\n );\n }\n }\n\n if (!mode) {\n // Support environments that don't respect NODE_ENV\n return [`.env.local`, '.env'];\n }\n // https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use\n const dotenvFiles = [\n `.env.${mode}.local`,\n // Don't include `.env.local` for `test` environment\n // since normally you expect tests to produce the same\n // results for everyone\n mode !== 'test' && `.env.local`,\n `.env.${mode}`,\n '.env',\n ].filter(Boolean) as string[];\n\n return dotenvFiles;\n}\n"],"mappings":"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"} \ No newline at end of file diff --git a/packages/@expo/env/src/__tests__/env.test.ts b/packages/@expo/env/src/__tests__/env.test.ts index 3f5beeb0153b1..9f51e0b7fc7c0 100644 --- a/packages/@expo/env/src/__tests__/env.test.ts +++ b/packages/@expo/env/src/__tests__/env.test.ts @@ -67,10 +67,26 @@ describe(getFiles, () => { expect.stringContaining('Proceeding without mode-specific .env') ); }); - it(`throws if NODE_ENV is not valid`, () => { - expect(() => getFiles('invalid')).toThrowErrorMatchingInlineSnapshot( - `"Environment variable "NODE_ENV=invalid" is invalid. Valid values are "development", "test", and "production"` + it(`warns if NODE_ENV is not valid`, () => { + const warnSpy = jest.spyOn(console, 'warn'); + + expect(() => getFiles('invalid')).not.toThrow(); + expect(warnSpy).toBeCalledWith( + expect.stringContaining('"NODE_ENV=invalid" is non-conventional') + ); + expect(warnSpy).toBeCalledWith( + expect.stringContaining('Use "development", "test", or "production"') ); + + warnSpy.mockClear(); + }); + it(`does not warn if NODE_ENV is not valid when in silent mode`, () => { + const warnSpy = jest.spyOn(console, 'warn'); + + expect(() => getFiles('invalid', { silent: true })).not.toThrow(); + expect(warnSpy).not.toBeCalled(); + + warnSpy.mockClear(); }); }); diff --git a/packages/@expo/env/src/env.ts b/packages/@expo/env/src/env.ts index 3545d14b72465..212a25358680f 100644 --- a/packages/@expo/env/src/env.ts +++ b/packages/@expo/env/src/env.ts @@ -198,9 +198,17 @@ export function getFiles( } if (mode && !['development', 'test', 'production'].includes(mode)) { - throw new Error( - `Environment variable "NODE_ENV=${mode}" is invalid. Valid values are "development", "test", and "production` - ); + if (silent) { + debug( + `NODE_ENV="${mode}" is non-conventional and might cause development code to run in production. Use "development", "test", or "production" instead.` + ); + } else { + console.warn( + chalk.yellow( + `"NODE_ENV=${mode}" is non-conventional and might cause development code to run in production. Use "development", "test", or "production" instead` + ) + ); + } } if (!mode) {