diff --git a/babel.config.js b/babel.config.js index 45a7c55167cee9..007aa7497d4a3b 100644 --- a/babel.config.js +++ b/babel.config.js @@ -74,7 +74,7 @@ module.exports = function getBabelConfig(api) { // in webpack config: api.env(['regressions']); - const outFileExtension = '.js'; + const outFileExtension = useESModules ? '.mjs' : '.js'; /** @type {babel.PluginItem[]} */ const plugins = [ diff --git a/docs/data/material/customization/typography/ResponsiveFontSizesChart.js b/docs/data/material/customization/typography/ResponsiveFontSizesChart.js index b80931885b4977..5ab87803cded60 100644 --- a/docs/data/material/customization/typography/ResponsiveFontSizesChart.js +++ b/docs/data/material/customization/typography/ResponsiveFontSizesChart.js @@ -1,9 +1,9 @@ import * as React from 'react'; -// import of a small, pure module in a private demo -// bundle size and module duplication is negligible -// eslint-disable-next-line no-restricted-imports -import { convertLength } from '@mui/material/styles/cssUtils'; -import { createTheme, responsiveFontSizes } from '@mui/material/styles'; +import { + createTheme, + responsiveFontSizes, + unstable_convertLength as convertLength, +} from '@mui/material/styles'; import Box from '@mui/material/Box'; import { LineChart } from '@mui/x-charts'; diff --git a/docs/data/material/guides/minimizing-bundle-size/minimizing-bundle-size.md b/docs/data/material/guides/minimizing-bundle-size/minimizing-bundle-size.md index c38c47545c3c00..236656e2408eda 100644 --- a/docs/data/material/guides/minimizing-bundle-size/minimizing-bundle-size.md +++ b/docs/data/material/guides/minimizing-bundle-size/minimizing-bundle-size.md @@ -214,50 +214,25 @@ It will perform the following diffs: The packages published on npm are **transpiled** with [Babel](https://github.com/babel/babel), optimized for performance with the [supported platforms](/material-ui/getting-started/supported-platforms/). -A [modern bundle](#modern-bundle) is also available. - -### How to use custom bundles? - -:::error -You are strongly discouraged to: - -- Import from any of the custom bundles directly. Do not do this: - - ```js - import { Button } from '@mui/material/legacy'; - ``` - - You have no guarantee that the dependencies also use legacy or modern bundles, leading to module duplication in your JavaScript files. - -- Import from any of the undocumented files or folders. Do not do this: - - ```js - import { Button } from '@mui/material/esm'; - ``` - - You have no guarantee that these imports will continue to work from one version to the next. +### Modern bundle - ::: +The modern bundle targets the latest released versions of evergreen browsers (Chrome, Firefox, Safari, Edge). +This can be used to make separate bundles targeting different browsers. -A great way to use these bundles is to configure bundler aliases, for example with [Webpack's `resolve.alias`](https://webpack.js.org/configuration/resolve/#resolvealias): +To use it, configure your bundler's resolve condition names. +For example, with [Webpack's `resolve.conditionNames`](https://webpack.js.org/configuration/resolve/#resolveconditionnames): -```js +```js title="webpack.config.js" { + // ... resolve: { - alias: { - '@mui/material': '@mui/material/legacy', - '@mui/styled-engine': '@mui/styled-engine/legacy', - '@mui/system': '@mui/system/legacy', - '@mui/base': '@mui/base/legacy', - '@mui/utils': '@mui/utils/legacy', - '@mui/lab': '@mui/lab/legacy', - } + conditionNames: ['mui-modern', 'import', 'default']; } } ``` -### Modern bundle +Here's the documentation for common bundlers: -The modern bundle can be found under the [`/modern` folder](https://unpkg.com/@mui/material/modern/). -It targets the latest released versions of evergreen browsers (Chrome, Firefox, Safari, Edge). -This can be used to make separate bundles targeting different browsers. +- [Webpack](https://webpack.js.org/configuration/resolve/#resolveconditionnames) +- [Vite](https://vitejs.dev/config/shared-options.html#resolve-conditions) +- [ESBuild](https://esbuild.github.io/api/#conditions) diff --git a/packages/mui-base/package.json b/packages/mui-base/package.json index 8f89b4c048608f..6a0565d3422c1f 100644 --- a/packages/mui-base/package.json +++ b/packages/mui-base/package.json @@ -28,10 +28,10 @@ }, "scripts": { "build": "pnpm build:modern && pnpm build:node && pnpm build:stable && pnpm build:types && pnpm build:copy-files", - "build:modern": "node ../../scripts/build.mjs modern", - "build:node": "node ../../scripts/build.mjs node", - "build:stable": "node ../../scripts/build.mjs stable", - "build:copy-files": "node ../../scripts/copyFiles.mjs", + "build:modern": "node ../../scripts/build.mjs modern --exportFormat exports", + "build:node": "node ../../scripts/build.mjs node --exportFormat exports", + "build:stable": "node ../../scripts/build.mjs stable --exportFormat exports", + "build:copy-files": "node ../../scripts/copyFiles.mjs --exportFormat exports", "build:types": "node ../../scripts/buildTypes.mjs", "prebuild": "rimraf build tsconfig.build.tsbuildinfo", "release": "pnpm build && pnpm publish", diff --git a/packages/mui-joy/package.json b/packages/mui-joy/package.json index 4169ee07e1d129..5618dda96aceed 100644 --- a/packages/mui-joy/package.json +++ b/packages/mui-joy/package.json @@ -26,10 +26,10 @@ }, "scripts": { "build": "pnpm build:modern && pnpm build:node && pnpm build:stable && pnpm build:types && pnpm build:copy-files", - "build:modern": "node ../../scripts/build.mjs modern", - "build:node": "node ../../scripts/build.mjs node", - "build:stable": "node ../../scripts/build.mjs stable", - "build:copy-files": "node ../../scripts/copyFiles.mjs", + "build:modern": "node ../../scripts/build.mjs modern --exportFormat exports", + "build:node": "node ../../scripts/build.mjs node --exportFormat exports", + "build:stable": "node ../../scripts/build.mjs stable --exportFormat exports", + "build:copy-files": "node ../../scripts/copyFiles.mjs --exportFormat exports", "build:types": "node ../../scripts/buildTypes.mjs", "prebuild": "rimraf build tsconfig.build.tsbuildinfo", "release": "pnpm build && pnpm publish", diff --git a/packages/mui-lab/package.json b/packages/mui-lab/package.json index 7700db598879df..77ff5e5010f3cb 100644 --- a/packages/mui-lab/package.json +++ b/packages/mui-lab/package.json @@ -29,10 +29,10 @@ }, "scripts": { "build": "pnpm build:modern && pnpm build:node && pnpm build:stable && pnpm build:types && pnpm build:copy-files", - "build:modern": "node ../../scripts/build.mjs modern", - "build:node": "node ../../scripts/build.mjs node", - "build:stable": "node ../../scripts/build.mjs stable", - "build:copy-files": "node ../../scripts/copyFiles.mjs", + "build:modern": "node ../../scripts/build.mjs modern --exportFormat exports", + "build:node": "node ../../scripts/build.mjs node --exportFormat exports", + "build:stable": "node ../../scripts/build.mjs stable --exportFormat exports", + "build:copy-files": "node ../../scripts/copyFiles.mjs --exportFormat exports", "build:types": "node ../../scripts/buildTypes.mjs", "prebuild": "rimraf build tsconfig.build.tsbuildinfo", "release": "pnpm build && pnpm publish", diff --git a/packages/mui-material-nextjs/package.json b/packages/mui-material-nextjs/package.json index 375e28ab8ecdd0..692a75c77fbbd1 100644 --- a/packages/mui-material-nextjs/package.json +++ b/packages/mui-material-nextjs/package.json @@ -25,9 +25,9 @@ }, "scripts": { "build": "pnpm build:modern && pnpm build:node && pnpm build:stable && pnpm build:types && pnpm build:copy-files", - "build:modern": "node ../../scripts/build.mjs modern", - "build:node": "node ../../scripts/build.mjs node", - "build:stable": "node ../../scripts/build.mjs stable", + "build:modern": "node ../../scripts/build.mjs modern --exportFormat exports", + "build:node": "node ../../scripts/build.mjs node --exportFormat exports", + "build:stable": "node ../../scripts/build.mjs stable --exportFormat exports", "build:copy-files": "node ../../scripts/copyFiles.mjs", "build:types": "node ../../scripts/buildTypes.mjs", "prebuild": "rimraf build tsconfig.build.tsbuildinfo", diff --git a/packages/mui-material/package.json b/packages/mui-material/package.json index 959b2aee3c7dfd..a904925af59612 100644 --- a/packages/mui-material/package.json +++ b/packages/mui-material/package.json @@ -28,10 +28,10 @@ }, "scripts": { "build": "pnpm build:modern && pnpm build:node && pnpm build:stable && pnpm build:types && pnpm build:copy-files", - "build:modern": "node ../../scripts/build.mjs modern", - "build:node": "node ../../scripts/build.mjs node", - "build:stable": "node ../../scripts/build.mjs stable", - "build:copy-files": "node ../../scripts/copyFiles.mjs", + "build:modern": "node ../../scripts/build.mjs modern --exportFormat exports", + "build:node": "node ../../scripts/build.mjs node --exportFormat exports", + "build:stable": "node ../../scripts/build.mjs stable --exportFormat exports", + "build:copy-files": "node ../../scripts/copyFiles.mjs --exportFormat exports", "build:types": "node ../../scripts/buildTypes.mjs", "prebuild": "rimraf build tsconfig.build.tsbuildinfo", "release": "pnpm build && pnpm publish", diff --git a/packages/mui-material/src/styles/index.d.ts b/packages/mui-material/src/styles/index.d.ts index f029178794472a..d8194bf0620f67 100644 --- a/packages/mui-material/src/styles/index.d.ts +++ b/packages/mui-material/src/styles/index.d.ts @@ -87,7 +87,11 @@ export { ComponentsProps, ComponentsPropsList } from './props'; export { ComponentsVariants } from './variants'; export { ComponentsOverrides, ComponentNameToClassKey } from './overrides'; export { Components } from './components'; -export { getUnit as unstable_getUnit, toUnitless as unstable_toUnitless } from './cssUtils'; +export { + getUnit as unstable_getUnit, + toUnitless as unstable_toUnitless, + convertLength as unstable_convertLength, +} from './cssUtils'; export type ClassNameMap = Record; @@ -102,7 +106,12 @@ export { default as makeStyles } from './makeStyles'; export { default as withStyles } from './withStyles'; export { default as withTheme } from './withTheme'; -export * from './ThemeProviderWithVars'; +export { + useColorScheme, + getInitColorSchemeScript, + CssVarsProvider, + Experimental_CssVarsProvider, +} from './ThemeProviderWithVars'; export { default as extendTheme } from './createThemeWithVars'; diff --git a/packages/mui-material/src/styles/index.js b/packages/mui-material/src/styles/index.js index e856d1d5d2fa43..2d03e7abe793a8 100644 --- a/packages/mui-material/src/styles/index.js +++ b/packages/mui-material/src/styles/index.js @@ -29,7 +29,11 @@ export function experimental_sx() { export { default as createTheme, createMuiTheme } from './createTheme'; export { default as unstable_createMuiStrictModeTheme } from './createMuiStrictModeTheme'; export { default as createStyles } from './createStyles'; -export { getUnit as unstable_getUnit, toUnitless as unstable_toUnitless } from './cssUtils'; +export { + getUnit as unstable_getUnit, + toUnitless as unstable_toUnitless, + convertLength as unstable_convertLength, +} from './cssUtils'; export { default as responsiveFontSizes } from './responsiveFontSizes'; export { default as createTransitions, duration, easing } from './createTransitions'; export { default as createColorScheme } from './createColorScheme'; @@ -45,7 +49,12 @@ export { default as makeStyles } from './makeStyles'; export { default as withStyles } from './withStyles'; export { default as withTheme } from './withTheme'; -export * from './ThemeProviderWithVars'; +export { + useColorScheme, + getInitColorSchemeScript, + CssVarsProvider, + Experimental_CssVarsProvider, +} from './ThemeProviderWithVars'; export { default as extendTheme } from './createThemeWithVars'; export { default as experimental_extendTheme } from './experimental_extendTheme'; // TODO: Remove in v7 export { default as getOverlayAlpha } from './getOverlayAlpha'; diff --git a/packages/mui-material/src/useAutocomplete/useAutocomplete.js b/packages/mui-material/src/useAutocomplete/useAutocomplete.js index 264a6e2218acdf..7941b0472a3469 100644 --- a/packages/mui-material/src/useAutocomplete/useAutocomplete.js +++ b/packages/mui-material/src/useAutocomplete/useAutocomplete.js @@ -1,4 +1,3 @@ -'use client'; /* eslint-disable no-constant-condition */ import * as React from 'react'; import { diff --git a/packages/mui-material/src/utils/index.js b/packages/mui-material/src/utils/index.js index a43e01cd154380..4f5ec2e5871616 100644 --- a/packages/mui-material/src/utils/index.js +++ b/packages/mui-material/src/utils/index.js @@ -1,4 +1,3 @@ -'use client'; import { unstable_ClassNameGenerator as ClassNameGenerator } from '@mui/utils'; export { default as capitalize } from './capitalize'; diff --git a/packages/mui-private-theming/package.json b/packages/mui-private-theming/package.json index 6aeb37e5e32984..fa5a6f5c521e23 100644 --- a/packages/mui-private-theming/package.json +++ b/packages/mui-private-theming/package.json @@ -27,10 +27,10 @@ }, "scripts": { "build": "pnpm build:modern && pnpm build:node && pnpm build:stable && pnpm build:copy-files", - "build:modern": "node ../../scripts/build.mjs modern", - "build:node": "node ../../scripts/build.mjs node", - "build:stable": "node ../../scripts/build.mjs stable", - "build:copy-files": "node ../../scripts/copyFiles.mjs", + "build:modern": "node ../../scripts/build.mjs modern --exportFormat exports", + "build:node": "node ../../scripts/build.mjs node --exportFormat exports", + "build:stable": "node ../../scripts/build.mjs stable --exportFormat exports", + "build:copy-files": "node ../../scripts/copyFiles.mjs --exportFormat exports", "prebuild": "rimraf build", "release": "pnpm build && pnpm publish", "test": "cd ../../ && cross-env NODE_ENV=test mocha 'packages/mui-private-theming/**/*.test.{js,ts,tsx}'", diff --git a/packages/mui-styled-engine-sc/package.json b/packages/mui-styled-engine-sc/package.json index 64f019c18648f4..ec09d84940d7ee 100644 --- a/packages/mui-styled-engine-sc/package.json +++ b/packages/mui-styled-engine-sc/package.json @@ -27,10 +27,10 @@ }, "scripts": { "build": "pnpm build:modern && pnpm build:node && pnpm build:stable && pnpm build:copy-files", - "build:modern": "node ../../scripts/build.mjs modern", - "build:node": "node ../../scripts/build.mjs node", - "build:stable": "node ../../scripts/build.mjs stable", - "build:copy-files": "node ../../scripts/copyFiles.mjs", + "build:modern": "node ../../scripts/build.mjs modern --exportFormat exports", + "build:node": "node ../../scripts/build.mjs node --exportFormat exports", + "build:stable": "node ../../scripts/build.mjs stable --exportFormat exports", + "build:copy-files": "node ../../scripts/copyFiles.mjs --exportFormat exports", "prebuild": "rimraf build", "release": "pnpm build && pnpm publish", "test": "cd ../../ && cross-env NODE_ENV=test mocha 'packages/mui-styled-engine-sc/**/*.test.{js,ts,tsx}'", diff --git a/packages/mui-styled-engine/package.json b/packages/mui-styled-engine/package.json index 9ca2bec44e0256..e4b1c805dcd296 100644 --- a/packages/mui-styled-engine/package.json +++ b/packages/mui-styled-engine/package.json @@ -27,10 +27,10 @@ }, "scripts": { "build": "pnpm build:modern && pnpm build:node && pnpm build:stable && pnpm build:copy-files", - "build:modern": "node ../../scripts/build.mjs modern", - "build:node": "node ../../scripts/build.mjs node", - "build:stable": "node ../../scripts/build.mjs stable", - "build:copy-files": "node ../../scripts/copyFiles.mjs", + "build:modern": "node ../../scripts/build.mjs modern --exportFormat exports", + "build:node": "node ../../scripts/build.mjs node --exportFormat exports", + "build:stable": "node ../../scripts/build.mjs stable --exportFormat exports", + "build:copy-files": "node ../../scripts/copyFiles.mjs --exportFormat exports", "prebuild": "rimraf build", "release": "pnpm build && pnpm publish", "test": "cd ../../ && cross-env NODE_ENV=test mocha 'packages/mui-styled-engine/**/*.test.{js,ts,tsx}'", diff --git a/packages/mui-styles/package.json b/packages/mui-styles/package.json index 35b84b54fcca1f..fea694832ea0d1 100644 --- a/packages/mui-styles/package.json +++ b/packages/mui-styles/package.json @@ -27,10 +27,10 @@ }, "scripts": { "build": "pnpm build:modern && pnpm build:node && pnpm build:stable && pnpm build:copy-files", - "build:modern": "node ../../scripts/build.mjs modern", - "build:node": "node ../../scripts/build.mjs node", - "build:stable": "node ../../scripts/build.mjs stable", - "build:copy-files": "node ../../scripts/copyFiles.mjs", + "build:modern": "node ../../scripts/build.mjs modern --exportFormat exports", + "build:node": "node ../../scripts/build.mjs node --exportFormat exports", + "build:stable": "node ../../scripts/build.mjs stable --exportFormat exports", + "build:copy-files": "node ../../scripts/copyFiles.mjs --exportFormat exports", "prebuild": "rimraf build", "release": "pnpm build && pnpm publish", "test": "cd ../../ && cross-env NODE_ENV=test mocha 'packages/mui-styles/**/*.test.{js,ts,tsx}'", diff --git a/packages/mui-system/package.json b/packages/mui-system/package.json index 354ee47336af1f..925313b2b0d08f 100644 --- a/packages/mui-system/package.json +++ b/packages/mui-system/package.json @@ -27,10 +27,10 @@ }, "scripts": { "build": "pnpm build:modern && pnpm build:node && pnpm build:stable && pnpm build:types && pnpm build:copy-files", - "build:modern": "node ../../scripts/build.mjs modern", - "build:node": "node ../../scripts/build.mjs node", - "build:stable": "node ../../scripts/build.mjs stable", - "build:copy-files": "node ../../scripts/copyFiles.mjs", + "build:modern": "node ../../scripts/build.mjs modern --exportFormat exports", + "build:node": "node ../../scripts/build.mjs node --exportFormat exports", + "build:stable": "node ../../scripts/build.mjs stable --exportFormat exports", + "build:copy-files": "node ../../scripts/copyFiles.mjs --exportFormat exports", "build:types": "node ../../scripts/buildTypes.mjs", "prebuild": "rimraf build tsconfig.build.tsbuildinfo", "release": "pnpm build && pnpm publish", diff --git a/packages/mui-types/package.json b/packages/mui-types/package.json index 62ebab324d86e7..acd97fd9fb6a0d 100644 --- a/packages/mui-types/package.json +++ b/packages/mui-types/package.json @@ -49,5 +49,10 @@ "@types/react": { "optional": true } + }, + "exports": { + ".": { + "types": "./index.d.ts" + } } } diff --git a/packages/mui-utils/package.json b/packages/mui-utils/package.json index 495e6726383a4d..67bc4378089d7c 100644 --- a/packages/mui-utils/package.json +++ b/packages/mui-utils/package.json @@ -27,10 +27,10 @@ }, "scripts": { "build": "pnpm build:modern && pnpm build:node && pnpm build:stable && pnpm build:types && pnpm build:copy-files", - "build:modern": "node ../../scripts/build.mjs modern", - "build:node": "node ../../scripts/build.mjs node", - "build:stable": "node ../../scripts/build.mjs stable", - "build:copy-files": "node ../../scripts/copyFiles.mjs", + "build:modern": "node ../../scripts/build.mjs modern --exportFormat exports", + "build:node": "node ../../scripts/build.mjs node --exportFormat exports", + "build:stable": "node ../../scripts/build.mjs stable --exportFormat exports", + "build:copy-files": "node ../../scripts/copyFiles.mjs --exportFormat exports", "build:types": "node ../../scripts/buildTypes.mjs", "prebuild": "rimraf build tsconfig.build.tsbuildinfo", "release": "pnpm build && pnpm publish", diff --git a/packages/mui-utils/src/types/index.ts b/packages/mui-utils/src/types/index.ts new file mode 100644 index 00000000000000..fcb073fefcd6be --- /dev/null +++ b/packages/mui-utils/src/types/index.ts @@ -0,0 +1 @@ +export * from './types'; diff --git a/packages/mui-utils/src/types.ts b/packages/mui-utils/src/types/types.ts similarity index 100% rename from packages/mui-utils/src/types.ts rename to packages/mui-utils/src/types/types.ts diff --git a/scripts/build.mjs b/scripts/build.mjs index 47c7b66ab13378..dcfdd6f69d4735 100644 --- a/scripts/build.mjs +++ b/scripts/build.mjs @@ -17,7 +17,7 @@ const validBundles = [ ]; async function run(argv) { - const { bundle, largeFiles, outDir: relativeOutDir, verbose } = argv; + const { bundle, exportFormat, largeFiles, outDir: relativeOutDir, verbose } = argv; if (validBundles.indexOf(bundle) === -1) { throw new TypeError( @@ -29,6 +29,7 @@ async function run(argv) { NODE_ENV: 'production', BABEL_ENV: bundle, MUI_BUILD_VERBOSE: verbose, + MUI_ADD_IMPORT_EXTENSIONS: exportFormat === 'exports', ...(await getVersionEnvVariables()), }; @@ -84,6 +85,10 @@ async function run(argv) { babelArgs.push('--compact false'); } + if (exportFormat === 'exports' && bundle !== 'node') { + babelArgs.push('--out-file-extension', '.mjs'); + } + const command = ['pnpm babel', ...babelArgs].join(' '); if (verbose) { @@ -112,6 +117,12 @@ yargs(process.argv.slice(2)) description: `Valid bundles: "${validBundles.join('" | "')}"`, type: 'string', }) + .option('exportFormat', { + type: 'string', + options: ['exports', 'legacy'], + default: 'legacy', + describe: 'Set to `exports` to build the package with the `exports` field.', + }) .option('largeFiles', { type: 'boolean', default: false, diff --git a/scripts/copyFiles.mjs b/scripts/copyFiles.mjs index 8ebf82814563b7..3a3b5c6fa28573 100644 --- a/scripts/copyFiles.mjs +++ b/scripts/copyFiles.mjs @@ -1,5 +1,6 @@ /* eslint-disable no-console */ import path from 'path'; +import yargs from 'yargs'; import { createModulePackages, createPackageFile, @@ -12,7 +13,8 @@ const packagePath = process.cwd(); const buildPath = path.join(packagePath, './build'); const srcPath = path.join(packagePath, './src'); -async function addLicense(packageData) { +async function addLicense(packageData, exportFormat = 'legacy') { + const esmExtension = exportFormat === 'exports' ? 'mjs' : 'js'; const license = `/** * ${packageData.name} v${packageData.version} * @@ -22,27 +24,30 @@ async function addLicense(packageData) { */ `; await Promise.all( - ['./index.js', './modern/index.js', './node/index.js'].map(async (file) => { - try { - await prepend(path.resolve(buildPath, file), license); - } catch (err) { - if (err.code === 'ENOENT') { - console.log(`Skipped license for ${file}`); - } else { - throw err; + [`./index.${esmExtension}`, `./modern/index.${esmExtension}`, './node/index.js'].map( + async (file) => { + try { + await prepend(path.resolve(buildPath, file), license); + } catch (err) { + if (err.code === 'ENOENT') { + console.log(`Skipped license for ${file}`); + } else { + throw err; + } } - } - }), + }, + ), ); } -async function run() { - const extraFiles = process.argv.slice(2); +async function run(argv) { + const { extraFiles, exportFormat } = argv; + try { // TypeScript await typescriptCopy({ from: srcPath, to: buildPath }); - const packageData = await createPackageFile(); + const packageData = await createPackageFile(exportFormat); await Promise.all( ['./README.md', '../../CHANGELOG.md', '../../LICENSE', ...extraFiles].map(async (file) => { @@ -51,13 +56,35 @@ async function run() { }), ); - await addLicense(packageData); + await addLicense(packageData, exportFormat); - await createModulePackages({ from: srcPath, to: buildPath }); + // await createModulePackages({ from: srcPath, to: buildPath, exportFormat }); } catch (err) { console.error(err); process.exit(1); } } -run(); +yargs(process.argv.slice(2)) + .command({ + command: '$0 [extraFiles..]', + description: 'copy files', + builder: (command) => { + return command + .positional('extraFiles', { + type: 'array', + default: [], + }) + .option('exportFormat', { + type: 'string', + options: ['exports', 'legacy'], + default: 'legacy', + describe: 'Set to `exports` to build the package with the `exports` field.', + }); + }, + handler: run, + }) + .help() + .strict(true) + .version(false) + .parse(); diff --git a/scripts/copyFilesUtils.mjs b/scripts/copyFilesUtils.mjs index 40b05542614f9e..b74ce6e14e2710 100644 --- a/scripts/copyFilesUtils.mjs +++ b/scripts/copyFilesUtils.mjs @@ -32,7 +32,8 @@ export async function includeFileInBuild(file, target = path.basename(file)) { * @param {string} param0.from * @param {string} param0.to */ -export async function createModulePackages({ from, to }) { +export async function createModulePackages({ from, to, exportFormat = 'legacy' }) { + const esmExtension = exportFormat === 'exports' ? 'mjs' : 'js'; const directoryPackages = glob.sync('*/index.{js,ts,tsx}', { cwd: from }).map(path.dirname); await Promise.all( @@ -45,8 +46,8 @@ export async function createModulePackages({ from, to }) { const packageJson = { sideEffects: false, module: topLevelPathImportsAreCommonJSModules - ? path.posix.join('../esm', directoryPackage, 'index.js') - : './index.js', + ? path.posix.join('../esm', directoryPackage, `index.${esmExtension}`) + : `./index.${esmExtension}`, main: topLevelPathImportsAreCommonJSModules ? './index.js' : path.posix.join('../node', directoryPackage, 'index.js'), @@ -91,7 +92,45 @@ export async function typescriptCopy({ from, to }) { return Promise.all(cmds); } -export async function createPackageFile() { +/** + * Returns the Core exports field. + * @returns {object} + */ +function getCoreExportsField() { + const coreExportsField = {}; + + const hasIndexMjs = fse.existsSync(path.resolve(buildPath, './index.mjs')); + if (hasIndexMjs) { + // Asumes the types file and node build are set up correctly + coreExportsField['.'] = { + types: './index.d.ts', + 'mui-modern': './modern/index.mjs', + import: './index.mjs', + default: './node/index.js', + }; + } + + const hasNestedIndexFiles = glob.sync('*/index.mjs', { cwd: buildPath }).length > 0; + if (hasNestedIndexFiles) { + // Asumes the types files and node build are set up correctly + coreExportsField['./*'] = { + types: './*/index.d.ts', + 'mui-modern': './modern/*/index.mjs', + import: './*/index.mjs', + default: './node/*/index.js', + }; + } + + return coreExportsField; +} + +/** + * Creates a package.json in the build directory. + * @param {boolean} skipExportsField Whether to skip the exports field in the package.json. Only top level ESM packages are supported. + * @returns {Promise} + */ +export async function createPackageFile(exportFormat = 'legacy') { + const esmExtension = exportFormat === 'exports' ? 'mjs' : 'js'; const packageData = await fse.readFile(path.resolve(packagePath, './package.json'), 'utf8'); const { nyc, scripts, devDependencies, workspaces, ...packageDataOther } = JSON.parse(packageData); @@ -104,9 +143,9 @@ export async function createPackageFile() { main: fse.existsSync(path.resolve(buildPath, './node/index.js')) ? './node/index.js' : './index.js', - module: fse.existsSync(path.resolve(buildPath, './esm/index.js')) - ? './esm/index.js' - : './index.js', + module: fse.existsSync(path.resolve(buildPath, `./esm/index.${esmExtension}`)) + ? `./esm/index.${esmExtension}` + : `./index.${esmExtension}`, } : {}), }; @@ -116,6 +155,13 @@ export async function createPackageFile() { newPackageData.types = './index.d.ts'; } + if (exportFormat === 'exports') { + newPackageData.exports = { + ...packageDataOther.exports, + ...getCoreExportsField(), + }; + } + const targetPath = path.resolve(buildPath, './package.json'); await fse.writeFile(targetPath, JSON.stringify(newPackageData, null, 2), 'utf8'); diff --git a/scripts/sizeSnapshot/webpack.config.js b/scripts/sizeSnapshot/webpack.config.js index dd4c5b5b6383de..5fbe0e7cef2cb8 100644 --- a/scripts/sizeSnapshot/webpack.config.js +++ b/scripts/sizeSnapshot/webpack.config.js @@ -8,7 +8,7 @@ const workspaceRoot = path.join(__dirname, '..', '..'); async function getWebpackEntries() { const materialPackagePath = path.join(workspaceRoot, 'packages/mui-material/build'); - const materialComponents = (await glob(path.join(materialPackagePath, '([A-Z])*/index.js'))).map( + const materialComponents = (await glob(path.join(materialPackagePath, '([A-Z])*/index.mjs'))).map( (componentPath) => { const componentName = path.basename(path.dirname(componentPath)); let entryName = componentName; @@ -27,7 +27,7 @@ async function getWebpackEntries() { ); const corePackagePath = path.join(workspaceRoot, 'packages/mui-base/build'); - const coreComponents = (await glob(path.join(corePackagePath, '([A-Z])*/index.js'))).map( + const coreComponents = (await glob(path.join(corePackagePath, '([A-Z])*/index.mjs'))).map( (componentPath) => { const componentName = path.basename(path.dirname(componentPath)); let entryName = componentName; @@ -44,7 +44,7 @@ async function getWebpackEntries() { ); const labPackagePath = path.join(workspaceRoot, 'packages/mui-lab/build'); - const labComponents = (await glob(path.join(labPackagePath, '([A-Z])*/index.js'))).map( + const labComponents = (await glob(path.join(labPackagePath, '([A-Z])*/index.mjs'))).map( (componentPath) => { const componentName = path.basename(path.dirname(componentPath)); @@ -56,7 +56,7 @@ async function getWebpackEntries() { ); const joyPackagePath = path.join(workspaceRoot, 'packages/mui-joy/build'); - const joyComponents = (await glob(path.join(joyPackagePath, '([A-Z])*/index.js'))).map( + const joyComponents = (await glob(path.join(joyPackagePath, '([A-Z])*/index.mjs'))).map( (componentPath) => { const componentName = path.basename(path.dirname(componentPath)); @@ -72,73 +72,73 @@ async function getWebpackEntries() { // WARNING: Changing the name will break tracking of bundle size over time // If the name of the package changes, rename its display name in https://github.com/eps1lon/mui-contributor-dashboard/blob/main/src/pages/SizeComparison.tsx id: '@material-ui/core', - path: path.join(path.relative(workspaceRoot, materialPackagePath), 'index.js'), + path: path.join(path.relative(workspaceRoot, materialPackagePath), 'index.mjs'), }, ...materialComponents, { id: '@material-ui/lab', - path: path.join(path.relative(workspaceRoot, labPackagePath), 'index.js'), + path: path.join(path.relative(workspaceRoot, labPackagePath), 'index.mjs'), }, ...labComponents, { id: '@material-ui/styles', - path: 'packages/mui-styles/build/index.js', + path: 'packages/mui-styles/build/index.mjs', }, { id: '@material-ui/private-theming', - path: 'packages/mui-private-theming/build/index.js', + path: 'packages/mui-private-theming/build/index.mjs', }, { id: '@material-ui/system', - path: 'packages/mui-system/build/index.js', + path: 'packages/mui-system/build/index.mjs', }, { id: 'createBox', - path: 'packages/mui-system/build/createBox/index.js', + path: 'packages/mui-system/build/createBox/index.mjs', }, { id: 'createStyled', - path: 'packages/mui-system/build/createStyled/index.js', + path: 'packages/mui-system/build/createStyled/index.mjs', }, { id: '@material-ui/core/styles/createTheme', - path: 'packages/mui-material/build/styles/createTheme.js', + path: 'packages/mui-material/build/styles/createTheme.mjs', }, { id: 'colorManipulator', - path: 'packages/mui-system/build/colorManipulator/index.js', + path: 'packages/mui-system/build/colorManipulator/index.mjs', }, { id: 'useAutocomplete', - path: 'packages/mui-lab/build/useAutocomplete/index.js', + path: 'packages/mui-lab/build/useAutocomplete/index.mjs', }, { id: '@material-ui/core/useMediaQuery', - path: 'packages/mui-material/build/useMediaQuery/index.js', + path: 'packages/mui-material/build/useMediaQuery/index.mjs', }, { id: '@material-ui/core/useScrollTrigger', - path: 'packages/mui-material/build/useScrollTrigger/index.js', + path: 'packages/mui-material/build/useScrollTrigger/index.mjs', }, { id: '@material-ui/unstyled', - path: path.join(path.relative(workspaceRoot, corePackagePath), 'index.js'), + path: path.join(path.relative(workspaceRoot, corePackagePath), 'index.mjs'), }, ...coreComponents, { id: '@material-ui/utils', - path: 'packages/mui-utils/build/esm/index.js', + path: 'packages/mui-utils/build/index.mjs', }, // TODO: Requires webpack v5 // Resolution of webpack/acorn to 7.x is blocked by nextjs (https://github.com/vercel/next.js/issues/11947) // { // id: '@material-ui/core.modern', // webpack: true, - // path: path.join(path.relative(workspaceRoot, materialPackagePath), 'modern/index.js'), + // path: path.join(path.relative(workspaceRoot, materialPackagePath), 'modern/index.mjs'), // }, { id: '@mui/joy', - path: path.join(path.relative(workspaceRoot, joyPackagePath), 'index.js'), + path: path.join(path.relative(workspaceRoot, joyPackagePath), 'index.mjs'), }, ...joyComponents, ];