Skip to content

[transitions] Fix RTG import in ESM#48645

Open
mj12albert wants to merge 5 commits into
mui:masterfrom
mj12albert:fix-rtg-esm-import
Open

[transitions] Fix RTG import in ESM#48645
mj12albert wants to merge 5 commits into
mui:masterfrom
mj12albert:fix-rtg-esm-import

Conversation

@mj12albert

@mj12albert mj12albert commented Jun 9, 2026

Copy link
Copy Markdown
Member

Fixes #48636

@mj12albert mj12albert added scope: transitions Changes related to the transitions. type: regression A bug, but worse, it used to behave as expected. labels Jun 9, 2026
@code-infra-dashboard

code-infra-dashboard Bot commented Jun 9, 2026

Copy link
Copy Markdown

Deploy preview

https://deploy-preview-48645--material-ui.netlify.app/

Bundle size

Bundle Parsed size Gzip size
@mui/material 0B(0.00%) 0B(0.00%)
@mui/lab 0B(0.00%) 0B(0.00%)
@mui/private-theming 0B(0.00%) 0B(0.00%)
@mui/system 0B(0.00%) 0B(0.00%)
@mui/utils 0B(0.00%) 0B(0.00%)

Details of bundle changes


Check out the code infra dashboard for more information about this PR.

@mj12albert mj12albert force-pushed the fix-rtg-esm-import branch 3 times, most recently from 535ae44 to 7fec9ff Compare June 10, 2026 05:12
@mj12albert mj12albert requested a review from brijeshb42 June 10, 2026 05:12
@brijeshb42

Copy link
Copy Markdown
Contributor

Here's the package diff.
There's cjs in someplaces where it should be esm. Can you check ?

@mj12albert mj12albert force-pushed the fix-rtg-esm-import branch 2 times, most recently from c5ca3e9 to 5e9396f Compare June 14, 2026 19:10
@github-actions github-actions Bot added the PR: out-of-date The pull request has merge conflicts and can't be merged. label Jun 15, 2026
@mj12albert mj12albert force-pushed the fix-rtg-esm-import branch from be3b553 to 4dea53d Compare June 15, 2026 09:07
@github-actions github-actions Bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged. label Jun 15, 2026
@mj12albert mj12albert force-pushed the fix-rtg-esm-import branch from 4dea53d to c6ba36b Compare June 15, 2026 09:30
mj12albert

This comment was marked as outdated.

@mj12albert mj12albert marked this pull request as ready for review June 15, 2026 09:42
Comment thread babel.config.mjs Outdated
@Janpot

Janpot commented Jun 15, 2026

Copy link
Copy Markdown
Member
  • I believe codesandbox doesn't support imports.

  • It seems like your intention is

    // ./package.json
    "imports": {
      "#mui/TransitionGroupContext": {
        "import": "react-transition-group/esm/TransitionGroupContext.js",
        "require": "react-transition-group/cjs/TransitionGroupContext.js",
        "default": "react-transition-group/esm/TransitionGroupContext.js"
      }
    }

    Is that a correct assumption? This should be perfectly legal to do. Shall we just update code-infra such that you can override import and require targets correctly? We can build on top of [code-infra] Generate package.json imports field on build mui-public#1533 (we'd still be breaking codesandbox demos though)

@mj12albert

Copy link
Copy Markdown
Member Author
  • Is that a correct assumption?

@Janpot I think splitting import/require/default wouldn't work for the react-router-node-esm-ssr setup (it's added to /examples here):

  1. examples/react-router-node-esm-ssr/package.json has "type": "module"
  2. react-router build produces a server entry that is loaded by Node as ESM
  3. The app imports MUI transitions, for example Collapse
  4. The built MUI ESM file imports #mui/TransitionGroupContext
  5. Since Node is resolving that from ESM code, Node selects the import condition
  6. That sends Node to react-transition-group/esm/TransitionGroupContext.js
  7. In RTG 4.4.5, that file is intended for bundlers. RTG does not mark it as native Node ESM with "type": "module" or an exports map
  8. On supported Node versions like Node 16/18, Node treats that .js file as CommonJS and then errors when it sees import React from 'react'

So a more direct mapping (instead of mapping to src/internal/*) would be:

"#mui/TransitionGroupContext": {
  "node": "react-transition-group/cjs/TransitionGroupContext.js",
  "browser": "react-transition-group/esm/TransitionGroupContext.js",
  "default": "react-transition-group/esm/TransitionGroupContext.js"
}

@Janpot

Janpot commented Jun 15, 2026

Copy link
Copy Markdown
Member

Ok, that seems semantically correct. We also don't really need the browser condition I suppose? We only want to force node on cjs.

  "#mui/TransitionGroupContext": {
    "node": "react-transition-group/cjs/TransitionGroupContext.js",
    "default": {
      "import": "react-transition-group/esm/TransitionGroupContext.js",
      "require": "react-transition-group/cjs/TransitionGroupContext.js",
      "default": "react-transition-group/esm/TransitionGroupContext.js",
    }
  } 

Adding tests in code-infra for this scenario.

Now about codesandbox...

@mj12albert

Copy link
Copy Markdown
Member Author

@Janpot Without browser, a webpack browser app using Material UI via require()/CJS could face the duplicate context risk again?

  1. require('@mui/material/Collapse') selects the CJS build
  2. CJS build does require('#mui/TransitionGroupContext')
  3. There is no top-level browser condition, so resolution falls into default
  4. Since the request is CJS, the nested require condition wins
  5. Collapse gets react-transition-group/cjs/TransitionGroupContext.js
  6. Separately, Webpack’s browser defaults prefer package module over main, so require('react-transition-group') can resolve RTG to esm/index.js
  7. RTG TransitionGroup provides react-transition-group/esm/TransitionGroupContext.js
  8. TransitionGroup and Collapse now use two different React contexts

@Janpot

Janpot commented Jun 15, 2026

Copy link
Copy Markdown
Member

👍 ok, makes sense

@mj12albert

Copy link
Copy Markdown
Member Author

Changed the fix, latest canary:

pnpm add https://pkg.pr.new/mui/material-ui/@mui/material@8752430

@Janpot It doesn't use package imports and CSB works now: https://codesandbox.io/p/sandbox/confident-snow-whlrhk

@Janpot Janpot left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I think I can live with a browser field, as long as it doesn't include any of our own paths. Thanks for looking into it.

Comment thread babel.config.mjs Outdated
return `./${resolvedPath.replace('\\', '/')}`;
}

function rewriteTransitionGroupContextImport() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this isn't needed anymore right?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's still needed as the first part of the fix, so that builds rewrite the import to react-transition-group/cjs/TransitionGroupContext.js for the node setups

Additionally, the "browser" field rewrites this to react-transition-group/esm/TransitionGroupContext.js for browser bundlers to handle the Webpack+CJS case

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just import from react-transition-group/cjs/TransitionGroupContext.js in the source?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I didn't even think about this as a possibility

The Codex evaluation is that: it could work, but changing it in the source like that is riskier because in the repo we alias '@mui/material' to 'packages/mui-material/src', so it's a larger surface area to check for issues

Whereas this babel "plugin" is just fixing the built package, whatdo you think? @Janpot

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whereas this babel "plugin" is just fixing the built package, whatdo you think?

tbh, that reply of codex doesn't make much sense to me. Ideally we don't mess too much with the build system. Any weird workaround only makes it harder for us to move it forward towards more modern tooling. Did you try if just the following + browser condition works?

import TransitionGroupContext from 'react-transition-group/cjs/TransitionGroupContext.js';

Actually this also reminds me of a similar "fix" we did for next.js document, but that doesn't have to load in the browser.

@mj12albert mj12albert requested a review from Janpot June 17, 2026 22:26
Comment thread babel.config.mjs Outdated
) {
// Use the explicit CJS file for Node builds; package.json's `browser`
// field redirects this request to RTG's ESM file in browser bundlers.
babelPath.node.source.value = 'react-transition-group/cjs/TransitionGroupContext.js';

@brijeshb42 brijeshb42 Jun 18, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't this transform to esm for the esm build of our package instead of the current cjs in both the cases ?
The output Transition.mjs file has react-transition-group/cjs/TransitionGroupContext.js as the import path instead of esm.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brijeshb42 The issue is that react-transition-group/esm/TransitionGroupContext.js contains ESM syntax, but their package.json does not have "type": "module", it uses this older "module": https://github.com/reactjs/react-transition-group/blob/2989b5b87b4b4d1001f21c8efa503049ffb4fe8d/package.json#L5-L6

This causes Node 16/18 to treat it as CJS and error, does that make sense? (this is my understanding of a long Codex explanation)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Got it. Ideally, it should have had mjs extension if no type: module in package.json

@brijeshb42

Copy link
Copy Markdown
Contributor

Best case would be to contribute the required change back to the repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: transitions Changes related to the transitions. type: regression A bug, but worse, it used to behave as expected.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

@mui/material@9.1.0: ERR_UNSUPPORTED_DIR_IMPORT from new internal/Transition.tsx

3 participants