|
| 1 | +import { Stability } from '@components/ApiMeta'; |
| 2 | + |
| 3 | +# ESM 格式产物 |
| 4 | + |
| 5 | +Rspack 支持打包 ESM 格式的产物。默认情况下,Rspack 会生成 CommonJS 格式的产物,但你可以通过配置 `output.module` 来生成 ESM 格式的产物。 |
| 6 | + |
| 7 | +这里先列出与 ESM 相关的配置并解释,这在构建应用和库时都需要用到。 |
| 8 | + |
| 9 | +1. [output.module](/config/output#outputmodule): 设置为 `true`,表示生成 ESM 格式的产物,开启时,会 |
| 10 | + 1. 影响 [externalsType](/config/externals#externalstype) 默认值:当 `output.module` 为 `true` 时,`externalsType` 默认为 `'module-import'` |
| 11 | + 2. 影响 [output.filename](/config/output#outputfilename) 默认值:当 `output.module` 为 `true` 时,默认文件名为 `'[name].mjs'` 而不是 `'[name].js'` |
| 12 | + 3. 影响 [output.chunkFilename](/config/output#outputchunkfilename) 默认值:当 `output.module` 为 `true` 时,chunk 文件名默认为 `'[id].mjs'` 而不是 `'[id].js'` |
| 13 | + 4. 影响 [output.hotUpdateChunkFilename](/config/output#outputhotupdatechunkfilename) 默认值:当 `output.module` 为 `true` 时,默认为 `'[id].[fullhash].hot-update.mjs'` |
| 14 | + 5. 影响 [output.hotUpdateMainFilename](/config/output#outputhotupdatemainfilename) 默认值:当 `output.module` 为 `true` 时,默认为 `'[runtime].[fullhash].hot-update.json.mjs'` |
| 15 | + 6. 影响 [output.iife](/config/output#outputiife) 默认值:当 `output.module` 为 `true` 时,`output.iife` 默认为 `false` |
| 16 | + 7. 影响 [output.library.type](/config/output#outputlibrarytype) 默认值:当 `output.module` 为 `true` 时,默认为 `'module'` 而不是 `'var'` |
| 17 | + 8. 影响 [output.scriptType](/config/output#outputscripttype) 默认值:当 `output.module` 为 `true` 时,默认为 `'module'` |
| 18 | + 9. 影响 [output.environment.dynamicImport](/config/output#outputenvironmentdynamicimport) 默认值:当 `output.module` 为 `true` 时会被启用 |
| 19 | + 10. 影响 [output.environment.dynamicImportInWorker](/config/output#outputenvironmentdynamicimportinworker) 默认值:当 `output.module` 为 `true` 时会被启用 |
| 20 | + 11. 影响 [output.environment.module](/config/output#outputenvironmentmodule) 默认值:当 `output.module` 为 `true` 时会被启用 |
| 21 | + 12. 影响 Node.js 相关配置的默认值:在 Node.js 环境下,当 `output.module` 为 `true` 时,`__filename` 和 `__dirname` 默认为 `'node-module'` |
| 22 | +2. [output.chunkFormat](/config/output#outputchunkformat): 设置为 `'module'`,表示使用 ESM 格式。 |
| 23 | +3. [output.library.type](/config/output#outputlibrarytype): 设置为 `'modern-module'`,表示对库的 ESM 产物格式进行了额外的优化。 |
| 24 | +4. [output.chunkLoading](/config/output#outputchunkloading): 设置为 `'import'`,表示使用 ESM 的 `import` 来加载 chunk。 |
| 25 | +5. [output.workerChunkLoading](/config/output#outputworkerchunkloading): 设置为 `'import'`,表示使用 ESM 的 `import` 来加载 worker |
| 26 | +6. [optimization.concatenateModules](/config/optimization#optimizationconcatenatemodules): modern-module 依赖 concatenateModules 的开启来保证输出的产物支持良好的 tree-shaking 及库最终的正确导出 |
| 27 | +7. [optimization.avoidEntryIife](/config/optimization#optimizationavoidentryiife): 在某些情况下,Rspack 会将 ESM 产物的输出包裹在一个 IIFE 中,这将破坏 ESM 的模块化特性 |
| 28 | +8. [experiments.outputModule](/config/experiments#experimentsoutputmodule): 开启 output.module 需要手动开启的前置实验特性 |
| 29 | +9. [HtmlWebpackPlugin.scriptLoading](/guide/tech/html#htmlwebpackplugin): 设置为 `'module'`,表示使用 ESM 的 `<script type="module">` 来加载 `.mjs` 模块。 |
| 30 | + |
| 31 | +## 构建应用的 ESM 格式产物 |
| 32 | + |
| 33 | +在构建应用时,Rspack 会默认生成 CommonJS 格式的产物。如果你需要生成 ESM 格式的产物,可以在 `rspack.config.mjs` 中进行如下配置: |
| 34 | + |
| 35 | +```js title="rspack.config.mjs" |
| 36 | +export default { |
| 37 | + //... |
| 38 | + output: { |
| 39 | + module: true, |
| 40 | + chunkFormat: 'module', |
| 41 | + chunkLoading: 'import', |
| 42 | + workerChunkLoading: 'import', |
| 43 | + }, |
| 44 | + experiments: { |
| 45 | + outputModule: true, |
| 46 | + }, |
| 47 | +}; |
| 48 | +``` |
| 49 | + |
| 50 | +你可以查看 [rspack-examples](https://github.com/rspack-contrib/rstack-examples/tree/main/rspack/react-refresh-esm) 中这个使用 React 应用构建到 ESM 产物的例子。 |
| 51 | + |
| 52 | +## 构建库的 ESM 格式产物 |
| 53 | + |
| 54 | +推荐使用 [Rslib](https://rslib.rs) 来构建库产物,Rslib 底层的实现基于 Rspack,能够构建 ES Module、CommonJS 和 UMD 等多种格式的产物。Rslib 提供了更高层次的 API,简化了库的构建过程。使用 Rslib 进行库的构建会比直接使用 Rspack 更加方便和高效。 |
| 55 | + |
| 56 | +当直接使用 Rspack 支持构建库(npm library)的 ESM 格式产物时,需要同时进行以下配置: |
| 57 | + |
| 58 | +```js title="rspack.config.mjs" |
| 59 | +export default { |
| 60 | + //... |
| 61 | + output: { |
| 62 | + module: true, |
| 63 | + chunkFormat: 'module', |
| 64 | + externalsType: "module-import", |
| 65 | + library: { |
| 66 | + type: 'modern-module', |
| 67 | + } |
| 68 | + chunkLoading: 'import', |
| 69 | + workerChunkLoading: 'import', |
| 70 | + }, |
| 71 | + optimization: { |
| 72 | + concatenateModules: true, |
| 73 | + avoidEntryIife: true, |
| 74 | + minimize: false, // 在构建库时禁用代码压缩 |
| 75 | + }, |
| 76 | + experiments: { |
| 77 | + outputModule: true, |
| 78 | + }, |
| 79 | +}; |
| 80 | +``` |
| 81 | + |
| 82 | +你可以查看 [rspack-examples](https://github.com/rspack-contrib/rstack-examples/tree/main/rspack/library-esm) 中这个使用 ESM 库的例子。 |
| 83 | + |
| 84 | +要进行 ESM 产物的打包还需要处理各种细节问题,这里不再一一列举,可以参考 [Rslib 中对 ESM 格式的相关配置](https://github.com/web-infra-dev/rslib/blob/f727b18805767b99fb85ae67ebff959aa644536e/packages/core/src/config.ts),或者直接使用 Rslib 开箱即用进行库的构建。 |
| 85 | + |
| 86 | +## ESM 产物未来规划 |
| 87 | + |
| 88 | +现在 Rspack 对 ESM 的支持还很基本,ESM 的产物还没有达到能够完全替代当前的 CommonJS 产物的程度,在很多场景下 ESM 产物也无法正常工作。包括: |
| 89 | + |
| 90 | +1. 没有对静态分析友好的代码分割支持 |
| 91 | +2. 缺少模块级别的副作用信息保留,影响 tree-shaking 的精确性 |
| 92 | +3. 缺少对 ESM 产物的 Live Bindings 支持,无法正确处理导出绑定的动态更新 |
| 93 | +4. 循环依赖处理在 ESM 产物中存在问题 |
| 94 | +5. 外部模块的重新导出(`export * from '...'`)在 ESM 格式下无法正确保留 |
| 95 | + |
| 96 | +Rspack 未来会继续完善对 ESM 的支持,目标是将 ESM 产物视为一等公民,使 ESM 的使用及配置更加简单和直观,更好地拥抱现代 JavaScript 模块系统。 |
0 commit comments