From 0d5e22c4f8458c0640d3daedc67f0048ed070d12 Mon Sep 17 00:00:00 2001 From: SoonIter Date: Thu, 13 Feb 2025 18:22:53 +0800 Subject: [PATCH] docs: update the doc --- .../src/example.json | 4 + .../src/index.tsx | 18 +- .../react-component-bundle/src/example.json | 4 + examples/react-component-bundle/src/index.tsx | 18 +- .../asset/__snapshots__/index.test.ts.snap | 9 +- tests/integration/asset/json/src/index.js | 5 +- website/docs/zh/config/rsbuild/output.mdx | 8 + website/docs/zh/guide/advanced/_meta.json | 3 + website/docs/zh/guide/advanced/json-files.mdx | 101 ++++++ .../docs/zh/guide/advanced/static-assets.mdx | 295 ++++++++++++++++++ website/docs/zh/guide/advanced/svgr-files.mdx | 105 +++++++ website/docs/zh/guide/solution/index.mdx | 2 +- 12 files changed, 536 insertions(+), 36 deletions(-) create mode 100644 examples/react-component-bundle-false/src/example.json create mode 100644 examples/react-component-bundle/src/example.json create mode 100644 website/docs/zh/guide/advanced/json-files.mdx create mode 100644 website/docs/zh/guide/advanced/static-assets.mdx create mode 100644 website/docs/zh/guide/advanced/svgr-files.mdx diff --git a/examples/react-component-bundle-false/src/example.json b/examples/react-component-bundle-false/src/example.json new file mode 100644 index 0000000000..6ebb36c196 --- /dev/null +++ b/examples/react-component-bundle-false/src/example.json @@ -0,0 +1,4 @@ +{ + "name": "foo", + "items": [1, 2] +} \ No newline at end of file diff --git a/examples/react-component-bundle-false/src/index.tsx b/examples/react-component-bundle-false/src/index.tsx index 66d57bec3b..885114d41c 100644 --- a/examples/react-component-bundle-false/src/index.tsx +++ b/examples/react-component-bundle-false/src/index.tsx @@ -1,17 +1,3 @@ -import type React from 'react'; -import { CounterButton } from './components/CounterButton'; -import { useCounter } from './useCounter'; -import './index.scss'; +import { name } from './example.json'; -export const Counter: React.FC = () => { - const { count, increment, decrement } = useCounter(); - - return ( -
-

React

-

Counter: {count}

- - -
- ); -}; +console.log(name); // 'foo'; \ No newline at end of file diff --git a/examples/react-component-bundle/src/example.json b/examples/react-component-bundle/src/example.json new file mode 100644 index 0000000000..6ebb36c196 --- /dev/null +++ b/examples/react-component-bundle/src/example.json @@ -0,0 +1,4 @@ +{ + "name": "foo", + "items": [1, 2] +} \ No newline at end of file diff --git a/examples/react-component-bundle/src/index.tsx b/examples/react-component-bundle/src/index.tsx index 66d57bec3b..885114d41c 100644 --- a/examples/react-component-bundle/src/index.tsx +++ b/examples/react-component-bundle/src/index.tsx @@ -1,17 +1,3 @@ -import type React from 'react'; -import { CounterButton } from './components/CounterButton'; -import { useCounter } from './useCounter'; -import './index.scss'; +import { name } from './example.json'; -export const Counter: React.FC = () => { - const { count, increment, decrement } = useCounter(); - - return ( -
-

React

-

Counter: {count}

- - -
- ); -}; +console.log(name); // 'foo'; \ No newline at end of file diff --git a/tests/integration/asset/__snapshots__/index.test.ts.snap b/tests/integration/asset/__snapshots__/index.test.ts.snap index 800bcb6016..0e589033d7 100644 --- a/tests/integration/asset/__snapshots__/index.test.ts.snap +++ b/tests/integration/asset/__snapshots__/index.test.ts.snap @@ -13,7 +13,14 @@ export { draft_rslib_entry_namespaceObject as default }; `; exports[`use json 1`] = ` -"JSON.parse('{"foo":1,"bar":["2"]}'); +"var data_namespaceObject = { + R: 1, + K: [ + "2" + ] +}; +console.log(data_namespaceObject.R); +console.log(data_namespaceObject.K); " `; diff --git a/tests/integration/asset/json/src/index.js b/tests/integration/asset/json/src/index.js index c14c58d2a5..fff715a3c9 100644 --- a/tests/integration/asset/json/src/index.js +++ b/tests/integration/asset/json/src/index.js @@ -1,3 +1,4 @@ -import a from './assets/data.json'; +import { bar, foo } from './assets/data.json'; -a; +console.log(foo); +console.log(bar); diff --git a/website/docs/zh/config/rsbuild/output.mdx b/website/docs/zh/config/rsbuild/output.mdx index 75e76d398a..f9c216affa 100644 --- a/website/docs/zh/config/rsbuild/output.mdx +++ b/website/docs/zh/config/rsbuild/output.mdx @@ -4,6 +4,12 @@ import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; 与构建产物相关的选项。 +## output.assetPrefix + +使用该选项设置静态资源的 URL 前缀,比如设置为 CDN 地址。 + +在 [format](/config/lib/format) 为 `cjs` 或 `esm` 时,Rslib 默认会将 `output.assetPrefix` 设置为 `"auto"`。 + ## output.charset 指定输出文件的 [字符编码](https://developer.mozilla.org/en-US/docs/Glossary/Character_encoding),以确保它们在不同的环境中能够正确显示。 @@ -24,6 +30,8 @@ import { RsbuildDocBadge } from '@components/RsbuildDocBadge'; 设置图片、字体、媒体等静态资源被自动内联为 base64 的体积阈值。 +在 [format](/config/lib/format) 为 `cjs` 或 `esm` 时,Rslib 默认会将 `output.dataUriLimit` 设置为 `0`,不内联任何静态资源,以便于应用侧的构建工具处理和优化。 + ## output.distPath 设置构建产物的输出目录,Rsbuild 会根据产物的类型输出到对应的子目录下。 diff --git a/website/docs/zh/guide/advanced/_meta.json b/website/docs/zh/guide/advanced/_meta.json index c9bbf4c497..58d2ca2131 100644 --- a/website/docs/zh/guide/advanced/_meta.json +++ b/website/docs/zh/guide/advanced/_meta.json @@ -2,6 +2,9 @@ "third-party-deps", "output-compatibility", "dts", + "static-assets", + "svgr-files", + "json-files", "module-federation", "storybook" ] diff --git a/website/docs/zh/guide/advanced/json-files.mdx b/website/docs/zh/guide/advanced/json-files.mdx new file mode 100644 index 0000000000..ae3dfcb714 --- /dev/null +++ b/website/docs/zh/guide/advanced/json-files.mdx @@ -0,0 +1,101 @@ +# 引用 JSON 文件 + +Rslib 支持在代码中引用 JSON 文件。 + +## JSON 文件 + +你可以直接在 JavaScript 文件中引用 JSON 文件。 + +### 默认引用 + +```json title="example.json" +{ + "name": "foo", + "items": [1, 2] +} +``` + +```js title="index.js" +import example from './example.json'; + +console.log(example.name); // 'foo'; +console.log(example.items); // [1, 2]; +``` + +:::warning + +在 Bundle 模式下,JSON 文件支持默认引用和具名引用。 + +在 Bundleless 模式下,JSON 文件仅支持具名引用。 + +::: + + +### 具名引用 + +Rslib 同样支持通过 named import 来引用 JSON 文件: + +下面是一个使用示例,假设源码如下: + +import { Tabs, Tab } from '@theme'; + + + +```js +import { name } from './example.json'; + +console.log(name); // 'foo'; + +``` + + +```json title="example.json" +{ + "name": "foo", + "items": [1, 2] +} +``` + + + +会根据配置文件中的 [产物结构](/guide/basic/output-structure) 配置,打包出如下产物: + + + + + +```tsx +var example_namespaceObject = { + "name": "foo" +}; +console.log(example_namespaceObject.name); +``` + + + + + + + + + + +```tsx +import * as example from './example.js'; + +console.log(example.name); +``` + + + +```tsx +var example_namespaceObject = JSON.parse('{"name":"foo","items":[1,2]}'); +var __webpack_exports__items = example_namespaceObject.items; +var __webpack_exports__name = example_namespaceObject.name; +export { __webpack_exports__items as items, __webpack_exports__name as name }; +``` + + + + + diff --git a/website/docs/zh/guide/advanced/static-assets.mdx b/website/docs/zh/guide/advanced/static-assets.mdx new file mode 100644 index 0000000000..f333f3ec2f --- /dev/null +++ b/website/docs/zh/guide/advanced/static-assets.mdx @@ -0,0 +1,295 @@ +# 引用静态资源 + +Rslib 支持在代码中引用图片、字体、音频、视频等类型的静态资源。 + +在 [format](/config/lib/format) 为 `cjs` 或 `esm` 时,Rslib 将产物视为需要被其他打包工具再次消费的中间产物。 + +## 静态资源格式 + +以下是 Rslib 默认支持的静态资源格式: + +- **图片**:png、jpg、jpeg、gif、svg、bmp、webp、ico、apng、avif、tif、tiff、jfif、pjpeg、pjp、cur。 +- **字体**:woff、woff2、eot、ttf、otf、ttc。 +- **音频**:mp3、wav、flac、aac、m4a、opus。 +- **视频**:mp4、webm、ogg、mov。 + +如果你需要引用其他格式的静态资源,请参考 [扩展静态资源类型](#扩展静态资源类型)。 + +## 在 JS 文件中引用 + +在 JS 文件中,可以直接通过 `import` 的方式引用相对路径下的静态资源: + +```tsx +// 引用 src/assets 目录下的 logo.png 图片 +import logo from './assets/logo.png'; + +console.log(logo); // "/static/logo.[hash].png" + +export default = () => ; +``` + +也可以使用**路径别名**来引用: + +```tsx +import logo from '@/assets/logo.png'; + +console.log(logo); // "/static/logo.[hash].png" + +export default = () => ; +``` + +Rslib 会将源文件转化为一个 JS 文件和一个根据 [output.distPath](/config/rsbuild/output#outputdistpath) 输出的静态资源文件,用于保留对静态资源的 `import` 语句。 + +下面是一个使用示例,假设源码如下: + +import { Tabs, Tab } from '@theme'; + + + +```tsx +import logo from './assets/logo.svg'; + +console.log(logo); + +``` + + + + + + +会根据配置文件中的 [产物结构](/guide/basic/output-structure) 配置,打包出如下产物: + + + + + +```tsx +import logo_rslib_entry_namespaceObject from './static/svg/logo.svg'; + +console.log(logo_rslib_entry_namespaceObject) +``` + + + + + + + + + + + + + +```tsx +import logo from './assets/logo.mjs'; + +console.log(logo); +``` + + + + +```tsx +import logo_rslib_entry_namespaceObject from '../static/svg/logo.svg'; +export { logo_rslib_entry_namespaceObject as default }; +``` + + + + + + + + + + +## 在 CSS 文件中引用 + +在 CSS 文件中,可以引用相对路径下的静态资源: + +```css title="src/index.css" +.logo { + background-image: url('./assets/logo.png'); +} +``` + +也支持使用**路径别名**来引用: + +```css title="src/index.css" +.logo { + background-image: url('@/assets/logo.png'); +} +``` + +在 [format](/config/lib/format) 为 `cjs` 或 `esm` 时,Rslib 将产物视为需要被其他打包工具再次消费的中间产物,会通过设置 [output.assetPrefix](/config/rsbuild/output#outputassetprefix) 为 `"auto"` 来使 CSS 产物中保留相对引用路径。 + +下面是一个使用示例,假设源码如下: + + + +```css +.logo { + background-image: url('./assets/logo.png'); +} +``` + + + + + + +会打包出如下产物: + + + + + +```css +.logo { + background-image: url('./static/image/logo.png'); +} +``` + + + + + + + + + +--- + +### 在 CSS 中忽略某些文件引用 + +如果需要在 CSS 文件中引用绝对路径下的静态资源: + +```css +@font-face { + font-family: DingTalk; + src: url('/image/font/foo.ttf'); +} +``` + +默认情况下,Rslib 内置的 `css-loader` 会解析 `url()` 中的绝对路径并寻找指定的模块。如果你希望跳过绝对路径的解析,可以配置 [`tools.cssLoader`](/config/rsbuild/tools#toolscssloader) 来过滤指定的路径,被过滤的路径将被原样保留在代码中。 + +```ts +export default { + tools: { + cssLoader: { + url: { + filter: (url) => { + if (/\/image\/font/.test(url)) { + return false; + } + return true; + }, + }, + }, + }, +}; +``` + +## 静态资源内联 + +在开发组件库这种会被其他打包工具再次消费的中间产物时,一般不会内联静态资源,交给应用侧的构建工具处理和优化。 + +自动内联的体积阈值可以通过 [output.dataUriLimit](/config/rsbuild/output#outputdataurilimit) 配置项修改,在 [format](/config/lib/format) 为 `cjs` 或 `esm` 时,Rslib 默认会将 `output.dataUriLimit` 设置为 `0`,不内联任何静态资源。 + +## 构建产物目录 + +当静态资源被引用后,会自动被输出到构建产物的目录下,你可以: + +- 通过 [output.filename](/config/rsbuild/output#outputfilename) 来修改产物的文件名。 +- 通过 [output.distPath](/config/rsbuild/output#outputdistpath) 来修改产物的输出路径。 + +## 类型声明 + +当你在 TypeScript 代码中引用静态资源时,TypeScript 可能会提示该模块缺少类型定义: + +``` +TS2307: Cannot find module './logo.png' or its corresponding type declarations. +``` + +此时你需要为静态资源添加类型声明文件,请在项目中创建 `src/env.d.ts` 文件,并添加相应的类型声明。 + +- 方法一:如果项目里安装了 `@rslib/core` 包,你可以直接引用 `@rslib/core` 提供的**预设类型**: + +```ts +/// +``` + +- 方法二:手动添加需要的类型声明: + +```ts title="src/env.d.ts" +// 以 png 图片为例 +declare module '*.png' { + const url: string; + export default url; +} +``` + +添加类型声明后,如果依然存在上述错误提示,请尝试重启当前 IDE,或者调整 `env.d.ts` 所在的目录,使 TypeScript 能够正确识别类型定义。 + +## 扩展静态资源类型 + +如果 Rslib 内置的静态资源类型不能满足你的需求,可以通过以下方式扩展额外的静态资源类型。 + +### 使用 `source.assetsInclude` + +通过 [source.assetsInclude](/config/rsbuild/source#sourceassetsinclude) 配置项,你可以指定需要被视为静态资源的额外文件类型。 + +```ts title="rslib.config.ts" +export default { + source: { + assetsInclude: /\.pdf$/, + }, +}; +``` + +添加以上配置后,你就可以在代码里引用 `*.pdf` 文件了,比如: + +```js +import myFile from './static/myFile.pdf'; + +console.log(myFile); // "/static/assets/myFile.[hash].pdf" +``` + +### 使用 `tools.rspack` + +可以通过 [tools.rspack](/config/rsbuild/tools#toolsrspack) 来修改内置的 Rspack 配置,并添加自定义的静态资源处理规则。 + +比如,把 `*.pdf` 文件当做静态资源输出到产物目录,可以添加以下配置: + +```ts title="rslib.config.ts" +export default { + tools: { + rspack(config, { addRules }) { + addRules([ + { + test: /\.pdf$/, + // 将资源转换为单独的文件,并且保留 import 语句 + type: 'asset/resource', + generator: { + importMode: 'preserve', + }, + }, + ]); + }, + }, +}; +``` + +关于 asset modules 的更多介绍,请参考 [Rspack - Asset modules](https://rspack.dev/guide/features/asset-module)。 diff --git a/website/docs/zh/guide/advanced/svgr-files.mdx b/website/docs/zh/guide/advanced/svgr-files.mdx new file mode 100644 index 0000000000..1f2be6671a --- /dev/null +++ b/website/docs/zh/guide/advanced/svgr-files.mdx @@ -0,0 +1,105 @@ +# 引用 SVGR + +默认情况下,Rslib 会将 SVG 图片当作静态资源处理。 + +通过添加 [@rsbuild/plugin-svgr](https://rsbuild.dev/zh/plugins/list/plugin-svgr) 插件,Rslib 支持调用 [SVGR](https://react-svgr.com/),将 SVG 图片转换为一个 React 组件使用。 + +## 快速开始 + +### 安装插件 + +你可以通过如下的命令安装插件: + +import { PackageManagerTabs } from '@theme'; + + + +### 注册插件 + +你可以在 `rslib.config.ts` 文件中注册插件: + +```ts title="rslib.config.ts" +import { pluginSvgr } from '@rsbuild/plugin-svgr'; + +export default { + plugins: [pluginSvgr()], +}; +``` + +## 示例 + +### Bundle 模式 + +在 Bundle 模式下,支持 [Rsbuild SVGR 插件](https://rsbuild.dev/zh/plugins/list/plugin-svgr) 下的所有用法,唯一的区别是当以 URL 形式使用 SVG 文件时,Rslib 会按照 [引用静态资源](/zh/guide/advanced/static-assets) 在产物中对应保留静态资源的 `import` 语句。 + +下面是一个使用示例: + +```jsx title="App.jsx" +import Logo from './logo.svg?react'; + +export const App = () => ; +``` + +如果导入的路径不包含 `?react` 后缀,那么 SVG 会被当做普通的静态资源来处理,保留对静态资源的 `import` 语句。 + +```js +import logoURL from './static/logo.svg'; + +console.log(logoURL); +``` + +`@rsbuild/plugin-svgr` 也支持默认导入和混合导入等用法: + +- 通过 [svgrOptions.exportType](https://rsbuild.dev/zh/plugins/list/plugin-svgr#svgroptionsexporttype) 设置为 `'default'` 来启用默认导入。 +- 通过 [mixedImport](https://rsbuild.dev/zh/plugins/list/plugin-svgr#mixedimport) 选项来启用混合导入,从而同时使用默认导入和具名导入。 + +### Bundleless 模式 + +在 Bundleless 模式下,由于每个文件都是独立经过代码转换,因此不支持 `?react` 和 `?url` 的引用形式,但支持下面两种使用形式: + +#### 具名导入 + +`@rsbuild/plugin-svgr` 支持具名导入 `ReactComponent` 来使用 SVGR,你需要设置 [svgrOptions.exportType](https://rsbuild.dev/zh/plugins/list/plugin-svgr#svgroptionsexporttype) 为 `'named'`: + +```js +pluginSvgr({ + svgrOptions: { + exportType: 'named', + }, +}); +``` + +```jsx title="App.jsx" +import { ReactComponent as Logo } from './logo.svg'; + +export const App = () => ; +``` + +所有的 `.svg` 文件都会被转换成 React 组件,此时你可以: + +- 通过设置 [exclude](https://rsbuild.dev/zh/plugins/list/plugin-svgr#exclude) 来排除不需要转换的文件。 +- 通过 [svgrOptions.exportType](https://rsbuild.dev/zh/plugins/list/plugin-svgr#svgroptionsexporttype) 设置为 `'default'` 来修改为默认导出。 + +#### 混合导入 + +如果你的库中同时存在 url 和 React 组件两种引入形式,你也可以通过混合导入的方式来使用: + +```ts +pluginSvgr({ + mixedImport: true, + svgrOptions: { + exportType: 'named', + }, +}); +``` + +此时引用的 SVG 文件会同时导出 URL 和 React 组件: + +```js +import logoUrl, { ReactComponent as Logo } from './logo.svg'; + +console.log(logoUrl); // -> string +console.log(Logo); // -> React component +``` + +更多信息可以参考 [mixedImport](https://rsbuild.dev/zh/plugins/list/plugin-svgr#mixedimport) 选项。 diff --git a/website/docs/zh/guide/solution/index.mdx b/website/docs/zh/guide/solution/index.mdx index 23d3c33d40..a3e0e7a9b4 100644 --- a/website/docs/zh/guide/solution/index.mdx +++ b/website/docs/zh/guide/solution/index.mdx @@ -4,7 +4,7 @@ ## Browser target -开发在浏览器中运行的库时,可以将其打包为 [ESM](/guide/basic/output-format#esm--cjs) 和 [CJS](/guide/basic/output-format#esm--cjs) 格式,用于与 app 的 bundler 集成。将包 [conditional-exports](https://nodejs.org/api/packages.html#conditional-exports) 配置为 ESM 输出可以更好地进行 treeshaking。此外,你可以创建 [UMD](/guide/basic/output-format#umd) 格式输出以供浏览器直接使用,甚至可以生成 [模块联邦](/guide/advanced/module-federation) 格式以供其他应用程序动态加载。根据目标浏览器支持配置 [Browserslist](https://rsbuild.dev/zh/guide/advanced/browserslist)以确定输出的降级语法,或添加 [polyfill](/guide/advanced/output-compatibility) 用于兼容 API。 +开发在浏览器中运行的库时,可以将其打包为 [ESM](/guide/basic/output-format#esm--cjs) 和 [CJS](/guide/basic/output-format#esm--cjs) 格式,用于与 app 的打包工具集成。将包 [conditional-exports](https://nodejs.org/api/packages.html#conditional-exports) 配置为 ESM 输出可以更好地进行 treeshaking。此外,你可以创建 [UMD](/guide/basic/output-format#umd) 格式输出以供浏览器直接使用,甚至可以生成 [模块联邦](/guide/advanced/module-federation) 格式以供其他应用程序动态加载。根据目标浏览器支持配置 [Browserslist](https://rsbuild.dev/zh/guide/advanced/browserslist)以确定输出的降级语法,或添加 [polyfill](/guide/advanced/output-compatibility) 用于兼容 API。 发布到 npm 时,你可以选择不压缩代码或[压缩代码](/config/rsbuild/output#outputminify),同时提供[sourcemap](/config/rsbuild/output#outputsourcema) 以增强库使用者的调试体验。样式上,可以使用 CSS 或 CSS 预处理器,如 Sass、Less 或 Stylus 等,或使用 PostCSS 用于 CSS 后处理。 Tailwind CSS 等工具也可以帮助你构建样式,也可以使用 CSS Modules。