Visitar URL original
feat(config): support multiple env files (#1110) · rolldown/tsdown@5d55836 · GitHub
Skip to content

Commit 5d55836

Browse files
sxzzsxzzbot
andauthored
feat(config): support multiple env files (#1110)
Co-authored-by: Kevin Bot <gh-bot@sxzz.moe>
1 parent 75a78ce commit 5d55836

12 files changed

Lines changed: 79 additions & 26 deletions

File tree

‎__snapshots__/tsnapi/config.snapshot.d.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export interface UserConfig {
1010
platform?: "node" | "neutral" | "browser";
1111
target?: string | string[] | false;
1212
env?: Record<string, any>;
13-
envFile?: string;
13+
envFile?: string | string[];
1414
envPrefix?: string | string[];
1515
define?: Record<string, string>;
1616
shims?: boolean;

‎__snapshots__/tsnapi/index.snapshot.d.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ export interface UserConfig {
145145
platform?: "node" | "neutral" | "browser";
146146
target?: string | string[] | false;
147147
env?: Record<string, any>;
148-
envFile?: string;
148+
envFile?: string | string[];
149149
envPrefix?: string | string[];
150150
define?: Record<string, string>;
151151
shims?: boolean;

‎docs/reference/cli.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,14 +207,15 @@ Note that environment variables defined with `--env.VAR_NAME` can only be access
207207

208208
## `--env-file <file>`
209209

210-
Load environment variables from a file. When used together with `--env`, variables in `--env` take precedence.
210+
Load environment variables from a file. The flag can be repeated to load several files: later files override earlier ones, and missing files are skipped. When used together with `--env`, variables in `--env` take precedence.
211211

212212
:::tip
213213
To prevent accidental exposure of sensitive information, only environment variables prefixed with `TSDOWN_` are injected by default. You can customize this behavior using the [`--env-prefix`](#env-prefix) flag.
214214
:::
215215

216216
```bash
217217
tsdown --env-file .env.production
218+
tsdown --env-file .env --env-file .env.local
218219
```
219220

220221
## `--env-prefix <prefix>` {#env-prefix}

‎docs/zh-CN/reference/cli.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,14 +205,15 @@ tsdown --env.NODE_ENV=production
205205

206206
## `--env-file <file>`
207207

208-
从文件加载环境变量。当与 `--env` 一起使用时,`--env` 中的变量优先生效。
208+
从文件加载环境变量。可以多次使用该标志加载多个文件:后面的文件会覆盖前面的,不存在的文件会被跳过。当与 `--env` 一起使用时,`--env` 中的变量优先生效。
209209

210210
:::tip
211211
为防止敏感信息意外暴露,默认仅注入以 `TSDOWN_` 前缀开头的环境变量。您可以通过 [`--env-prefix`](#env-prefix) 标志自定义此行为。
212212
:::
213213

214214
```bash
215215
tsdown --env-file .env.production
216+
tsdown --env-file .env --env-file .env.local
216217
```
217218

218219
## `--env-prefix <prefix>` {#env-prefix}

‎schema.json‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,11 @@
5353
"default": {}
5454
},
5555
"envFile": {
56-
"type": "string",
57-
"description": "Path to env file providing compile-time env variables."
56+
"anyOf": [
57+
{ "type": "string" },
58+
{ "type": "array", "items": { "type": "string" } }
59+
],
60+
"description": "Path(s) to env files providing compile-time env variables.\n\nFiles are loaded in order, so later files override earlier ones.\nMissing files are skipped."
5861
},
5962
"envPrefix": {
6063
"anyOf": [
@@ -418,8 +421,11 @@
418421
"default": {}
419422
},
420423
"envFile": {
421-
"type": "string",
422-
"description": "Path to env file providing compile-time env variables."
424+
"anyOf": [
425+
{ "type": "string" },
426+
{ "type": "array", "items": { "type": "string" } }
427+
],
428+
"description": "Path(s) to env files providing compile-time env variables.\n\nFiles are loaded in order, so later files override earlier ones.\nMissing files are skipped."
423429
},
424430
"envPrefix": {
425431
"anyOf": [

‎skills/tsdown/references/reference-cli.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,11 @@ Access as `import.meta.env.*` or `process.env.*`.
222222

223223
### `--env-file <file>`
224224

225-
Load environment variables from file:
225+
Load environment variables from file. Repeat to load several files (later files win, missing files are skipped):
226226

227227
```bash
228228
tsdown --env-file .env.production
229+
tsdown --env-file .env --env-file .env.local
229230
```
230231

231232
### `--env-prefix <prefix>`

‎src/cli.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ cli
5959
.option('--env.* <value>', 'Define compile-time env variables')
6060
.option(
6161
'--env-file <file>',
62-
'Load environment variables from a file, when used together with --env, variables in --env take precedence',
62+
'Load environment variables from a file, can be repeated',
6363
)
6464
.option(
6565
'--env-prefix <prefix>',

‎src/config/index.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ export async function resolveConfig(
7373
.filter((config) => !!config)
7474

7575
workspaceDeps.forEach((dep) => globalDeps.add(dep))
76+
for (const config of configs) {
77+
config.configDeps.forEach((dep) => globalDeps.add(dep))
78+
}
7679
return configs
7780
}),
7881
)

‎src/config/options.ts‎

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -183,23 +183,29 @@ export async function resolveUserConfig(
183183
'`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.',
184184
)
185185
}
186+
configDeps = new Set(configDeps)
187+
186188
const envFromProcess = filterEnv(process.env, envPrefix)
187-
if (envFile) {
188-
const resolvedPath = path.resolve(cwd, envFile)
189+
const envFromFiles: Record<string, string | undefined> = {}
190+
for (const file of toArray(envFile)) {
191+
const resolvedPath = path.resolve(cwd, file)
192+
const content = await readFile(resolvedPath, 'utf8').catch((error) => {
193+
if (error.code === 'ENOENT') return null
194+
throw error
195+
})
196+
if (content == null) {
197+
debug('env file not found, skipped: %s', resolvedPath)
198+
continue
199+
}
189200
logger.info(nameLabel, `env file: ${color(resolvedPath)}`)
190-
191-
const parsed = parseEnv(await readFile(resolvedPath, 'utf8'))
192-
const envFromFile = filterEnv(parsed, envPrefix)
193-
194-
// precedence: env file < process.env < tsdown option
195-
env = { ...envFromFile, ...envFromProcess, ...env }
196-
} else {
197-
// precedence: process.env < tsdown option
198-
env = { ...envFromProcess, ...env }
201+
configDeps.add(resolvedPath)
202+
// later files take precedence
203+
Object.assign(envFromFiles, parseEnv(content))
199204
}
200-
debug(`Environment variables: %O`, env)
201205

202-
configDeps = new Set(configDeps)
206+
// precedence: env files < process.env < tsdown option
207+
env = { ...filterEnv(envFromFiles, envPrefix), ...envFromProcess, ...env }
208+
debug(`Environment variables: %O`, env)
203209

204210
if (fromVite) {
205211
const viteUserConfig = await loadViteConfig(

‎src/config/types.ts‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,11 +242,14 @@ export interface UserConfig {
242242
*/
243243
env?: Record<string, any>
244244
/**
245-
* Path to env file providing compile-time env variables.
245+
* Path(s) to env files providing compile-time env variables.
246+
*
247+
* Files are loaded in order, so later files override earlier ones.
248+
* Missing files are skipped.
246249
* @example
247-
* `.env`, `.env.production`, etc.
250+
* `.env`, `['.env', '.env.local']`, etc.
248251
*/
249-
envFile?: string
252+
envFile?: string | string[]
250253
/**
251254
* When loading env variables from `envFile`, only include variables with these prefixes.
252255
* @default 'TSDOWN_'

0 commit comments

Comments
 (0)