|
| 1 | +import { readFile } from 'node:fs/promises' |
1 | 2 | import path from 'node:path' |
2 | 3 | import process from 'node:process' |
| 4 | +import { parseEnv } from 'node:util' |
3 | 5 | import { blue } from 'ansis' |
4 | 6 | import { createDefu } from 'defu' |
5 | 7 | import isInCi from 'is-in-ci' |
@@ -62,6 +64,8 @@ export async function resolveUserConfig( |
62 | 64 | report = true, |
63 | 65 | target, |
64 | 66 | env = {}, |
| 67 | + envFile, |
| 68 | + envPrefix = 'TSDOWN_', |
65 | 69 | copy, |
66 | 70 | publicDir, |
67 | 71 | hash = true, |
@@ -164,6 +168,28 @@ export async function resolveUserConfig( |
164 | 168 | } |
165 | 169 | } |
166 | 170 |
|
| 171 | + envPrefix = toArray(envPrefix) |
| 172 | + if (envPrefix.includes('')) { |
| 173 | + logger.warn( |
| 174 | + '`envPrefix` includes an empty string; filtering is disabled. All environment variables from the env file and process.env will be injected into the build. Ensure this is intended to avoid accidental leakage of sensitive information.', |
| 175 | + ) |
| 176 | + } |
| 177 | + const envFromProcess = filterEnv(process.env, envPrefix) |
| 178 | + if (envFile) { |
| 179 | + const resolvedPath = path.resolve(cwd, envFile) |
| 180 | + logger.info(nameLabel, `env file: ${color(resolvedPath)}`) |
| 181 | + |
| 182 | + const parsed = parseEnv(await readFile(resolvedPath, 'utf8')) |
| 183 | + const envFromFile = filterEnv(parsed, envPrefix) |
| 184 | + |
| 185 | + // precedence: env file < process.env < tsdown option |
| 186 | + env = { ...envFromFile, ...envFromProcess, ...env } |
| 187 | + } else { |
| 188 | + // precedence: process.env < tsdown option |
| 189 | + env = { ...envFromProcess, ...env } |
| 190 | + } |
| 191 | + debugLog(`Environment variables: %O`, env) |
| 192 | + |
167 | 193 | if (fromVite) { |
168 | 194 | const viteUserConfig = await loadViteConfig( |
169 | 195 | fromVite === true ? 'vite' : fromVite, |
@@ -278,6 +304,23 @@ export async function resolveUserConfig( |
278 | 304 | }) |
279 | 305 | } |
280 | 306 |
|
| 307 | +/** filter env variables by prefixes */ |
| 308 | +function filterEnv( |
| 309 | + envDict: Record<string, string | undefined>, |
| 310 | + envPrefixes: string[], |
| 311 | +) { |
| 312 | + const env: Record<string, string> = {} |
| 313 | + for (const [key, value] of Object.entries(envDict)) { |
| 314 | + if ( |
| 315 | + envPrefixes.some((prefix) => key.startsWith(prefix)) && |
| 316 | + value !== undefined |
| 317 | + ) { |
| 318 | + env[key] = value |
| 319 | + } |
| 320 | + } |
| 321 | + return env |
| 322 | +} |
| 323 | + |
281 | 324 | const defu = createDefu((obj, key, value) => { |
282 | 325 | if (Array.isArray(obj[key]) && Array.isArray(value)) { |
283 | 326 | obj[key] = value |
|
0 commit comments