未验证 提交 313b5520 编写于 作者: T Tim Neutkens 提交者: GitHub

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: NJJ Kasper <jj@jjsweb.site>
上级 0d49f22e
......@@ -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
......
......@@ -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
......
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 = [
......
{
"name": "env-config",
"devDependencies": {
"dotenv": "latest"
}
}
/* 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()
})
})
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册