html.tags
type TagsConfig = HtmlTag | HtmlTagHandler | Array<HtmlTag | HtmlTagHandler>;
添加和修改最终注入到 HTML 页面的标签。
对象形式
type HtmlTag = {
tag: string;
attrs?: Record<string, string | boolean | null | undefined>;
children?: string;
/** @default false */
hash?: boolean | string | ((url: string, hash: string) => string);
/** @default true */
publicPath?: boolean | string | ((url: string, publicPath: string) => string);
/**
* 定义当前标签相对于原有标签的插入位置。
* 设为 `true` 时,将被插入原有标签之后;设为 `false` 时,将被插入原有标签之前。
* @default true
*/
append?: boolean;
/**
* 是否将标签添加到 head 中 (仅对于允许包含在 head 中的元素会默认启用)
* @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head#see_also}
*/
head?: boolean;
};
对象形式的配置项可以用于描述需要注入的标签,并可以通过参数控制注入的位置:
export default {
output: {
assetPrefix: 'https://example.com/',
},
html: {
tags: [
{
tag: 'script',
attrs: { src: 'a.js' },
head: true,
append: true,
publicPath: true,
hash: true,
},
],
},
};
这样的配置将会在 HTML 的 head
最后添加一个 script
标签:
<html>
<head>
<!-- some other headTags... -->
<script src="https://example.com/a.js?8327ec63"></script>
</head>
<body>
<!-- some other bodyTags... -->
</body>
</html>
标签中表示外部资源文件路径的字段会受到 publicPath
和 hash
选项的影响,这些字段包括 script
标签的 src
和 link
标签的 href
。
启用 publicPath
会让标签中表示路径的属性被拼接上 output.assetPrefix 字段。而 hash
字段会让文件名后多出一个哈希查询用于控制浏览器缓存,哈希字符串与 HTML 文件产物的哈希值相同。
用户也可以向这两个配置传入函数,以自行控制路径拼接的逻辑。
设置标签插入位置
标签最终的插入位置由 head
和 append
选项决定,当两个元素的 head
和 append
配置相同时,将被插入到相同区域,并且维持彼此之间的相对位置。
append
用于描述是将该标签添加到原有标签的末尾还是开头
head
用于描述是否将该标签添加到页面 <head>
中
最终在页面中的插入位置如下:
<html>
<head>
<!-- tags with `{ head: true, append: false }` here. -->
<!-- some other headTags... -->
<!-- tags with `{ head: true, append: true }` here. -->
</head>
<body>
<!-- tags with `{ head: false, append: false }` here. -->
<!-- some other bodyTags... -->
<!-- tags with `{ head: false, append: true }` here. -->
</body>
</html>
函数形式
type HtmlTagContext = {
hash: string;
entryName: string;
outputName: string;
publicPath: string;
};
type HtmlTagHandler = (
tags: HtmlTag[],
context: HtmlTagContext,
) => HtmlTag[] | void;
html.tags
也支持传入回调函数,通过在回调中编写逻辑可以任意修改标签列表,常用于修改标签列表或是在插入标签的同时确保其相对位置。
回调函数接受 tags 列表作为参数,并需要修改或直接返回新的 tags 数组:
export default {
html: {
tags: [
(tags) => [{ tag: 'script', attrs: { src: 'a.js' } }, ...tags],
(tags) => {
// 修改 'a.js' 标签
const target = tags.find((tag) => tag.attrs?.src === 'a.js');
if (target) {
target.attrs!.defer = true;
}
},
(tags) => {
// 将 'b.js' 插入到 'a.js' 之后
const targetIndex = tags.findIndex((tag) => tag.attrs?.src === 'a.js');
tags.splice(targetIndex + 1, 0, {
tag: 'script',
attrs: { src: 'd.js' },
});
},
],
},
};
最终产物将会类似:
<html>
<head>
<script src="/a.js" defer></script>
<script src="/d.js"></script>
<!-- some other headTags... -->
</head>
<body>
<!-- some bodyTags... -->
</body>
</html>
限制
这个配置用于在 Rsbuild 构建完成后修改 HTML 产物的内容,并不会引入和解析新的模块。因此,它无法用于引入未编译的源码文件,也无法代替 source.preEntry 等配置。
例如对于以下项目:
web-app
├── src
│ ├── index.tsx
│ └── polyfill.ts
└── rsbuild.config.ts
rsbuild.config.ts
export default {
output: {
assetPrefix: 'https://example.com/',
},
html: {
tags: [{ tag: 'script', attrs: { src: './src/polyfill.ts' } }],
},
};
这里的 tag 对象将会在简单处理后直接添加到 HTML 产物中,但对应的 polyfill.ts
将不会被转译、打包,也因此应用会在处理这行脚本时出现 404 错误。
<body>
<script src="https://example.com/src/polyfill.ts"></script>
</body>
合理的使用场景包括:
- 注入 CDN 上 路径确定 的静态资源
- 注入需要首屏加载的内联脚本
例如以下示例的使用方式:
web-app
├── src
│ └── index.tsx
├── public
│ └── service-worker.js
└── rsbuild.config.ts
rsbuild.config.ts
function report() {
fetch('https://www.example.com/report');
}
export default {
html: {
output: {
assetPrefix: 'https://example.com/',
},
tags: [
// Inject asset from the `public` directory.
{ tag: 'script', attrs: { src: 'service-worker.js' } },
// Inject asset from other CDN url.
{
tag: 'script',
publicPath: false,
attrs: { src: 'https://cdn.example.com/foo.js' },
},
// Inject inline script.
{
tag: 'script',
children: report.toString() + '\nreport()',
},
],
},
};
得到的产物将会类似:
<body>
<script src="https://example.com/service-worker.js"></script>
<script src="https://cdn.example.com/foo.js"></script>
<script>
function report() {
fetch('https://www.example.com/report');
}
report();
</script>
</body>