diff --git a/docs/guide/env-and-mode.md b/docs/guide/env-and-mode.md index 318bd1ea32da33..78d5af73aa5f71 100644 --- a/docs/guide/env-and-mode.md +++ b/docs/guide/env-and-mode.md @@ -77,6 +77,23 @@ If you want to customize the env variables prefix, see the [envPrefix](/config/s - Since any variables exposed to your Vite source code will end up in your client bundle, `VITE_*` variables should _not_ contain any sensitive information. ::: +::: details Expanding variables in reverse order + +Vite supports expanding variables in reverse order. +For example, the `.env` below will be evaluated as `VITE_FOO=foobar`, `VITE_BAR=bar`. + +```[.env] +VITE_FOO=foo${VITE_BAR} +VITE_BAR=bar +``` + +This does not work in shell scripts and other tools like `docker-compose`. +That said, Vite supports this behavior as this has been supported by `dotenv-expand` for a long time and other tools in JavaScript ecosystem uses older versions that supports this behavior. + +To avoid interop issues, it is recommended to avoid relying on this behavior. Vite may start emitting warnings for this behavior in the future. + +::: + ### IntelliSense for TypeScript By default, Vite provides type definitions for `import.meta.env` in [`vite/client.d.ts`](https://github.com/vitejs/vite/blob/main/packages/vite/client.d.ts). While you can define more custom env variables in `.env.[mode]` files, you may want to get TypeScript IntelliSense for user-defined env variables that are prefixed with `VITE_`. diff --git a/docs/guide/migration.md b/docs/guide/migration.md index 2741d026954c93..80d65e9697b9b0 100644 --- a/docs/guide/migration.md +++ b/docs/guide/migration.md @@ -99,8 +99,8 @@ There are other breaking changes which only affect few users. - This PR not only introduces a breaking change mentioned above as "Default value for `resolve.conditions`", but also makes `resolve.mainFields` to not be used for no-externalized dependencies in SSR. If you were using `resolve.mainFields` and want to apply that to no-externalized dependencies in SSR, you can use [`ssr.resolve.mainFields`](/config/ssr-options#ssr-resolve-mainfields). - [[#18493] refactor!: remove fs.cachedChecks option](https://github.com/vitejs/vite/pull/18493) - This opt-in optimization was removed due to edge cases when writing a file in a cached folder and immediately importing it. -- [[#18697] fix(deps)!: update dependency dotenv-expand to v12](https://github.com/vitejs/vite/pull/18697) - - Variables used in interpolation should be declared before the interpolation now. For more details, see [the `dotenv-expand` changelog](https://github.com/motdotla/dotenv-expand/blob/v12.0.1/CHANGELOG.md#1200-2024-11-16). +- ~~[[#18697] fix(deps)!: update dependency dotenv-expand to v12](https://github.com/vitejs/vite/pull/18697)~~ + - ~~Variables used in interpolation should be declared before the interpolation now. For more details, see [the `dotenv-expand` changelog](https://github.com/motdotla/dotenv-expand/blob/v12.0.1/CHANGELOG.md#1200-2024-11-16).~~ This breaking change was reverted in v6.1.0. - [[#16471] feat: v6 - Environment API](https://github.com/vitejs/vite/pull/16471) - Updates to an SSR-only module no longer triggers a full page reload in the client. To return to the previous behaviour, a custom Vite plugin can be used: diff --git a/package.json b/package.json index 656f7ae943c986..8b75b995c160bc 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,8 @@ "patchedDependencies": { "http-proxy@1.18.1": "patches/http-proxy@1.18.1.patch", "sirv@3.0.0": "patches/sirv@3.0.0.patch", - "chokidar@3.6.0": "patches/chokidar@3.6.0.patch" + "chokidar@3.6.0": "patches/chokidar@3.6.0.patch", + "dotenv-expand@12.0.1": "patches/dotenv-expand@12.0.1.patch" }, "peerDependencyRules": { "allowedVersions": { diff --git a/packages/vite/src/node/__tests__/env.spec.ts b/packages/vite/src/node/__tests__/env.spec.ts index a229971198211b..36fbaa2d8172d0 100644 --- a/packages/vite/src/node/__tests__/env.spec.ts +++ b/packages/vite/src/node/__tests__/env.spec.ts @@ -39,6 +39,17 @@ describe('loadEnv', () => { `) }) + test('override 2', () => { + expect(loadEnv('development2', join(__dirname, './env'))) + .toMatchInlineSnapshot(` + { + "VITE_APP_BASE_ROUTE": "source", + "VITE_APP_BASE_URL": "source", + "VITE_SOURCE": "source", + } + `) + }) + test('VITE_USER_NODE_ENV', () => { loadEnv('development', join(__dirname, './env')) expect(process.env.VITE_USER_NODE_ENV).toEqual(undefined) diff --git a/packages/vite/src/node/__tests__/env/.env.development2 b/packages/vite/src/node/__tests__/env/.env.development2 new file mode 100644 index 00000000000000..7d719c8d4cde36 --- /dev/null +++ b/packages/vite/src/node/__tests__/env/.env.development2 @@ -0,0 +1,2 @@ +VITE_SOURCE=source +VITE_APP_BASE_ROUTE=$VITE_SOURCE diff --git a/patches/dotenv-expand@12.0.1.patch b/patches/dotenv-expand@12.0.1.patch new file mode 100644 index 00000000000000..e3b5e10d416a99 --- /dev/null +++ b/patches/dotenv-expand@12.0.1.patch @@ -0,0 +1,31 @@ +diff --git a/lib/main.js b/lib/main.js +index 794f3bf512ee8cd24fe20e83d159bf8682fb901e..5567e6e282d65b87deea02f8cb396d3e7276581e 100644 +--- a/lib/main.js ++++ b/lib/main.js +@@ -64,7 +64,7 @@ function expandValue (value, processEnv, runningParsed) { + + function expand (options) { + // for use with progressive expansion +- const runningParsed = {} ++ // const runningParsed = {} + + let processEnv = process.env + if (options && options.processEnv != null) { +@@ -79,13 +79,15 @@ function expand (options) { + if (processEnv[key] && processEnv[key] !== value) { + value = processEnv[key] + } else { +- value = expandValue(value, processEnv, runningParsed) ++ // PATCH: we pass options.parsed instead of runningParsed ++ // to allow variables declared in other files to be used ++ value = expandValue(value, processEnv, options.parsed) + } + + options.parsed[key] = _resolveEscapeSequences(value) + + // for use with progressive expansion +- runningParsed[key] = _resolveEscapeSequences(value) ++ // runningParsed[key] = _resolveEscapeSequences(value) + } + + for (const processKey in options.parsed) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0fb87c08328c7c..99e1ea5387d4a8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,6 +13,9 @@ patchedDependencies: chokidar@3.6.0: hash: r6f2jac4ef543toizf7sfnkaom path: patches/chokidar@3.6.0.patch + dotenv-expand@12.0.1: + hash: cccknsdvxfahgkn34dugpdmdpa + path: patches/dotenv-expand@12.0.1.patch http-proxy@1.18.1: hash: qqiqxx62zlcu62nljjmhlvexni path: patches/http-proxy@1.18.1.patch @@ -305,7 +308,7 @@ importers: version: 16.4.7 dotenv-expand: specifier: ^12.0.1 - version: 12.0.1 + version: 12.0.1(patch_hash=cccknsdvxfahgkn34dugpdmdpa) es-module-lexer: specifier: ^1.6.0 version: 1.6.0 @@ -10253,7 +10256,7 @@ snapshots: dependencies: is-obj: 2.0.0 - dotenv-expand@12.0.1: + dotenv-expand@12.0.1(patch_hash=cccknsdvxfahgkn34dugpdmdpa): dependencies: dotenv: 16.4.7