mui / base-ui

Base UI is an open-source library of accessible, unstyled UI components for React.
MIT License
288 stars 47 forks source link

[core] Add exports field and build proper ES modules (no import extensions variant) #821

Closed michaldudak closed 3 days ago

michaldudak commented 1 week ago

Builds "true" ES modules alongside CommonJS output.

Summary of changes

Type definitions

To verify if different methods of module resolution in TypeScript can resolve the exported types, the Are The Types Wrong (ATTW) tool was used. Its reports led to building the type definitions per build output (to avoid errors like False CJS and False ESM. Another reported issue was the inability to resolve types under the node10 module resolution when the exports field is used. While we don't support Node 10, Typescript uses this resolution strategy by default (see https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/NoResolution.md#false-positive-unsupported-file-extension). To work around this, I introduced the typesVersions field in package.json, as described in https://github.com/andrewbranch/example-subpath-exports-ts-compat/tree/main/examples/node_modules/types-versions-wildcards.

Testing

I created a repo to test the package with different bundlers and plain Node.js: https://github.com/michaldudak/base-ui-bundler-tests. There is an issue with running a Node.js app in ESM mode due to Base UI dependency on @mui/utils. The utils package does not currently conform to the ESM spec and cannot be used without a bundler this way. As we're planning to move away from it and define our utilities locally (#827), this won't be a problem for long.


This is a variant of #745 that does not require file extensions in import/export specifiers. It uses babel-plugin-add-import-extension to modify JS files and tsc-alias to modify type definitions.

Closes #550 Closes #648

mui-bot commented 1 week ago

Netlify deploy preview

https://deploy-preview-821--base-ui.netlify.app/

Generated by :no_entry_sign: dangerJS against 79f09095bea8fe1d14ab0632e0285dabad0f8034

Janpot commented 1 week ago

I'd expected the result after running tsc-alias to be the same regardless of esm or cjs. isn't that the case if you used the same file extension for both?

michaldudak commented 1 week ago

It does look the same in this case, yes (I don't know if that's true for any input, but I haven't found anything that could cause differences so far).

I went the simpler way, not having to deal with copying build .d.ts files across directories, but since running tsc twice adds a few seconds to the build time, I now redid this the right way - building types once to the esm directory, running tsc-alias on the output, and copying them to the cjs directory.