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

[RTK Alpha]: Invalid exports config for CJS consumption w/ Node #3208

Closed
rschristian opened this issue Feb 25, 2023 · 7 comments
Closed

[RTK Alpha]: Invalid exports config for CJS consumption w/ Node #3208

rschristian opened this issue Feb 25, 2023 · 7 comments
Milestone

Comments

@rschristian
Copy link
Contributor

I skimmed the issues but couldn't find anything matching, so apologies if it's a duplicate and/or intentional.

The current config in the Alpha does not allow for consumption of the CJS bundle in modern version of Node/any tool that follows Node's module resolution spec, as it uses .js to refer to a CJS module despite the package setting "type": "module". If "type": "module" is set, .cjs is necessary in "exports".

Some bundlers do work around this and are more forgiving (whether or not that's a good thing is something else entirely), but this config will not work in Node and/or any environments that follow its resolution mechanism.

To reproduce:

// index.cjs
const { createSlice } = require('@reduxjs/toolkit');
console.log(typeof createSlice);

Attempting to execute this file (node index.cjs) will result in the following expected error:

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/ryun/Projects/example/node_modules/redux-thunk/lib/index.js
require() of ES modules is not supported.
require() of /home/ryun/Projects/example/node_modules/redux-thunk/lib/index.js from /home/ryun/Projects/example/node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.cjs.development.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /home/ryun/Projects/example/node_modules/redux-thunk/package.json.

Generally, it should be pretty safe to use .cjs in "exports". Both are relatively new, and any environment that supports consuming from "exports" should support .cjs. This may mean you'll want to duplicate your CJS bundles, however (provide as .js for "main" and the spec-adherent .cjs for "exports"), assuming you're not opposed to larger install size.

@markerikson markerikson added this to the 2.0 milestone Feb 25, 2023
@markerikson
Copy link
Collaborator

sigh

this is exactly why I keep begging somebody, anybody, to put together a comprehensive and authoritative guide to doing this :(

@rschristian
Copy link
Contributor Author

rschristian commented Feb 25, 2023

Yeah, sorry. Happy to help where I can, I've (unfortunately, I guess) dealt with this (and the following headaches) quite a bit while maintaining a few build tools. It's admittedly a lot of esoteric knowledge and a lot of "it depends on what you want to support".

On the other hand, if no one has raised an issue yet, and you have enough users on the alpha, maybe no one's using RTK in Node/compliant environments and trying to consume CJS? Might be a non-issue, but one I thought I'd raise at least.

@markerikson
Copy link
Collaborator

I assume no one is using the alpha, period.

Both because that's what always happens with pre-releases, and also because no one is raising feedback so far.

I do honestly appreciate you filing the issue, but I am also legitimately getting angry at how messed up this whole situation is :(

I want to do right by my users and support the variety of build tools and environments I expect they'll be using for their apps.

But I can't do that if every single article and person is giving me contradictory instructions on what I'm supposed to do :(

@rschristian
Copy link
Contributor Author

I'll try to write up a PR later tonight if I can for what my suggestion would be, but it really is a bad situation in the ecosystem in all reality. I think it's fair to say ecosystem collectively screwed up the CJS -> ESM transition pretty hard, from bundlers jumping on ESM early ("module" in package.json), to spec committees being a tad detached, to third party tools (TS) layering their own stuff on top.

It's contradictory because the ecosystem is sadly contradictory.

@atomiks
Copy link

atomiks commented Feb 25, 2023

The following configuration should work across all tools:

  • Don't use "type": "module"
  • Top-level main links to .js extension (avoid .cjs)
  • Top-level module links to .js extension (avoid .mjs)
  • In exports, import links to .mjs, while module links to .js

This means you have two separate ESM builds, one with .js (webpack 4) and another with .mjs for modern tools to work without the module package.json type.

I saw this format from zustand early last year, and no one has reported issues since then:

{
  "main": "./dist/cjs/index.js",
  "module": "./dist/es/index.js",
  "exports": {
    "./package.json": "./package.json",
    ".": {
      "types": "./types/index.d.ts",
      "import": "./dist/es/index.mjs",
      "module": "./dist/es/index.js",
      "default": "./dist/cjs/index.js"
    }
  }
}

@rschristian
Copy link
Contributor Author

There's not much of a reason to add "module" into "exports" if it can be avoided (it's mainly to avoid dual-package hazard issues in build tools), but that's otherwise what I'd recommend.

@markerikson
Copy link
Collaborator

I think we can call this fixed as of the latest 2.0 alphas.

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

No branches or pull requests

3 participants