rsnext/packages/next/lib/load-env-config.ts

102 lines
2.8 KiB
TypeScript
Raw Normal View History

import fs from 'fs'
import path from 'path'
import * as log from '../build/output/log'
import dotenvExpand from 'next/dist/compiled/dotenv-expand'
import dotenv, { DotenvConfigOutput } from 'next/dist/compiled/dotenv'
export type Env = { [key: string]: string }
export type LoadedEnvFiles = Array<{
path: string
contents: string
}>
let combinedEnv: Env | undefined = undefined
let cachedLoadedEnvFiles: LoadedEnvFiles = []
export function processEnv(loadedEnvFiles: LoadedEnvFiles, dir?: string) {
// don't reload env if we already have since this breaks escaped
// environment values e.g. \$ENV_FILE_KEY
if (
combinedEnv ||
process.env.__NEXT_PROCESSED_ENV ||
!loadedEnvFiles.length
) {
return process.env as Env
}
// flag that we processed the environment values in case a serverless
// function is re-used or we are running in `next start` mode
process.env.__NEXT_PROCESSED_ENV = 'true'
for (const envFile of loadedEnvFiles) {
try {
let result: DotenvConfigOutput = {}
result.parsed = dotenv.parse(envFile.contents)
result = dotenvExpand(result)
if (result.parsed) {
log.info(`Loaded env from ${path.join(dir || '', envFile.path)}`)
}
Object.assign(process.env, result.parsed)
} catch (err) {
log.error(
`Failed to load env from ${path.join(dir || '', envFile.path)}`,
err
)
}
}
return process.env as Env
}
export function loadEnvConfig(
dir: string,
dev?: boolean
): {
combinedEnv: Env
loadedEnvFiles: LoadedEnvFiles
} {
// don't reload env if we already have since this breaks escaped
// environment values e.g. \$ENV_FILE_KEY
if (combinedEnv) return { combinedEnv, loadedEnvFiles: cachedLoadedEnvFiles }
const isTest = process.env.NODE_ENV === 'test'
const mode = isTest ? 'test' : dev ? 'development' : 'production'
const dotenvFiles = [
`.env.${mode}.local`,
// Don't include `.env.local` for `test` environment
// since normally you expect tests to produce the same
// results for everyone
mode !== 'test' && `.env.local`,
`.env.${mode}`,
'.env',
].filter(Boolean) as string[]
for (const envFile of dotenvFiles) {
// only load .env if the user provided has an env config file
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')
cachedLoadedEnvFiles.push({
path: envFile,
contents,
})
} catch (err) {
if (err.code !== 'ENOENT') {
log.error(`Failed to load env from ${envFile}`, err)
}
}
}
combinedEnv = processEnv(cachedLoadedEnvFiles, dir)
return { combinedEnv, loadedEnvFiles: cachedLoadedEnvFiles }
}