From 8c97451e77344738d2203779f9b0b4c6d5c79c5e Mon Sep 17 00:00:00 2001 From: Timeless0911 <1604889533@qq.com> Date: Thu, 5 Dec 2024 16:33:28 +0800 Subject: [PATCH] docs: translate some basic and adbanced docs --- .../guide/advanced/output-compatibility.mdx | 4 +- .../en/guide/advanced/third-party-deps.mdx | 11 +- website/docs/en/guide/basic/output-format.mdx | 32 ++--- .../docs/en/guide/basic/output-structure.mdx | 4 +- website/docs/en/guide/basic/typescript.mdx | 4 +- website/docs/en/guide/basic/upgrade-rslib.mdx | 6 +- .../guide/advanced/output-compatibility.mdx | 106 ++++++++++++++ .../zh/guide/advanced/third-party-deps.mdx | 81 +++++++++++ website/docs/zh/guide/basic/output-format.mdx | 130 ++++++++++++++++++ .../docs/zh/guide/basic/output-structure.mdx | 21 +++ website/docs/zh/guide/basic/typescript.mdx | 45 ++++++ website/docs/zh/guide/basic/upgrade-rslib.mdx | 71 ++++++++++ .../docs/zh/guide/start/components/CJS.mdx | 2 +- .../docs/zh/guide/start/components/ESM.mdx | 2 +- website/docs/zh/guide/start/components/MF.mdx | 4 +- .../docs/zh/guide/start/components/UMD.mdx | 2 +- 16 files changed, 488 insertions(+), 37 deletions(-) diff --git a/website/docs/en/guide/advanced/output-compatibility.mdx b/website/docs/en/guide/advanced/output-compatibility.mdx index da92f9213..f1f777acc 100644 --- a/website/docs/en/guide/advanced/output-compatibility.mdx +++ b/website/docs/en/guide/advanced/output-compatibility.mdx @@ -33,7 +33,7 @@ And install [core-js-pure](https://www.npmjs.com/package/core-js-pure) as the ru -Configure the Babel plugin with polyfill options, set the [target](https://babeljs.io/docs/options#targets) field to specify the target browser version. +Configure the Babel plugin with polyfill options, set the [targets](https://babeljs.io/docs/options#targets) field to specify the target browser version. ```ts title="rslib.config.ts" {1,11-24} import { pluginBabel } from '@rsbuild/plugin-babel'; @@ -97,7 +97,7 @@ export default defineConfig({ #### Configurations - For projects with `bundle` enabled, the Node Polyfill will be injected and included in the output. -- For projects with `bundle` disabled, polyfills are not injected into the output by default. To avoid inlining the polyfill in every module. The modules are externalized and need to be added to dependencies manually, follow these steps: +- For projects with `bundle` disabled, polyfills are not injected into the output by default. To avoid inlining the polyfill in every module, the modules are externalized and need to be added to dependencies manually, follow these steps: 1. Configure `output.external` with `resolvedPolyfillToModules`, which you can import from [@rsbuild/plugin-node-polyfill](https://github.com/rspack-contrib/rsbuild-plugin-node-polyfill). This will externalize the polyfill modules to the installed polyfill dependencies. 2. Install used polyfill modules as dependencies. diff --git a/website/docs/en/guide/advanced/third-party-deps.mdx b/website/docs/en/guide/advanced/third-party-deps.mdx index 82af2795e..6773c439c 100644 --- a/website/docs/en/guide/advanced/third-party-deps.mdx +++ b/website/docs/en/guide/advanced/third-party-deps.mdx @@ -9,17 +9,17 @@ Generally, third-party dependencies required by a project can be installed via t } ``` -Dependencies under `"dependencies"` are generally related to project code and builds, and if these third-party dependencies are declared under `"devDependencies"`, then there will be missing dependencies in production runtime. +Dependencies under `"dependencies"` are generally required for the package in runtime, and if these third-party dependencies are declared under `"devDependencies"`, then there will be missing dependencies in production runtime. In addition to `"dependencies"`, `"peerDependencies"`can also declare dependencies that are needed in the production environment, but it puts more emphasis on the existence of these dependencies declared by `"peerDependencies"` in the project's runtime environment, similar to the plugin mechanism. ## Default handling of third-party dependencies -By default, **third-party dependencies under `"dependencies"`, `"optionalDependencies"` and `"peerDependencies"` are not bundled by Rslib**. +By default, third-party dependencies under `"dependencies"`, `"optionalDependencies"` and `"peerDependencies"` are not bundled by Rslib. This is because when the npm package is installed, its `"dependencies"` will also be installed. By not packaging `"dependencies"`, you can reduce the size of the package product. -If you need to package some dependencies, it is recommended to move them from `"dependencies"` to `"devDependencies"`, which is equivalent to **prebundle** the dependencies and reduces the size of the dependency installation. +If you need to package some dependencies, it is recommended to move them from `"dependencies"` to `"devDependencies"`, which is equivalent to prebundle the dependencies and reduces the size of the dependency installation. ### Example @@ -51,13 +51,14 @@ import * as __WEBPACK_EXTERNAL_MODULE_react__ from 'react'; console.info(__WEBPACK_EXTERNAL_MODULE_react__['default']); ``` -If you want to modify the default processing, you can use the following API. +If you want to modify the default processing, you can use the following API: - [lib.autoExternal](/config/lib/auto-external) +- [output.externals](/config/rsbuild/output#outputexternals) ## Exclude specified third-party dependencies -We previously introduced the use of [`lib.autoExternal`](/config/lib/auto-external). This configuration lets you manage third-party dependencies more precisely. +The configuration described above allows you to implement more fine-grained handling of third-party dependencies. For example, when we need to leave only certain dependencies unbundled, we can configure it as follows. diff --git a/website/docs/en/guide/basic/output-format.mdx b/website/docs/en/guide/basic/output-format.mdx index 33d330467..941d0fcc1 100644 --- a/website/docs/en/guide/basic/output-format.mdx +++ b/website/docs/en/guide/basic/output-format.mdx @@ -5,7 +5,7 @@ import MF from '../start/components/MF.mdx'; # Output Format -This sets the output format for the generated JavaScript files. There are three supported values now: `esm`, `cjs`, and `umd`. In this guide, we will discuss the differences between these formats and how to choose the right one for your library. +There are four supported output formats for the generated JavaScript files in Rslib: `esm`, `cjs`, `umd`, and `mf`. In this chapter, we will introduce the differences between these formats and how to choose the right one for your library. ## ESM / CJS @@ -13,19 +13,17 @@ Library authors need to carefully consider which module formats to support. Let' ### What are ESM and CJS? - - - **ESM**: ESM is - **CommonJS**: [CommonJS](https://nodejs.org/api/modules.html#modules-commonjs-modules) is -### What is the dilemma of esm / cjs +### What is the dilemma of ESM / CJS > The following references are from [Node Modules at War: Why CommonJS and ES Modules Can't Get Along](https://redfin.engineering/node-modules-at-war-why-commonjs-and-es-modules-cant-get-along-9617135eeca1). 1. You can't `require()` ESM scripts; you can only import ESM scripts, like this: `import {foo} from 'foo'` 2. CJS scripts can't use static `import` statements like the one above. -3. ESM scripts can `import` CJS scripts, but only by using the “default import” syntax `import _ from 'lodash'`, not the “named import” syntax `import {shuffle} from 'lodash'`, which is a hassle if the CJS script uses named exports. (Except, sometimes, unpredictibly, Node can figure out what you meant!) +3. ESM scripts can `import` CJS scripts, but only by using the **default import** syntax `import _ from 'lodash'`, not the **named import** syntax `import {shuffle} from 'lodash'`, which is a hassle if the CJS script uses named exports. (Except, sometimes, unpredictibly, Node can figure out what you meant!) 4. ESM scripts can `require()` CJS scripts, even with named exports, but it's typically not worth the trouble, because it requires even more boilerplate, and, worst of all, bundlers like Webpack and Rollup don't/won't know how to work with ESM scripts that use `require()`. 5. CJS is the default; you have to opt-in to ESM mode. You can opt-in to ESM mode by renaming your script from `.js` to `.mjs`. Alternately, you can set `"type": "module"` in `package.json`, and then you can opt-out of ESM by renaming scripts from `.js` to `.cjs`. (You can even tweak just an individual subdirectory by putting a one-line `{"type": "module"}` `package.json` file in there.) @@ -33,7 +31,7 @@ Library authors need to carefully consider which module formats to support. Let' For different shapes of libraries, the choice of module format may vary. Here are two common scenarios: -#### ship [pure ESM](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c) package. +#### ship [pure ESM](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c) package shipping only ESM is the best choice for libraries that are intended to be used in modern environments, such as browser applications or Node.js applications that support ESM. However, if the upstream library is in format of CJS, they only can import pure ESM by using dynamic import like `const pureEsmLib = await import('pure-esm-lib')`. @@ -47,7 +45,7 @@ shipping only ESM is the best choice for libraries that are intended to be used - Some Node.js tools and libraries still have limited or incomplete support for ESM, requiring workarounds or additional configuration. - You must explicitly include file extensions in import paths, which can be cumbersome, especially when working with TypeScript or other transpiled languages. -#### ship [ESM & CJS (dual)](https://antfu.me/posts/publish-esm-and-cjs#compatibility) package. +#### ship [ESM & CJS (dual)](https://antfu.me/posts/publish-esm-and-cjs#compatibility) package The community is migrating to ESM, but there are still many projects using CJS. If you want to support both ESM and CJS, you can publish a dual package. For most library authors, offering dual formats is a safer and smoother way to access the best of both worlds. You could read antfu' blog post [Publish ESM and CJS packages](https://antfu.me/posts/publish-esm-and-cjs) for more details. @@ -60,8 +58,8 @@ The community is migrating to ESM, but there are still many projects using CJS. - **Cons:** - - Increased complexity: Maintaining two module formats adds complexity to the build process, requiring additional configuration and testing to ensure both versions work correctly14. - - Dual package hazard: Mixing ESM and CJS can lead to issues such as broken instanceof checks or unexpected behavior when dependencies are loaded in different formats13. + - Increased complexity: Maintaining two module formats adds complexity to the build process, requiring additional configuration and testing to ensure both versions work correctly. + - Dual package hazard: Mixing ESM and CJS can lead to issues such as broken instanceof checks or unexpected behavior when dependencies are loaded in different formats. ## UMD @@ -78,17 +76,17 @@ A detailed answer from StackOverflow: [What is the Universal Module Definition ( > However, for frontend libraries, you still offer a single file for convenience, that users can download (from a CDN) and directly embed in their web pages. This still commonly employs a UMD pattern, it's just no longer written/copied by the library author into their source code, but added automatically by the transpiler/bundler. > > And similarly, for backend/universal libraries that are supposed to work in -> node.js, you still also distribute a commonjs module build via npm to support -> all the users who still use a legacy version of node.js (and don't want/need +> Node.js, you still also distribute a commonjs module build via npm to support +> all the users who still use a legacy version of Node.js (and don't want/need > to employ a transpiler themselves). This is less common nowadays for new > libraries, but existing ones try hard to stay backwards-compatible and not > cause applications to break. ### How to build a UMD library? -- Set the `lib.format` to `umd` in the Rslib configuration file. -- If the library need to be exported with a name, set `lib.umdName` to the name of the UMD library. -- Use `output.externals` to specify the external dependencies that the UMD library depends on, `lib.autoExtension` is enabled by default for UMD. +- Set the [lib.format](/config/lib/format) to `umd` in the Rslib configuration file. +- If the library need to be exported with a name, set [lib.umdName](/config/lib/umd-name) to the name of the UMD library. +- Use [output.externals](/config/rsbuild/output#outputexternals) to specify the external dependencies that the UMD library depends on, [lib.autoExtension](/config/lib/auto-extension) is enabled by default for UMD. ### Examples @@ -136,9 +134,3 @@ export default defineConfig({ ### What is MF? MF stands for Module Federation. - -### When to use MF? - -### How to build a MF library? - -Check out [Advanced - Module Federation](/guide/advanced/module-federation) chapter for more details. diff --git a/website/docs/en/guide/basic/output-structure.mdx b/website/docs/en/guide/basic/output-structure.mdx index 7627a9a91..b8a2e41e4 100644 --- a/website/docs/en/guide/basic/output-structure.mdx +++ b/website/docs/en/guide/basic/output-structure.mdx @@ -6,7 +6,7 @@ So first let's understand bundle and bundleless. A bundle is a package of build artifacts, which may be a single file or multiple files based on a certain [code splitting strategy](https://esbuild.github.io/api/#splitting). -bundleless, on the other hand, means that each source file is compiled and built separately, but not bundled together. Each output file can be found with its corresponding source code file. The process of **bundleless build can also be understood as the process of code conversion of source files only**. +bundleless, on the other hand, means that each source file is compiled and built separately, but not bundled together. Each output file can be found with its corresponding source code file. The process of bundleless build can also be understood as the process of code conversion of source files only. They have their own benefits. @@ -14,7 +14,9 @@ They have their own benefits. - bundleless maintains the original file structure and is more conducive to debugging and tree shaking. :::warning + bundleless is a single-file compilation mode, so for referencing and exporting types, you need to add the `type` keyword. For example, `import type { A } from './types'`. Please refer to [TypeScript - isolatedModules](/guide/basic/typescript#isolatedmodules) for more information. + ::: You can specify whether to bundle using the [bundle](/config/lib/bundle) option, which is set to `true` by default. diff --git a/website/docs/en/guide/basic/typescript.mdx b/website/docs/en/guide/basic/typescript.mdx index c59369d51..7beead194 100644 --- a/website/docs/en/guide/basic/typescript.mdx +++ b/website/docs/en/guide/basic/typescript.mdx @@ -32,9 +32,9 @@ export type { SomeType } from './types'; ## tsconfig.json Path -Rslib by default reads the `tsconfig.json` file from the root directory. You can use [source.tsconfigPath](https://rsbuild.dev/config/source/tsconfig-path) to configure a custom tsconfig.json file path. +Rslib by default reads the `tsconfig.json` file from the root directory. You can use [source.tsconfigPath](/config/rsbuild/source#sourcetsconfigpath) to configure a custom `tsconfig.json` file path. -```ts +```ts title="rslib.config.ts" export default { lib: [ // ... diff --git a/website/docs/en/guide/basic/upgrade-rslib.mdx b/website/docs/en/guide/basic/upgrade-rslib.mdx index af779e7c3..b9c4e3f0f 100644 --- a/website/docs/en/guide/basic/upgrade-rslib.mdx +++ b/website/docs/en/guide/basic/upgrade-rslib.mdx @@ -6,7 +6,9 @@ This section explains how to upgrade the project's Rslib dependencies to the lat {/* > Please see [Releases](/community/releases/index) to understand the Rsbuild release strategy. */} :::info -Rslib is still in the early stages of development, and the API may change frequently. We recommend upgrading to the latest version to access new features and bug fixes. We plan to release version 0.1.0 in the fourth quarter of 2024. + +Rslib is still in 0.x version stage, and the API may change frequently. We recommend upgrading to the latest version to access new features and bug fixes. + ::: ## Using Taze @@ -22,7 +24,7 @@ npx taze major --include "/(rsbuild|rslib)/" -w ``` :::tip -Rslib has not yet reached version 0.1.0, so you need to add the `major` parameter when updating. +Rslib has not yet reached version 1.0.0, so you need to add the `major` parameter when updating. ::: The result will look similar to: diff --git a/website/docs/zh/guide/advanced/output-compatibility.mdx b/website/docs/zh/guide/advanced/output-compatibility.mdx index 6d5ceba8f..9d5b7e4d2 100644 --- a/website/docs/zh/guide/advanced/output-compatibility.mdx +++ b/website/docs/zh/guide/advanced/output-compatibility.mdx @@ -1 +1,107 @@ +import { Steps, SourceCode } from '@theme'; +import { PackageManagerTabs } from '@theme'; + # 产物兼容性 + +本节介绍如何指定支持的目标环境。 + +## 语法降级 + +通过设置 [lib.syntax](/config/lib/syntax),你可以选择 JavaScript 和 CSS 将被降级到的语法。你可以使用 [Browserslist](https://browsersl.ist/) 的查询语法。Rslib 还支持常见的 ECMAScript 版本号,例如 `ES2015`。 + +Rslib 还支持使用 [.browserslistrc](https://github.com/browserslist/browserslist#config-file) 文件来设置。需要注意的是,[lib.syntax](/config/lib/syntax) 优先于 `.browserslistrc`。如果两者都存在,将使用 `lib.syntax`。 + +默认情况下,syntax 被设置为 `ESNext`,这代表将仅支持主流浏览器(Chrome / Firefox / Edge / macOS Safari / iOS Safari)或 Node.js 的最新版本,具体取决于 [output.target](/config/rsbuild/output#outputtarget)。 + +## Polyfill + +在处理兼容性问题之前,建议了解以下背景知识,以便更好地处理相关问题。请查看有关[语法降级和 API 降级](https://rsbuild.dev/zh/guide/advanced/browser-compatibility#%E8%AF%AD%E6%B3%95%E9%99%8D%E7%BA%A7%E5%92%8C-api-%E9%99%8D%E7%BA%A7)的背景知识。 + +### 浏览器 + +通常,我们不需要为 npm 包注入 polyfill,这个步骤应该在 web 应用框架侧完成,但在某些场景下,我们需要注入 polyfill 以使我们的库直接在低版本浏览器中运行。 + +需要注意的是,这个插件不会转换你的代码语法,它只会为代码中使用的未支持函数注入 polyfill,将它们作为普通函数导入,而不是污染全局。你需要安装 [core-js-pure](https://www.npmjs.com/package/core-js-pure) 依赖。 + +#### 设置 + +polyfill 依赖于 Babel 注入 polyfill 代码,因此你需要安装 [Rsbuild Babel 插件](https://rsbuild.dev/zh/plugins/list/plugin-babel) 和 [babel-plugin-polyfill-corejs3](https://www.npmjs.com/package/babel-plugin-polyfill-corejs3) 来注入 polyfill 代码。 + + + +并安装 [core-js-pure](https://www.npmjs.com/package/core-js-pure) 作为运行时依赖代码。 + + + +配置 Babel 插件,设置 [targets](https://babeljs.io/docs/options#targets) 字段以指定目标浏览器版本。 + +```ts title="rslib.config.ts" {1,11-24} +import { pluginBabel } from '@rsbuild/plugin-babel'; +import { defineConfig } from '@rslib/core'; + +export default defineConfig({ + lib: [ + { + format: 'esm', + }, + ], + plugins: [ + pluginBabel({ + babelLoaderOptions: { + plugins: [ + [ + require('babel-plugin-polyfill-corejs3'), + { + method: 'usage-pure', + targets: { ie: '10' }, + version: '3.29', + }, + ], + ], + }, + }), + ], +}); +``` + +#### 配置 + +更多详细信息,请查看 [babel-plugin-polyfill-corejs3](https://www.npmjs.com/package/babel-plugin-polyfill-corejs3) 文档。 + +### Node.js + +:::tip 关于 Node Polyfill +通常,我们不需要在浏览器侧使用 Node 库。然而,在某些情况下,代码将在 Node 侧和浏览器侧运行,Node Polyfill 提供了这些 Node 库的浏览器版本 polyfill。 +::: + +通过使用 [@rsbuild/plugin-node-polyfill](https://github.com/rspack-contrib/rsbuild-plugin-node-polyfill),Node 核心库的 polyfill 会自动注入到浏览器侧,允许你在浏览器侧使用这些模块。 + +#### 设置 + +Rslib 使用 [@rsbuild/plugin-node-polyfill](https://github.com/rspack-contrib/rsbuild-plugin-node-polyfill) 提供 Node Polyfill 功能。 + + + +然后将其添加到插件字段中。 + +```ts title="rslib.config.ts" +import { defineConfig } from '@rslib/core'; +import { pluginNodePolyfill } from '@rsbuild/plugin-node-polyfill'; + +export default defineConfig({ + lib: [{ format: 'esm' }], + plugins: [pluginNodePolyfill()], +}); +``` + +#### 配置 + +- 对于启用了 `bundle` 的项目,Node Polyfill 将被注入并包含在输出中。 +- 对于未启用 `bundle` 的项目,默认情况下不会注入 polyfill。为了避免在每个模块中内联 polyfill,模块需要被 external,并手动添加到依赖中,请按照以下步骤操作: + + 1. 配置 `output.external` 和 `resolvedPolyfillToModules`,你可以从 [@rsbuild/plugin-node-polyfill](https://github.com/rspack-contrib/rsbuild-plugin-node-polyfill) 导入。这将 polyfill 模块 external 到已安装的 polyfill 依赖中。 + 2. 安装使用的 polyfill 模块作为依赖。 + + 通过以下步骤,每个 polyfill 模块的使用将被替换为 `externals` 字段中的相应模块。更多详细信息,请查看 的示例。 + +更多详细信息,请查看 [@rsbuild/plugin-node-polyfill](https://github.com/rspack-contrib/rsbuild-plugin-node-polyfill) 文档,所有配置均适用于 Rslib。 diff --git a/website/docs/zh/guide/advanced/third-party-deps.mdx b/website/docs/zh/guide/advanced/third-party-deps.mdx index eadfe73a6..ff74ceeb0 100644 --- a/website/docs/zh/guide/advanced/third-party-deps.mdx +++ b/website/docs/zh/guide/advanced/third-party-deps.mdx @@ -1 +1,82 @@ # 处理三方依赖 + +通常,项目所需的三方依赖可以通过包管理器的 `install` 命令安装。安装成功后,它们通常会出现在项目的 `package.json` 文件中的 `dependencies` 和 `devDependencies` 字段下。 + +```json title="package.json" +{ + "dependencies": {}, + "devDependencies": {} +} +``` + +`dependencies` 字段下的依赖通常来说是这个包运行所需的依赖,如果这些三方依赖声明在 `devDependencies` 字段下,那么在生产运行时会出现缺失依赖。 + +除了 `dependencies` 字段,`peerDependencies` 也可以声明在生产环境中需要的依赖,但它更强调这些依赖在项目运行时的存在,类似于插件机制。 + +## 三方依赖的默认处理 + +默认情况下,`dependencies`、`optionalDependencies` 和 `peerDependencies` 字段下的三方依赖不会被 Rslib 打包。 + +这是因为在 npm 包安装时,其 `dependencies` 也会被安装。通过不打包 `dependencies`,可以减少包的体积。 + +如果需要打包某些依赖,建议将它们从 `dependencies` 移动到 `devDependencies`,这相当于预打包依赖,并减少依赖安装的体积。 + +### 示例 + +如果项目依赖了 `react`。 + +```json title="package.json" +{ + "dependencies": { + "react": "^18" + }, + // 或 + "peerDependencies": { + "react": "^18" + } +} +``` + +当在源代码中使用 `react` 依赖时: + +```tsx title="src/index.ts" +import React from 'react'; +console.info(React); +``` + +此时产物中不会包含 `react` 的代码: + +```js title="dist/index.js" +import * as __WEBPACK_EXTERNAL_MODULE_react__ from 'react'; +console.info(__WEBPACK_EXTERNAL_MODULE_react__['default']); +``` + +如果想要修改默认的处理方式,可以通过下面的 API 进行修改: + +- [lib.autoExternal](/config/lib/auto-external) +- [output.externals](/config/rsbuild/output#outputexternals) + +## 排除指定三方依赖 + +上面介绍的配置可以让你实现对三方依赖更细微的处理。 + +例如当我们需要仅对某些依赖不进行打包处理的时候,可以按照如下方式进行配置: + +:::tip +在这种情况下,某些依赖可能不适合打包。如果遇到这种情况,则可以按照下面的方式进行处理。 +::: + +```ts +export default defineConfig({ + lib: [ + { + // ... + autoExternal: true, + output: { + externals: ['pkg-1', /pkg-2/], + }, + // ... + }, + ], +}); +``` diff --git a/website/docs/zh/guide/basic/output-format.mdx b/website/docs/zh/guide/basic/output-format.mdx index 6ac089a5e..3a26f739e 100644 --- a/website/docs/zh/guide/basic/output-format.mdx +++ b/website/docs/zh/guide/basic/output-format.mdx @@ -1 +1,131 @@ +import ESM from '../start/components/ESM.mdx'; +import CJS from '../start/components/CJS.mdx'; +import UMD from '../start/components/UMD.mdx'; +import MF from '../start/components/MF.mdx'; + # 产物输出格式 + +Rslib 支持四种 JavaScript 文件的输出格式:`esm`、`cjs`、`umd` 和 `mf`。在本章中,我们将介绍这些格式之间的区别以及如何为你的库选择合适的格式。 + +## ESM / CJS + +库作者需要仔细考虑支持哪种模块格式。让我们了解一下 ESM (ECMAScript Modules) 和 CJS (CommonJS),以及何时使用它们。 + +### 什么是 ESM 和 CJS? + +- **ESM**: ESM 是 + +- **CommonJS**: [CommonJS](https://nodejs.org/api/modules.html#modules-commonjs-modules) 是 + +### ESM 和 CJS 的困境 + +> 以下参考自 [Node 模块之战:为什么 CommonJS 和 ES Modules 无法共存](https://redfin.engineering/node-modules-at-war-why-commonjs-and-es-modules-cant-get-along-9617135eeca1)。 + +1. 你不能 `require()` ESM 脚本;你只能导入 ESM 脚本,像这样:`import {foo} from 'foo'` +2. CJS 脚本不能使用静态 `import` 语句,如上所示。 +3. ESM 脚本可以 `import` CJS 脚本,但只能使用**默认导入**语法 `import _ from 'lodash'`,而不能使用**命名导入**语法 `import {shuffle} from 'lodash'`,如果 CJS 脚本使用命名导出,这会很麻烦。(不过,有时 Node 会不可预料 地猜出你的意思!) +4. ESM 脚本可以 `require()` CJS 脚本,即使是命名导出,但通常不值得这样做,因为这需要更多的模板代码,而且最糟糕的是,像 webpack 和 Rollup 这样的打包工具不知道/不会处理使用 `require()` 的 ESM 脚本。 +5. CJS 是默认的;你需要选择加入 ESM 模式。你可以通过将脚本从 `.js` 重命名为 `.mjs` 来选择性开启 ESM 模式。或者,你可以在 `package.json` 中设置 `"type": "module"`,然后通过将脚本从 `.js` 重命名为 `.cjs` 来选择性关闭 ESM。(你甚至可以通过在单个子目录中放置一行 `{"type": "module"}` `package.json` 来调整它。) + +### 何时支持哪种格式? + +对于不同类型的库,模块格式的选择可能会有所不同。以下是两种常见的情况: + +#### 发布纯 ESM 库 + +发布纯 ESM 库是现代环境库的最佳选择,例如浏览器应用程序或支持 ESM 的 Node.js 应用程序。然而,如果上游库是 CJS 格式,它们只能通过动态导入使用纯 ESM 库,例如 `const pureEsmLib = await import('pure-esm-lib')`。 + +- **优点:** + - ESM 是官方的 JavaScript 标准,使其更具前瞻性和跨环境支持。 + - ESM 支持静态分析,这有助于摇树优化移除未使用的代码。 + - 语法更简洁直观,与 CommonJS 相比,import 和 export 语句更容易阅读。 + - ESM 允许在浏览器和 Node.js 环境中更好地兼容,使其成为同构或通用 JavaScript 应用程序的理想选择。 +- **缺点:** + - ESM 模块是异步加载的,这在某些情况下可能会使条件引入和懒加载变得复杂。 + - 一些 Node.js 工具和库仍然对 ESM 有限制或不支持,需要解决方法或额外配置。 + - 你必须在导入路径中显式包含文件扩展名,这可能会很麻烦,尤其是在使用 TypeScript 或其他转译语言时。 + +#### 发布 [ESM 和 CJS(双重)](https://antfu.me/posts/publish-esm-and-cjs#compatibility) 包 + +社区正在向 ESM 迁移,但仍有许多项目在使用 CJS。如果你想同时支持 ESM 和 CJS,可以发布一个双重包。对于大多数库作者来说,提供双重格式是一种更安全、更平滑的方式,可以同时享受两种格式的优点。你可以阅读 antfu 的博客文章 [在一个包中发布 ESM 和 CJS](https://antfu.me/posts/publish-esm-and-cjs) 了解更多详情。 + +- **优点:** + + - 更广泛的兼容性:双重包支持现代 ESM 环境和旧版 CJS 环境,确保在不同生态系统中更广泛的使用。 + - 渐进式迁移:开发者可以逐步从 CJS 迁移到 ESM,而无需破坏现有项目,从而更平滑地采用新标准。 + - 灵活性:用户可以根据自己的项目选择最适合的模块系统,在不同的构建工具和环境中提供灵活性。 + - 跨运行时支持:双重包可以在多个运行时中工作,例如 Node.js 和浏览器,而无需额外的打包或转译。 + +- **缺点:** + + - 增加复杂性:维护两种模块格式会增加构建过程的复杂性,需要额外的配置和测试,以确保两种版本都能正常工作。 + - 双重包风险:混合 ESM 和 CJS 可能会导致实例检查失败或依赖项在不同格式中加载时出现意外行为。 + +## UMD + +### 什么是 UMD? + + + +### 何时使用 UMD? + +如果你正在构建一个需要在浏览器和 Node.js 环境中使用的库,UMD 是一个不错的选择。UMD 可以作为独立的脚本标签在浏览器中使用,也可以作为 CommonJS 模块在 Node.js 中使用。 + +StackOverflow 上的详细回答:[什么是通用模块定义 (UMD)?](https://stackoverflow.com/a/77284527/8063488) + +> 然而,对于前端库,你仍然可以提供一个单一文件,方便用户从 CDN 下载并直接嵌入到他们的网页中。这通常仍然采用 UMD 模式,只是现在不再由库作者手动编写/复制到源代码中,而是由转译器/打包器自动添加。 +> +> 同样地,对于需要在 Node.js 中运行的后端/通用库,你仍然可以通过 npm 分发一个 CommonJS 模块构建,以支持所有仍在使用旧版 Node.js 的用户(他们不想/不需要自己使用转译器)。这在新库中不太常见,但现有库会尽力保持向后兼容,不会导致应用程序被破坏。 + +### 如何构建 UMD 库? + +- 在 Rslib 配置文件中将 [lib.format](/config/lib/format) 设置为 `umd`。 +- 如果库需要导出名称,请将 [lib.umdName](/config/lib/umd-name) 设置为 UMD 库的名称。 +- 使用 [output.externals](/config/rsbuild/output#outputexternals) 指定 UMD 库依赖的外部依赖,UMD 的 [lib.autoExtension](/config/lib/auto-extension) 配置默认启用。 + +### 示例 + +以下是一个构建 UMD 库的 Rslib 配置示例。 + +- `lib.format: 'umd'`: 配置 Rslib 构建 UMD 库。 +- `lib.umdName: 'RslibUmdExample'`: 设置 UMD 库的导出名称。 +- `output.externals.react: 'React'`: 指定外部依赖 `react` 可以通过 `window.React` 访问。 +- `runtime: 'classic'`: 使用 React 的 classic 运行时,以支持使用 React 版本低于 18 的应用程序。 + +```ts title="rslib.config.ts" {7-12,22} +import { pluginReact } from '@rsbuild/plugin-react'; +import { defineConfig } from '@rslib/core'; + +export default defineConfig({ + lib: [ + { + format: 'umd', + umdName: 'RslibUmdExample', + output: { + externals: { + react: 'React', + }, + distPath: { + root: './dist/umd', + }, + }, + }, + ], + output: { + target: 'web', + }, + plugins: [ + pluginReact({ + swcReactOptions: { + runtime: 'classic', + }, + }), + ], +}); +``` + +## MF + +### 什么是 MF? + +MF 代表 Module Federation。 diff --git a/website/docs/zh/guide/basic/output-structure.mdx b/website/docs/zh/guide/basic/output-structure.mdx index c18a7339e..40ef06644 100644 --- a/website/docs/zh/guide/basic/output-structure.mdx +++ b/website/docs/zh/guide/basic/output-structure.mdx @@ -1 +1,22 @@ # 产物结构 + +## bundle / bundleless + +首先让我们了解一下 bundle 和 bundleless。 + +所谓 bundle 是指对构建产物进行打包,构建产物可能是一个文件,也有可能是基于一定的[代码拆分策略](https://esbuild.github.io/api/#splitting)得到的多个文件。 + +而 bundleless,则是指对每个源文件单独进行编译构建,但是并不将它们打包在一起。每一个产物文件都可以找到与之相对应的源码文件。bundleless 构建的过程,也可以理解为仅对源文件进行代码转换的过程。 + +它们有各自的好处: + +- bundle 可以减少构建产物的体积,也可以对依赖预打包,减小安装依赖的体积。提前对库进行打包,可以加快应用项目构建的速度。 +- bundleless 则是可以保持原有的文件结构,更有利于调试和 tree shaking。 + +:::warning + +bundleless 是单文件编译模式,因此对于类型的引用和导出你需要加上 `type` 字段, 例如 `import type { A } from './types`。更多信息可以参考 [TypeScript - isolatedModules](/guide/basic/typescript#isolatedmodules)。 + +::: + +你可以使用 [bundle](/config/lib/bundle) 选项来指定是否进行 bundle,默认情况下该选项设置为 `true`。 diff --git a/website/docs/zh/guide/basic/typescript.mdx b/website/docs/zh/guide/basic/typescript.mdx index 8b199f180..545c09307 100644 --- a/website/docs/zh/guide/basic/typescript.mdx +++ b/website/docs/zh/guide/basic/typescript.mdx @@ -1 +1,46 @@ # 使用 Typescript + +Rslib 默认支持 TypeScript,你可以直接在项目中使用 `.ts` 和 `.tsx` 文件。 + +## TypeScript 转译 + +Rslib 默认使用 SWC 进行 TypeScript 代码的转译,同时也支持切换到 Babel 进行转译。 + +### isolatedModules + +不同于原生的 TypeScript 编译器,SWC 和 Babel 这类工具会单独编译每个文件,这会导致无法确定导入的名称是类型还是值。因此,在 Rslib 中使用 TypeScript 时,你需要在 `tsconfig.json` 文件中启用 [isolatedModules](https://typescriptlang.org/tsconfig/#isolatedModules) 选项: + +```json title="tsconfig.json" +{ + "compilerOptions": { + "isolatedModules": true + } +} +``` + +这个选项可以帮助你避免使用某些在 SWC 和 Babel 中无法正确编译的语法,例如跨文件的类型引用。它会引导你修正为对应正确的用法: + +```ts +// 错误 +export { SomeType } from './types'; + +// 正确 +export type { SomeType } from './types'; +``` + +> 更多关于 SWC 和 tsc 之间差异的详细信息,可以查看 [SWC - Migrating from tsc](https://swc.rs/docs/migrating-from-tsc)。 + +## tsconfig.json 路径 + +Rslib 默认从根目录下读取 `tsconfig.json` 文件。你可以使用 [source.tsconfigPath](/config/rsbuild/source#sourcetsconfigpath) 配置一个自定义的 `tsconfig.json` 文件路径。 + +```ts title="rslib.config.ts" +export default { + lib: [ + // ... + ], + source: { + tsconfigPath: './tsconfig.custom.json', + }, +}; +``` diff --git a/website/docs/zh/guide/basic/upgrade-rslib.mdx b/website/docs/zh/guide/basic/upgrade-rslib.mdx index 3c34eec28..c92b8ef9f 100644 --- a/website/docs/zh/guide/basic/upgrade-rslib.mdx +++ b/website/docs/zh/guide/basic/upgrade-rslib.mdx @@ -1 +1,72 @@ # 升级 Rslib + +本节介绍如何将项目中的 Rslib 依赖升级到最新版本。 + +{/* TODO */} +{/* > Please see [Releases](/community/releases/index) to understand the Rsbuild release strategy. */} + +:::info + +Rslib 仍处于 0.x 版本,API 可能会频繁变化。我们建议升级到最新版本以使用新功能和已修复的 bug。 + +::: + +## 使用 Taze + +我们推荐使用 [Taze](https://github.com/antfu-collective/taze) 来升级 Rslib 版本。Taze 是一个用于更新 npm 依赖的 CLI 工具。 + +### 使用方法 + +运行以下命令以升级所有名称中包含 `rslib` 和 `rsbuild` 的依赖项: + +```bash +npx taze major --include "/(rsbuild|rslib)/" -w +``` + +:::tip + +Rslib 尚未达到 1.0.0 版本,因此你需要在更新时添加 `major` 参数。 + +::: + +结果将类似于: + +```bash +rslib - 2 major, 1 patch + + @rsbuild/plugin-react dev ~2mo ^1.0.1 → ^1.0.6 + @rslib/core dev ~7d ^0.0.15 → ^0.0.16 + rsbuild-plugin-dts dev ~7d ^0.0.15 → ^0.0.16 + +ℹ changes written to package.json, run npm i to install updates. +``` + +你可以调整 `include` 模式以匹配特定包,例如,仅升级 `@rslib` 范围内的包: + +```bash +npx taze --include /@rslib/ -w +``` + +### 选项 + +以下是一些使用 taze 选项的示例。 + +- 在 monorepo 中,你可以添加 `-r` 选项以递归升级: + +```bash +npx taze --include /(rsbuild|rslib)/ -w -r +``` + +- 添加 `-l` 选项以升级锁定版本: + +```bash +npx taze --include /(rsbuild|rslib)/ -w -l +``` + +- 升级到 major 版本: + +```bash +npx taze major --include /(rsbuild|rslib)/ -w +``` + +> 更多选项请参考 [taze 文档](https://github.com/antfu-collective/taze)。 diff --git a/website/docs/zh/guide/start/components/CJS.mdx b/website/docs/zh/guide/start/components/CJS.mdx index 6914198b9..04eff4c33 100644 --- a/website/docs/zh/guide/start/components/CJS.mdx +++ b/website/docs/zh/guide/start/components/CJS.mdx @@ -1 +1 @@ -a module system used in JavaScript, particularly in server-side environments like Node.js. It was created to allow JavaScript to be used outside of the browser by providing a way to manage modules and dependencies. +一种在 JavaScript 中使用的模块系统,特别是在像 Node.js 这样的服务器端环境中。它的诞生是为了通过提供一种管理模块和依赖项的方法,允许 JavaScript 在浏览器之外使用。 diff --git a/website/docs/zh/guide/start/components/ESM.mdx b/website/docs/zh/guide/start/components/ESM.mdx index 8774f4bc9..4e0737576 100644 --- a/website/docs/zh/guide/start/components/ESM.mdx +++ b/website/docs/zh/guide/start/components/ESM.mdx @@ -1 +1 @@ -a modern module system introduced in ES2015 that allows JavaScript code to be organized into reusable, self-contained modules. ESM is now the standard for both [browser](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) and [Node.js](https://nodejs.org/api/esm.html) environments, replacing older module systems like [CommonJS (CJS)](https://nodejs.org/api/modules.html) and [AMD](https://requirejs.org/docs/whyamd.html). +一种在 ES2015 中引入的现代模块系统,允许将 JavaScript 代码组织成可重用的、自包含的模块。ESM 现在是 [浏览器](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Modules) 和 [Node.js](https://nodejs.org/api/esm.html) 环境的标准,取代了旧的模块系统,如 [CommonJS (CJS)](https://nodejs.org/api/modules.html) 和 [AMD](https://requirejs.org/docs/whyamd.html)。 diff --git a/website/docs/zh/guide/start/components/MF.mdx b/website/docs/zh/guide/start/components/MF.mdx index 9fbaa0a5a..f11370527 100644 --- a/website/docs/zh/guide/start/components/MF.mdx +++ b/website/docs/zh/guide/start/components/MF.mdx @@ -1,3 +1,3 @@ -Module Federation is an architectural pattern for JavaScript application decomposition (similar to microservices on the server-side), allowing you to share code and resources between multiple JavaScript applications (or micro-frontends). +模块联邦是一种用于 JavaScript 应用程序分解的架构模式(类似于服务器端的微服务),允许你在多个 JavaScript 应用程序(或微前端)之间共享代码和资源。 -See [Module Federation](https://rsbuild.dev/guide/advanced/module-federation) for more details. +请参阅 [模块联邦](https://rsbuild.dev/guide/advanced/module-federation) 以获取更多详细信息。 diff --git a/website/docs/zh/guide/start/components/UMD.mdx b/website/docs/zh/guide/start/components/UMD.mdx index 14851f7aa..948b84d32 100644 --- a/website/docs/zh/guide/start/components/UMD.mdx +++ b/website/docs/zh/guide/start/components/UMD.mdx @@ -1 +1 @@ -UMD stands for [Universal Module Definition](https://github.com/umdjs/umd), a pattern for writing JavaScript modules that can work universally across different environments, such as both the browser and Node.js. Its primary goal is to ensure compatibility with the most popular module systems, including AMD (Asynchronous Module Definition), CommonJS (CJS), and browser globals. +UMD 代表 [通用模块定义](https://github.com/umdjs/umd),这是一种编写 JavaScript 模块的模式,可以在不同的环境中通用,例如浏览器和 Node.js。其主要目标是确保与最流行的模块系统兼容,包括 AMD(异步模块定义)、CommonJS(CJS)和浏览器全局变量。