Repository navigation
feat(config): support multiple env files - #1110
Conversation
✅ Deploy Preview for tsdown-main ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
tsdown
create-tsdown
@tsdown/css
@tsdown/exe
tsdown-migrate
commit: |
There was a problem hiding this comment.
🟡 Changes recommended
Automatic restarts leave the replacement watcher unmanaged, shared env-file registration creates quadratic watch setup work, and empty env-file paths can cause directory read errors.
3 open issues
What changed in this PR
Adds opt-in support for multiple environment files in tsdown, addressing #1056, and connects loaded files to watch-mode configuration reloads.
Changes:
- Accept ordered env-file arrays and repeated
--env-fileflags, skipping missing files while preserving environment-variable precedence. - Merge per-config dependencies into restart tracking, including env files and
fromVitedependencies. - Update documentation, schemas, API snapshots, and integration coverage.
| File | Description |
|---|---|
| tests/e2e.test.ts | Tests multiple files, override order, and missing-file handling. |
| tests/__snapshots__/multiple-env-files.snap.md | Records bundled environment values. |
| src/config/types.ts | Allows and documents env-file arrays. |
| src/config/options.ts | Loads files in order and tracks loaded dependencies. |
| src/config/index.ts | Merges per-config dependencies into global tracking. |
| src/cli.ts | Advertises repeatable env-file flags. |
| skills/tsdown/references/reference-cli.md | Documents multiple-file CLI usage. |
| schema.json | Allows string or array env-file values. |
| docs/zh-CN/reference/cli.md | Updates Chinese CLI guidance and examples. |
| docs/reference/cli.md | Updates English CLI guidance and examples. |
| snapshots/tsnapi/index.snapshot.d.ts | Updates the main API type snapshot. |
| snapshots/tsnapi/config.snapshot.d.ts | Updates the configuration API type snapshot. |
Review effort: Balanced
| for (const config of configs) { | ||
| config.configDeps.forEach((dep) => globalDeps.add(dep)) |
There was a problem hiding this comment.
Fixed in 17bd0fc: config deps are no longer merged into the shared set. Each watcher now gets the shared deps plus its own config's configDeps.
| if (envFile) { | ||
| const resolvedPath = path.resolve(cwd, envFile) | ||
| const envFromFiles: Record<string, string | undefined> = {} | ||
| for (const file of toArray(envFile)) { |
There was a problem hiding this comment.
Fixed in 17bd0fc: empty env file paths are skipped again, with a test.
| } else { | ||
| // precedence: process.env < tsdown option | ||
| env = { ...envFromProcess, ...env } | ||
| configDeps.add(resolvedPath) |
There was a problem hiding this comment.
Good catch. This predates this PR, since config file changes and the r shortcut restart the same way. Leaving it for a separate fix.

AI usage
Description
envFile(and--env-file) now accept multiple files, e.g.envFile: ['.env', '.env.local']. Files are loaded in order, so later files override earlier ones, and missing files are skipped (as in Vite). The precedence stays env files <process.env<env. Env files are still opt-in: no automatic loading, noenvDirormode.Loaded env files are added to the config deps, so editing one restarts the build in watch mode. Per-config
configDepswere never merged into the deps used by the watcher, so this also makesfromViteconfig deps trigger a restart.Linked Issues
Closes #1056
Additional context
r).