Skip to content

Conversation

@brijeshb42
Copy link
Contributor

@brijeshb42 brijeshb42 commented Jan 22, 2026

  1. New cli arg --flat for the new logic to create flat builds

  2. Flat builds create mjs (and d.mts for types) files for esm and cjs (and d.cts for types) files for cjs builds for simplicity. There are no js files now.. I scrapped this due to an issue with tsc compilation where it needs the presence of d.ts files which was not present with this (only .d.cts and .d.mts files were present). This can perhaps be achieved when we move over to use a bundler but not currently.

    Flat builds use the type value of package.json to determine the output file extensions.
    For module -

    1. .js files are es modules and .cjs files are commonjs.
    2. main field points to index.cjs (if export['.'] is present and module field points to index.js

    For commonjs or when no type is specified -

    1. .js files are commonjs and .mjs files are es modules.
    2. main field points to index.js (if export['.'] is present and module field points to index.mjs
  3. Added validation for bin field in package.json. It should point to the source files instead of built files now.

  4. Some refactoring/tests around exports and bin generation for output package.json.

To fix:

  • tsc build with project references throws error
  • Fix issues on windows.

In an effort to fix issues like -

  1. Can't get MUI 7 working with module federation (MUI 6 worked fine) material-ui#47561
  2. Codesandbox
  3. Parcel vanilla mode

Downstream changes -

  1. [code-infra] Setup flat build for packages base-ui#3830 (has bundler analyses as well)
  2. [code-infra] Setup flat build for packages mui-x#21029
  3. [code-infra] Setup flat build for packages material-ui#47670

@brijeshb42 brijeshb42 added scope: code-infra Involves the code-infra product (https://www.notion.so/mui-org/5562c14178aa42af97bc1fa5114000cd). breaking change Introduces changes that are not backward compatible. labels Jan 22, 2026
@netlify
Copy link

netlify bot commented Jan 22, 2026

Deploy Preview for mui-internal ready!

Name Link
🔨 Latest commit 75e8dac
🔍 Latest deploy log https://app.netlify.com/projects/mui-internal/deploys/69773192a0671e000853718a
😎 Deploy Preview https://deploy-preview-1064--mui-internal.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@mui-bot
Copy link

mui-bot commented Jan 22, 2026

Bundle size report

Bundle Parsed size Gzip size
@base-ui-components/react 0B(0.00%) 0B(0.00%)
@mui/x-charts-pro 0B(0.00%) 0B(0.00%)

Details of bundle changes


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

@brijeshb42 brijeshb42 requested a review from a team January 22, 2026 14:04
The executable files that should be installed into the `PATH`.
*/
bin?: string | Partial<Record<string, string>>;
bin?: string | Record<string, string>;
Copy link
Member

@Janpot Janpot Jan 22, 2026

Choose a reason for hiding this comment

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

This would cause pkg.bin['any string here'] to be of type string. We want it to be string | undefined.

Suggested change
bin?: string | Record<string, string>;
bin?: string | Partial<Record<string, string>>;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But isn't that the case ? If pkg.bin has a key, it should have a value. It can't be undefined. Or maybe I am missing some use-case.

Copy link
Member

Choose a reason for hiding this comment

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

The way this is declared has a reason. It's to maximize type safety. Consider the following example under your changes:

function checkBin(pkg: PackageJson) {
  const foo: string = pkg.bin['some nonsense']
  console.log(typeof foo);
  // prints undefined, even though we declared it as string
}

Compiles without a problem and the type of foo is actually not corresponding to the actual value at runtime. this is a common source of bugs. If we do Partial, then it will complain about assigning something that can potentially be undefined to a string.

Moreover, it requires you to be defensive, typescript forces you to add a check whether the property exists before blindly using it:

function checkBin(pkg: PackageJson) {
  if (pkg.bin['some-script']) {
    const path: string = pkg.bin['some-script']
  }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you mean that there might be a case that someone has not specified a value for a key in package.json['bin'] ? Like this -

"bin": {
  "code-infra": null // since there cannot be undefined
}

I don't see this happening but I have reverted any ways since it required 1-2 if checks.

Copy link
Member

Choose a reason for hiding this comment

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

no, the oppositie, that someone tries to access a key that is not in that object.

@Janpot
Copy link
Member

Janpot commented Jan 22, 2026

Nice work. I think you may want to check

// cjs for reexporting from commons only modules.
// If we need to rely more on this we can think about setting up a separate commonjs => commonjs build for .cjs files to .cjs
// `--extensions-.cjs --out-file-extension .cjs`
await cjsCopy({ from: sourceDir, to: outDir });

It's to handle an edge case with Next.js used here: https://github.com/mui/material-ui/blob/b09d704dcdc0de3ea0d54b10e1c0803e8256b415/packages/mui-material-nextjs/src/v13-appRouter/appRouterV13.tsx#L6

I suspect that:

  • it will now copy the file twice into the same location
  • it may conflict with other .cjs files we emit

Not sure though

@csvan
Copy link

csvan commented Feb 6, 2026

Any news on this? It's a critical fix to make MUI work with Module Federation currently

@brijeshb42
Copy link
Contributor Author

Although this has been implemented, we need to test the build output with all the bundlers to make sure that it won't introduce any bugs.

@brijeshb42
Copy link
Contributor Author

@Janpot The PR is now ready. I've posted a detailed bundler comparison in Base UI PR.

@Janpot
Copy link
Member

Janpot commented Feb 10, 2026

Does this work with codesandbox now? Is it portable to Core/X?

@brijeshb42
Copy link
Contributor Author

brijeshb42 commented Feb 10, 2026

No. No codesandbox still. I was just trying to make sure anything that already works is not breaking. Codesandbox doesn't work with current structure as well as the new one.
I am checking out CSB as a followup but that should not block this.

Is it portable to Core/X?

Yes. Same structure for all our packages. I analyzed just Base UI since it was already setup with Michal's bundler project.

await createFile(
path.join(
outputDir,
`index${getOutExtension('esm', { isFlat: true, packageType: 'module' })}`,
Copy link
Member

@Janpot Janpot Feb 10, 2026

Choose a reason for hiding this comment

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

I would avoid using getOutExtension in fixtures. If there's a bug in getOutExtension, it may cancel each other out in the implementation details. Instead, make the fixture more static and explicit:

`index.mjs`,

Tests must be as simple as possible, we don't want to have to create tests for tests.

Can these files be created in parallel?

Are these tests written by AI?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. It has followed what was in the AGENTS file, ie, to make the tests closer to the real world. That's why its actually creating the files instead of simulating a filesystem.

1. New cli arg `--flat` for the new logic to create flat builds
2. Flat builds create `mjs` (and `d.mts` for types) files for esm and
`cjs` (and `d.cts` for types) files for cjs builds for simplicity. There
are no `js` files now.
3. Added validation for `bin` field in `package.json`. It should point
to the source files instead of built files now.
@brijeshb42
Copy link
Contributor Author

brijeshb42 commented Feb 11, 2026

@csvan Could you verify if module federation related issues are resolved if you use @mui/material version https://pkg.pr.new/mui/material-ui/@mui/material@eca9727 ? All the other CI published packages are listed here (if required) - https://github.com/mui/material-ui/pull/47670/checks?check_run_id=63203520528

this will remove matching exports from the final package.json
The package might be trying to block an import
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking change Introduces changes that are not backward compatible. scope: code-infra Involves the code-infra product (https://www.notion.so/mui-org/5562c14178aa42af97bc1fa5114000cd).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants