`import.meta.env.DEV` and `PROD` are incorrect if a custom `mode` is provided programmatically
Describe the bug
Ordinarily, building a Vite app results in import.meta.env.DEV === false and import.meta.env.PROD === true regardless of the mode configuration.
If you set mode when calling vite.build(...) programmatically, however, DEV and PROD are true and false unless the mode happens to be production.
Reproduction
https://github.com/Rich-Harris/vite-mode-repro
System Info
System:
OS: macOS 12.0.1
CPU: (10) arm64 Apple M1 Max
Memory: 779.03 MB / 32.00 GB
Shell: 5.8 - /bin/zsh
Binaries:
Node: 16.15.1 - ~/.nvm/versions/node/v16.15.1/bin/node
Yarn: 1.22.19 - ~/.nvm/versions/node/v16.15.1/bin/yarn
npm: 8.11.0 - ~/.nvm/versions/node/v16.15.1/bin/npm
Browsers:
Chrome: 103.0.5060.114
Chrome Canary: 105.0.5187.0
Firefox: 102.0.1
Safari: 15.1
npmPackages:
vite: ^3.0.2 => 3.0.2
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.
I think this is expected behaviour per the docs. You'd need to set NODE_ENV=production in .env.[mode] to bring back the prod behaviour. Maybe it make sense to default to production for builds but it would be a breaking change.
We have the same issue here. The NODE_ENV=production doesn't set import.meta.env.PROD to true, unlike with Vite 2.
@cedeber can you provide a repro for that? Using the repro in this issue, adding .env.custom-programmatic with NODE_ENV=production fixed it for me.
Unfortunately no. But I think I've found the change (not sure it's an issue though).
We use Node workspaces but the run script, the vite config file and the .env file are on the root of the project.
So vite.config.ts contains root: "./packages/application/src".
If I move the env.staging file in this folder (instead of the root of the project /), then it works again. I also tried to log VITE_SOME_KEY=123 as in the example and it works.
I'll go ahead and close this since I agree with @bluwy that it's working as intended
Hang on a sec @benmccann — it's not working as intended. Either dev should be true in both cases where a custom mode is provided, or in neither. That's a matter for debate — personally I think it's bizarre that DEV is basically an alias for MODE !== 'production', and that it should instead reflect command — but either way there's a bug here.
I think this is expected behaviour per the docs
The docs are a bit ambiguous, I think:
A lot hinges on the interpretation of 'running in production'. If it means 'running in production' — i.e. MODE is "production" — then PROD should indeed be false if MODE === 'custom'. But by that logic, so should DEV! That's incompatible with "(always the opposite of import.meta.env.PROD)".
If instead 'production' means 'the output of vite build rather than vite dev' — which I think makes a lot more sense — then the docs are internally coherent, if slightly ambiguously worded.
I'd argue that since the observed behaviour depends entirely on whether mode is provided via vite.config.js or programmatically, it's effectively undefined, meaning we have the opportunity to choose the semantics that make the most sense and characterise it as a bugfix :)
Here's the logic as implemented, which looks at a few different variables to figure out if it's production: https://github.com/vitejs/vite/blob/60721ac53a1bf326d1cac097f23642faede234ff/packages/vite/src/node/config.ts#L450
I'm not sure it should reflect command. E.g. I think you should be able to test serving in production mode. If you want to know what command was run then it's probably safest to look at command.
But it does sounds like there's a bug here if passing the mode programatically and via vite.config.js are not behaving the same.
Wow, it was not clear for me that vite build --mode production would switch to PROD without the .env file.
I always found weird that vite build switched to DEV by default because a --mode is set. I always consider mode to be a way to manipulate a bit the config but never that it will switch the PROD/END env vars.
What happens then if you use it the other way, with --mode development and set a .env with NODE_ENV=production?
I believe the mode should stay a string and don't change the behavior with some hidden keywords. And I understand better that a build is always production except if you force it via the NODE_ENV=development, disregarding the meaning of the mode string.
I'm not sure it should reflect
command
That's a valid position, but it's often very useful to know if you're in vite dev or vite build (without juggling mode), so if that's the conclusion then I'd propose the addition of a new value:
import.meta.env.COMMAND; // 'build' or 'serve'
So vite dev gives COMMAND == "serve". That's how to make it even more confusing, imho.
Either
devshould betruein both cases where a custom mode is provided, or in neither. That's a matter for debate — personally I think it's bizarre thatDEVis basically an alias forMODE !== 'production', and that it should instead reflectcommand— but either way there's a bug here.
DEV isn't an alias for MODE !== 'production', it's more of an alias for process.env.NODE_ENV !== 'production', but only using MODE if process.env.NODE_ENV is not defined, since we need a value as a fallback (which IIUC this issue proposes to fallback with command === 'serve' or command === 'build' instead).
And according to https://vitejs.dev/guide/env-and-mode.html#modes:
However, it is important to understand that mode is a wider concept than just development vs. production. A typical example is you may want to have a "staging" mode where it should have production-like behavior, but with slightly different env variables from production.
It further explains that mode isn't something that affects dev / prod, it's just another "mode" your app is in, you have to configure what the "environment" is to affect dev / prod. Just that production "mode" gets special treatment as a prod "environment" by default.
So I think this isn't a bug. Maybe we could improve the docs, or implement a good fallback as proposed (which I think make sense, but for Vite 4), but it is still working as intended.
Thanks for the illuminating discussion. The only way I'm able to get import.meta.env.PROD to be true was with vite build.
Assuming the logic mentioned above:
https://github.com/vitejs/vite/blob/60721ac53a1bf326d1cac097f23642faede234ff/packages/vite/src/node/config.ts#L450-L452
I tried running my code in production mode using vite dev, but none of the following worked for me:
NODE_ENV=production vite devvite dev --mode production- Contents of
.envincludesNODE_ENV=productionandVITE_USER_NODE_ENV=productionthen I runvite dev
Is it safe to say that configuring production mode is only possible with vite build? I propose the current behaviour should be documented so it's clearer how to use Vite in production mode. I'm happy to contribute to the docs once I have a solid understanding of current config behaviour.
Is it safe to say that configuring production mode is only possible with
vite build? I propose the current behaviour should be documented so it's clearer how to use Vite in production mode. I'm happy to contribute to the docs once I have a solid understanding of current config behaviour.
Yes, you can't set production in dev as some integrations only apply HMR for non-prod environments. This behaviour is set at:
https://github.com/vitejs/vite/blob/1983cf43d4da92d40b1f96dff0a44def044f9130/packages/vite/src/node/config.ts#L363-L365
I agree that we could probably mention this somewhere in the docs.
Discussion here: https://github.com/vitejs/vite/discussions/9274
I believe this is fixed in https://github.com/vitejs/vite/pull/10996. Vite build will always default to prod by default, unless specifically changed with NODE_ENV=development in the env file, or in process.env.