Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Please remove process.env.NODE_ENV in dist/immer.mjs #1141

Open
diandian18 opened this issue Sep 4, 2024 · 6 comments
Open

Please remove process.env.NODE_ENV in dist/immer.mjs #1141

diandian18 opened this issue Sep 4, 2024 · 6 comments
Labels

Comments

@diandian18
Copy link

🚀 Feature Proposal

I use import { produce } from 'immer' in vite project. After building, process.env.NODE_ENV is still in my built file.

Motivation

Could process.env.NODE_ENV be removed in dist/immer.mjs?

@markerikson
Copy link
Contributor

That inclusion is intentional, and Vite should be replacing it automatically.

@blixt
Copy link

blixt commented Oct 3, 2024

This problem is not only about Vite, and this is typically not happening with other packages. As an example, using immer via JSPM (e.g. using the Import Map Generator) will not work in a browser unless you shim a Node.js environment.

@markerikson
Copy link
Contributor

I'm not familiar with how JSPM resolves which file to use inside of an NPM package, but if you need to use it in a browser directly you should be pointing it to dist/immer.production.mjs, which is an ESM module that has already been precompiled to strip out the process.env.NODE_ENV checks, minified, and is meant for use as a modern <script type="module"> directly.

@blixt
Copy link

blixt commented Oct 4, 2024

JSPM is an import maps first approach to package management so it does support development builds and production builds, so the true solution might not be as simple as to just say "use production builds if you want the Node environment stuff stripped out". However, I believe JSPM will respect the exports conditional property, i.e.:

{
  "exports": {
    "node": "./dist/cjs/index.js",
    "default": "./dist/esm/index.js"
  }
}

You can read more here: https://nodejs.org/api/packages.html#conditional-exports

Basically this would be the most official way to say "for Node environments we use this entry point, otherwise we use this other one".

For Immer, which already uses exports to differentiate CJS and ESM it would look something like this:

{
  // ...
  "exports": {
    "./package.json": "./package.json",
    ".": {
      "types": "./dist/immer.d.ts",
      "node": {
        "import": "./dist/immer.mjs",
        "require": "./dist/cjs/index.js"
      },
      "default": "./dist/immer.production.mjs"
    }
  },
  // ...
}

Now like I implied initially, this would hide the development version from JSPM (which would be useful if you want to have a bundler-less browser first environment with development support, like we did at Framer which is completely ES Modules + Import Maps based). But from what I can see, there is no ./dist/immer.browser.mjs or so which would be needed, and I do think the change I wrote above would already be a step up.

Now I'm not sure what @guybedford's stance is on these kinds of situations – for example esm.sh appears to have taken another approach where it doesn't include the process reference – possibly by figuring out which module is for production (maybe with a manual override?), or by just post-processing the code to consider process.env.NODE_ENV a constant that can be turned into true or false.

@guybedford
Copy link

JSPM will replace process.env.NODE_ENV in CommonJS as a CommonJS feature contract, but yes for native ES modules we don't do the same thing, the reason being that we don't consider it to be a modern pattern going forward into the native ES ecosystem.

What we do for CommonJS is effectively build two files - one with the dev and one with the production condition, and then set up entry conditions to those variations depending on which mode the package is loaded. It's a little messy, and doing this explicitly at the package level is the preferred model (using the "development" and "production" package conditions - https://nodejs.org/docs/latest/api/packages.html#community-conditions-definitions).

This is mostly a principled stance in JSPM though which we can change anytime, so if there is strong resistance to moving away from process.env.NODE_ENV in the ESM ecosystem we could support it in JSPM for native modules. import.meta.env is also another active discussion as a native ESM approach in Node.js itself.

As for using dist/immer.production.mjs, this isn't described in any of the package.json entry points for tools to pick up:

{
  "main": "./dist/cjs/index.js",
  "module": "./dist/immer.legacy-esm.js",
  "exports": {
    "./package.json": "./package.json",
    ".": {
      "types": "./dist/immer.d.ts",
      "import": "./dist/immer.mjs",
      "require": "./dist/cjs/index.js"
    }
  },
  "jsnext:main": "dist/immer.mjs",
  "react-native": "./dist/immer.legacy-esm.js"
}

Adding a browser entry to this in the above "exports" would be very helpful if that is the intention.

@markerikson
Copy link
Contributor

Sure, makes sense. Immer isn't my package, but I did contribute the packaging setup based on what I was working on for the Redux libraries. File a PR here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants