vite icon indicating copy to clipboard operation
vite copied to clipboard

`import.meta.env.DEV` and `PROD` are incorrect if a custom `mode` is provided programmatically

Open Rich-Harris opened this issue 3 years ago • 13 comments

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

Rich-Harris avatar Jul 18 '22 22:07 Rich-Harris

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.

bluwy avatar Jul 19 '22 06:07 bluwy

We have the same issue here. The NODE_ENV=production doesn't set import.meta.env.PROD to true, unlike with Vite 2.

cedeber avatar Jul 19 '22 10:07 cedeber

@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.

bluwy avatar Jul 19 '22 12:07 bluwy

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.

cedeber avatar Jul 19 '22 13:07 cedeber

I'll go ahead and close this since I agree with @bluwy that it's working as intended

benmccann avatar Jul 19 '22 15:07 benmccann

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.

Rich-Harris avatar Jul 19 '22 15:07 Rich-Harris

I think this is expected behaviour per the docs

The docs are a bit ambiguous, I think:

image

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 :)

Rich-Harris avatar Jul 19 '22 15:07 Rich-Harris

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

benmccann avatar Jul 19 '22 15:07 benmccann

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.

benmccann avatar Jul 19 '22 15:07 benmccann

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.

cedeber avatar Jul 19 '22 16:07 cedeber

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'

Rich-Harris avatar Jul 19 '22 16:07 Rich-Harris

So vite dev gives COMMAND == "serve". That's how to make it even more confusing, imho.

cedeber avatar Jul 19 '22 16:07 cedeber

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.

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.

bluwy avatar Jul 20 '22 06:07 bluwy

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 dev
  • vite dev --mode production
  • Contents of .env includes NODE_ENV=production and VITE_USER_NODE_ENV=production then I run vite 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.

theetrain avatar Aug 02 '22 15:08 theetrain

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.

bluwy avatar Aug 02 '22 17:08 bluwy

Discussion here: https://github.com/vitejs/vite/discussions/9274

benmccann avatar Oct 18 '22 13:10 benmccann

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.

bluwy avatar Nov 28 '22 17:11 bluwy