Update checking for existing dotenv usage (#11496)

* Update checking for existing dotenv usage

* Check for package-lock.json also
This commit is contained in:
JJ Kasper 2020-03-31 11:27:46 -05:00 committed by GitHub
parent b8d075ef0e
commit b307ed9186
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 131 additions and 9 deletions

View file

@ -1,12 +1,22 @@
import fs from 'fs'
import path from 'path'
import chalk from 'next/dist/compiled/chalk'
import findUp from 'next/dist/compiled/find-up'
import dotenvExpand from 'next/dist/compiled/dotenv-expand'
import dotenv, { DotenvConfigOutput } from 'next/dist/compiled/dotenv'
import findUp from 'next/dist/compiled/find-up'
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)
}
export function loadEnvConfig(dir: string, dev?: boolean): Env | false {
const packageJson = findUp.sync('package.json', { cwd: dir })
@ -14,15 +24,26 @@ export function loadEnvConfig(dir: string, dev?: boolean): Env | false {
// 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) {
const { dependencies, devDependencies } = require(packageJson)
const allPackages = Object.keys({
...dependencies,
...devDependencies,
})
if (allPackages.some(pkg => pkg === 'dotenv')) {
// check main `package.json` first
if (packageJsonHasDep(packageJson, 'dotenv')) {
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')) {
return false
}
} catch (_) {}
}
} else {
// we should always have a package.json but disable in case we don't
return false
@ -49,6 +70,13 @@ export function loadEnvConfig(dir: string, dev?: boolean): Env | false {
const dotEnvPath = path.join(dir, envFile)
try {
const stats = fs.statSync(dotEnvPath)
// make sure to only attempt to read files
if (!stats.isFile()) {
continue
}
const contents = fs.readFileSync(dotEnvPath, 'utf8')
let result: DotenvConfigOutput = {}
result.parsed = dotenv.parse(contents)
@ -62,7 +90,7 @@ export function loadEnvConfig(dir: string, dev?: boolean): Env | false {
Object.assign(combinedEnv, result.parsed)
} catch (err) {
if (err.code !== 'ENOENT') {
console.log(
console.error(
`> ${chalk.cyan.bold('Error: ')} Failed to load env from ${envFile}`,
err
)

View file

@ -0,0 +1,6 @@
{
"name": "env-config",
"devDependencies": {
"dotenv": "latest"
}
}

View file

@ -0,0 +1 @@
HELLO=world

View file

@ -0,0 +1,4 @@
{
"name": "env-config",
"dependencies": {}
}

View file

@ -0,0 +1 @@
export default () => 'hi'

View file

@ -0,0 +1,82 @@
/* 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 = ''
appPort = await findPort()
app = await launchApp(appDir, appPort, {
onStderr(msg) {
stderr += msg || ''
},
})
const html = await renderViaHTTP(appPort, '/')
await killApp(app)
expect(html).toContain('hi')
expect(stderr).not.toContain('Failed to load env')
})
})
describe('production mode', () => {
it('should build app successfully', async () => {
const { stderr, code } = await nextBuild(appDir, [], { stderr: true })
expect(code).toBe(0)
expect((stderr || '').length).toBe(0)
})
it('should start without error', async () => {
let stderr = ''
appPort = await findPort()
app = await nextStart(appDir, appPort, {
onStderr(msg) {
stderr += msg || ''
},
})
const html = await renderViaHTTP(appPort, '/')
await killApp(app)
expect(html).toContain('hi')
expect(stderr).not.toContain('Failed to load env')
})
})
}
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()
})
})