Environment variable value not reloading when ".env changed, restarting server..." if process.env. is mutated once
Describe the bug
I was thinking it is a critical issue but when recreating the minimal reproducible PoC for the issue I found the root cause. I still think this should be resolved even if it is more related to the developer's mistake than a bug.
Long story short; I was looking to use process.env. in the vite.config.js file and I found this example https://stackoverflow.com/a/70711383 but that response is not compatible with the current vite at all and will create all sorts of issues if used in dev mode.
// !!! DO NOT USE !!!
import { defineConfig, loadEnv } from "vite";
import react from "@vitejs/plugin-react";
// https://vitejs.dev/config/
export default ({ mode }) => {
process.env = { ...process.env, ...loadEnv(mode, process.cwd()) };
console.log(process.env);
return defineConfig({
plugins: [react()],
});
};
The issue lies in the mutation of the process.env object because as soon as the process.env is set loadEnv will not override the values from process.env
// This is fine but not ideal
import { defineConfig, loadEnv } from "vite";
import react from "@vitejs/plugin-react";
// https://vitejs.dev/config/
export default ({ mode }) => {
const env = { ...process.env, ...loadEnv(mode, process.cwd()) };
console.log(env);
return defineConfig({
plugins: [react()],
});
};
The reason I'm opening this as a bug is as I see the way to resolve this issue such that it works in both cases, and this doesn't seem like intended behaviour, we could save the state of process.env at the first run of the server and consider this for the last loop in loadEnv for subsequent server reloads, making snippet valid. As this is only used to prioritise inline env vars according to the comment.
I've also left updated solution on StackOverflow
Reproduction
https://stackblitz.com/edit/vitejs-vite-wrbmyr?file=.env
Steps to reproduce
No response
System Info
System:
OS: Linux 5.0 undefined
CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
Memory: 0 Bytes / 0 Bytes
Shell: 1.0 - /bin/jsh
Binaries:
Node: 18.20.3 - /usr/local/bin/node
Yarn: 1.22.19 - /usr/local/bin/yarn
npm: 10.2.3 - /usr/local/bin/npm
pnpm: 8.15.6 - /usr/local/bin/pnpm
npmPackages:
vite: ^5.3.2 => 5.3.3
Used Package Manager
npm
Logs
No response
Validations
- [X] Follow our Code of Conduct
- [X] Read the Contributing Guidelines.
- [X] Read the docs.
- [X] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- [X] Make sure this is a Vite issue and not a framework-specific issue. For example, if it's a Vue SFC related bug, it should likely be reported to vuejs/core instead.
- [X] Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
- [X] The provided reproduction is a minimal reproducible example of the bug.
Remix uses Object.assign(process.env, loadEnv(mode, root, "")) to expose env files on server side process.env during dev, so it suffers from the same issue https://github.com/remix-run/remix/issues/9587.
I have also realized today that Astro is doing the same thing. Nonetheless, I also think this isn't technically a bug in Vite so we can close this?
Please do not close this one, I would argue this is a bug in Vite. What we are currently sure is that it is at least unintended behaviour of Vite dev server. (actually loadEnv func)
I would expect whenever Vite dev server reloads, that it takes latest value in updated .env file, and that I can use process.env in Vite config. Not working like that without any warnings to developer is an issue. PR #17712 fixes the issue/bug completely.
For dev ssr, repeating loading .env and exposing it on process.env is probably a valid and important use case, but I think I found a workaround https://github.com/hi-ogawa/vite-plugins/pull/657.
I'm not sure if this is a bug either as overwriting process.env shouldn't be necessary for SPA use cases at least. For ssr framework, they can have own convention to not rely on process.env, so the issue seems often avoided.
I've hit this same issue a few times now and definitely think this is an area that needs attention from vite / rollup.
Consider this plugins situation - https://stackblitz.com/~/github.com/SuperStreaming/intlayerapp?file=vite.config.ts
4 plugins -
export const plugin1 = (): PluginOption => ({
name: "plugin1",
config: () => {
process.env = {
...process.env,
VITE_CUSTOM_VAR: "A CUSTOM VAR",
VITE_A_OVERRIDED_VAR: "OVERRIDED PLUGIN 1",
};
},
});
export const plugin2 = (): PluginOption => ({
name: "plugin2",
config: () => {
process.env = {
VITE_CUSTOM_VAR2: "A CUSTOM VAR 2",
VITE_A_OVERRIDED_VAR: "OVERRIDED PLUGIN 2",
};
},
});
export const plugin3 = (): PluginOption => ({
name: "plugin3",
config: () => {
process.env.VITE_CUSTOM_VAR3 = "A CUSTOM VAR 3";
process.env.VITE_A_OVERRIDED_VAR = "OVERRIDED PLUGIN 3";
},
});
export const brokenPlugin = (): PluginOption => ({
name: "brokenPlugin",
config: (config) => {
dotenv.config({
path: [
`.env.${config.mode}.local`,
`.env.${config.mode}`,
".env.local",
".env",
],
});
},
});
You will get different envs set, in different ways, based on the order you add the plugins in your config,
export default defineConfig({
plugins: [react(), plugin1(), brokenPlugin(), plugin2(), plugin3()],
server: {
open: true,
},
});
gives you different to...
export default defineConfig({
plugins: [react(), plugin3(), plugin2(), plugin1(), brokenPlugin()],
server: {
open: true,
},
});
I'm not sure if this is the correct (or safe?) way to even set env vars from a plugin because I can't even find docs on env vars for plugins in the vite/rollup docs.
For me, I'd prefer a one, and one only safe way to set env vars config.updateEnv({my_new_var: "seaders"}), and a warning (or error out?) if envs are changed any other way, at least in dev mode.
The errors I have hit, I'm just lucky that I initially hit it myself, so had an understanding of what actually was going on, and that the plugin I used was open source - with a really communicative responsive dev. If I had just installed that plugin / another plugin that did similar, I'd have zero awareness of env var shenanigans going on.