/
env.ts
100 lines (91 loc) · 2.79 KB
/
env.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import fs from 'node:fs'
import { parse } from 'dotenv'
import { expand } from 'dotenv-expand'
import { arraify, lookupFile } from './utils'
import type { UserConfig } from './config'
export function loadEnv(
mode: string,
envDir: string,
prefixes: string | string[] = 'VITE_',
): Record<string, string> {
if (mode === 'local') {
throw new Error(
`"local" cannot be used as a mode name because it conflicts with ` +
`the .local postfix for .env files.`,
)
}
prefixes = arraify(prefixes)
const env: Record<string, string> = {}
const envFiles = [
/** default file */ `.env`,
/** local file */ `.env.local`,
/** mode file */ `.env.${mode}`,
/** mode local file */ `.env.${mode}.local`,
]
const parsed = Object.fromEntries(
envFiles.flatMap((file) => {
const path = lookupFile(envDir, [file], {
pathOnly: true,
rootDir: envDir,
})
if (!path) return []
return Object.entries(parse(fs.readFileSync(path)))
}),
)
const expandOptions = {
parsed: {
...(process.env as any),
...parsed,
},
// prevent process.env mutation
ignoreProcessEnv: true,
}
let expandParsed: NonNullable<ReturnType<typeof expand>['parsed']>
try {
// let environment variables use each other
expandParsed = expand(expandOptions).parsed!
} catch (e) {
// custom error handling until https://github.com/motdotla/dotenv-expand/issues/65 is fixed upstream
// check for message "TypeError: Cannot read properties of undefined (reading 'split')"
if (e.message.includes('split')) {
throw new Error(
'dotenv-expand failed to expand env vars. Maybe you need to escape `$`?',
)
}
throw e
}
Object.keys(parsed).forEach((key) => {
parsed[key] = expandParsed[key]
})
// only keys that start with prefix are exposed to client
for (const [key, value] of Object.entries(parsed)) {
if (prefixes.some((prefix) => key.startsWith(prefix))) {
env[key] = value
} else if (
key === 'NODE_ENV' &&
process.env.VITE_USER_NODE_ENV === undefined
) {
// NODE_ENV override in .env file
process.env.VITE_USER_NODE_ENV = value
}
}
// check if there are actual env variables starting with VITE_*
// these are typically provided inline and should be prioritized
for (const key in process.env) {
if (prefixes.some((prefix) => key.startsWith(prefix))) {
env[key] = process.env[key] as string
}
}
return env
}
export function resolveEnvPrefix({
envPrefix = 'VITE_',
}: UserConfig): string[] {
envPrefix = arraify(envPrefix)
if (envPrefix.some((prefix) => prefix === '')) {
throw new Error(
`envPrefix option contains value '', which could lead unexpected exposure of sensitive information.`,
)
}
return envPrefix
}