From 313b552026af7fa2c0421eb1407c382dd731294c Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Fri, 15 May 2020 21:02:16 +0200 Subject: [PATCH] Enable .env support by default (#12911) * Enable .env support by default Given we've had tons of reports from various people that expected .env support to work even though they had dotenv installed already I think it's fine to enable it as a default: Fixes #12728 * Remove old test * Fix duplicate env loading * Update docs Co-authored-by: JJ Kasper --- docs/basic-features/environment-variables.md | 1 - errors/env-loading-disabled.md | 4 +- packages/next/lib/load-env-config.ts | 57 +--------- .../env-config-disable/app/package.json | 6 -- .../packages/sub-app/.env/.env.development | 1 - .../app/packages/sub-app/package.json | 4 - .../app/packages/sub-app/pages/index.js | 1 - .../env-config-disable/test/index.test.js | 102 ------------------ 8 files changed, 5 insertions(+), 171 deletions(-) delete mode 100644 test/integration/env-config-disable/app/package.json delete mode 100644 test/integration/env-config-disable/app/packages/sub-app/.env/.env.development delete mode 100644 test/integration/env-config-disable/app/packages/sub-app/package.json delete mode 100644 test/integration/env-config-disable/app/packages/sub-app/pages/index.js delete mode 100644 test/integration/env-config-disable/test/index.test.js diff --git a/docs/basic-features/environment-variables.md b/docs/basic-features/environment-variables.md index 91a03d5c55..45e2c0050f 100644 --- a/docs/basic-features/environment-variables.md +++ b/docs/basic-features/environment-variables.md @@ -47,7 +47,6 @@ npx cross-env NEXT_PUBLIC_EXAMPLE_KEY=my-value next dev - Trying to destructure `process.env` variables won't work due to the limitations of webpack's [DefinePlugin](https://webpack.js.org/plugins/define-plugin/). - To avoid exposing secrets, do not use the `NEXT_PUBLIC_` prefix for them. Instead, [expose the variables using `.env`](#exposing-environment-variables). -- You cannot have `dotenv` installed in your project, as this will cause Next.js to disable the auto-loading of the environment variables. Look for and uninstall this package if your variables are showing up as `undefined`. ## Exposing Environment Variables diff --git a/errors/env-loading-disabled.md b/errors/env-loading-disabled.md index f6fd2d4e28..34515e5c1c 100644 --- a/errors/env-loading-disabled.md +++ b/errors/env-loading-disabled.md @@ -8,7 +8,9 @@ This is also disabled if a `package.json` isn't able to found in your project so #### Possible Ways to Fix It -Remove `dotenv` from your `devDependencies` or `dependencies` and allow Next.js to load your `dotenv` files for you +Update to the latest version of Next.js (>= v9.4.1) where this support is enabled regardless of `dotenv` being installed. + +Remove `dotenv` from your `devDependencies` or `dependencies` and allow Next.js to load your `dotenv` files for you. ### Useful Links diff --git a/packages/next/lib/load-env-config.ts b/packages/next/lib/load-env-config.ts index 704c153dec..307e1e92bc 100644 --- a/packages/next/lib/load-env-config.ts +++ b/packages/next/lib/load-env-config.ts @@ -1,71 +1,18 @@ import fs from 'fs' import path from 'path' import * as log from '../build/output/log' -import findUp from 'next/dist/compiled/find-up' -import { execOnce } from '../next-server/lib/utils' import dotenvExpand from 'next/dist/compiled/dotenv-expand' import dotenv, { DotenvConfigOutput } from 'next/dist/compiled/dotenv' export type Env = { [key: string]: string } -const packageJsonHasDep = (packageJsonPath: string, dep: string): boolean => { - const { dependencies, devDependencies } = require(packageJsonPath) - const allPackages = Object.keys({ - ...dependencies, - ...devDependencies, - }) - - return allPackages.some(pkg => pkg === dep) -} - let combinedEnv: Env | undefined = undefined -const envLoadingDisabledWarning = execOnce((packageFile?: string) => { - log.warn( - (packageFile - ? `dotenv loading was disabled due to the \`dotenv\` package being installed in: ${packageFile}` - : `dotenv loading was disabled due to no package.json file able to be found`) + - `\nSee more info here: https://err.sh/next.js/env-loading-disabled` - ) -}) - export function loadEnvConfig(dir: string, dev?: boolean): Env | false { + // don't reload env if we already have since this breaks escaped + // environment values e.g. \$ENV_FILE_KEY if (combinedEnv) return combinedEnv - const packageJson = findUp.sync('package.json', { cwd: dir }) - - // only do new env loading if dotenv isn't installed since we - // can't check for an experimental flag in next.config.js - // since we want to load the env before loading next.config.js - if (packageJson) { - // check main `package.json` first - if (packageJsonHasDep(packageJson, 'dotenv')) { - envLoadingDisabledWarning(path.relative(dir, packageJson)) - return false - } - // check for a yarn.lock or lerna.json file in case it's a monorepo - const monorepoFile = findUp.sync( - ['yarn.lock', 'lerna.json', 'package-lock.json'], - { cwd: dir } - ) - - if (monorepoFile) { - const monorepoRoot = path.dirname(monorepoFile) - const monorepoPackageJson = path.join(monorepoRoot, 'package.json') - - try { - if (packageJsonHasDep(monorepoPackageJson, 'dotenv')) { - envLoadingDisabledWarning(path.relative(dir, monorepoPackageJson)) - return false - } - } catch (_) {} - } - } else { - // we should always have a package.json but disable in case we don't - envLoadingDisabledWarning() - return false - } - const isTest = process.env.NODE_ENV === 'test' const mode = isTest ? 'test' : dev ? 'development' : 'production' const dotenvFiles = [ diff --git a/test/integration/env-config-disable/app/package.json b/test/integration/env-config-disable/app/package.json deleted file mode 100644 index 46aaa57dea..0000000000 --- a/test/integration/env-config-disable/app/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "env-config", - "devDependencies": { - "dotenv": "latest" - } -} diff --git a/test/integration/env-config-disable/app/packages/sub-app/.env/.env.development b/test/integration/env-config-disable/app/packages/sub-app/.env/.env.development deleted file mode 100644 index 940a5d8d95..0000000000 --- a/test/integration/env-config-disable/app/packages/sub-app/.env/.env.development +++ /dev/null @@ -1 +0,0 @@ -HELLO=world \ No newline at end of file diff --git a/test/integration/env-config-disable/app/packages/sub-app/package.json b/test/integration/env-config-disable/app/packages/sub-app/package.json deleted file mode 100644 index ffaa95af60..0000000000 --- a/test/integration/env-config-disable/app/packages/sub-app/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "env-config", - "dependencies": {} -} diff --git a/test/integration/env-config-disable/app/packages/sub-app/pages/index.js b/test/integration/env-config-disable/app/packages/sub-app/pages/index.js deleted file mode 100644 index 0957a987fc..0000000000 --- a/test/integration/env-config-disable/app/packages/sub-app/pages/index.js +++ /dev/null @@ -1 +0,0 @@ -export default () => 'hi' diff --git a/test/integration/env-config-disable/test/index.test.js b/test/integration/env-config-disable/test/index.test.js deleted file mode 100644 index 3713b9ab47..0000000000 --- a/test/integration/env-config-disable/test/index.test.js +++ /dev/null @@ -1,102 +0,0 @@ -/* eslint-env jest */ -/* global jasmine */ -import fs from 'fs-extra' -import { join } from 'path' -import { - nextBuild, - findPort, - launchApp, - killApp, - nextStart, - renderViaHTTP, -} from 'next-test-utils' - -jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 2 - -const monorepoRoot = join(__dirname, '../app') -const yarnLock = join(monorepoRoot, 'yarn.lock') -const lernaConf = join(monorepoRoot, 'lerna.json') -const appDir = join(monorepoRoot, 'packages/sub-app') - -let app -let appPort - -const runTests = () => { - describe('dev mode', () => { - it('should start dev server without errors', async () => { - let stderr = '' - let stdout = '' - appPort = await findPort() - app = await launchApp(appDir, appPort, { - onStderr(msg) { - stderr += msg || '' - }, - onStdout(msg) { - stdout += msg || '' - }, - }) - - const html = await renderViaHTTP(appPort, '/') - await killApp(app) - - expect(html).toContain('hi') - expect(stderr).not.toContain('Failed to load env') - expect(stdout).toContain( - 'dotenv loading was disabled due to the `dotenv` package being installed in' - ) - }) - }) - - describe('production mode', () => { - it('should build app successfully', async () => { - const { stderr, stdout, code } = await nextBuild(appDir, [], { - stderr: true, - stdout: true, - }) - expect(code).toBe(0) - expect((stderr || '').length).toBe(0) - expect(stdout).toContain( - 'dotenv loading was disabled due to the `dotenv` package being installed in' - ) - }) - - it('should start without error', async () => { - let stderr = '' - let stdout = '' - appPort = await findPort() - app = await nextStart(appDir, appPort, { - onStderr(msg) { - stderr += msg || '' - }, - onStdout(msg) { - stdout += msg || '' - }, - }) - - const html = await renderViaHTTP(appPort, '/') - await killApp(app) - - expect(html).toContain('hi') - expect(stderr).not.toContain('Failed to load env') - expect(stdout).toContain( - 'dotenv loading was disabled due to the `dotenv` package being installed in' - ) - }) - }) -} - -describe('Env support disabling', () => { - describe('with yarn based monorepo', () => { - beforeAll(() => fs.writeFile(yarnLock, 'test')) - afterAll(() => fs.remove(yarnLock)) - - runTests() - }) - - describe('with lerna based monorepo', () => { - beforeAll(() => fs.writeFile(lernaConf, 'test')) - afterAll(() => fs.remove(lernaConf)) - - runTests() - }) -}) -- GitLab