Html Config
本章节描述了 Builder 中与 HTML 有关的配置。
html.appIcon
- 类型:
string
- 默认值:
undefined
设置 iOS 系统下的 apple-touch-icon 图标的文件路径,可以设置为相对于项目根目录的相对路径,也可以设置为文件的绝对路径。暂不支持设置为 CDN URL。
配置该选项后,在编译过程中会自动将图标拷贝至 dist 目录下,并在 HTML 中添加相应的 link
标签。
示例
设置为相对路径:
export default {
html: {
appIcon: './src/assets/icon.png',
},
};
设置为绝对路径:
import path from 'path';
export default {
html: {
appIcon: path.resolve(__dirname, './src/assets/icon.png'),
},
};
重新编译后,HTML 中自动生成了以下标签:
<link rel="apple-touch-icon" sizes="180*180" href="/static/image/icon.png" />
html.crossorigin
- 类型:
boolean | 'anonymous' | 'use-credentials'
- 默认值:
false
用于设置 <script>
和 <style>
标签的 crossorigin 属性。
- 当传入
true
时,它会被自动设置为 crossorigin="anonymous"
。
- 当传入
false
时,它不会设置 crossorigin
属性。
示例
export default {
html: {
crossorigin: 'anonymous',
},
};
编译后,HTML 中的 <script>
标签变为:
<script defer src="/static/js/main.js" crossorigin="anonymous"></script>
<style>
标签变为:
<link href="/static/css/main.css" rel="stylesheet" crossorigin="anonymous" />
可选值
crossorigin
可以被设置为以下几个值:
html.disableHtmlFolder
移除 HTML 产物对应的文件夹。开启该选项后,生成的 HTML 文件目录会从 [name]/index.html
变为 [name].html
。
示例
默认情况下,HTML 产物在 dist
目录下的结构为:
/dist
└── html
└── main
└── index.html
开启 html.disableHtmlFolder
配置:
export default {
html: {
disableHtmlFolder: true,
},
};
重新编译后,HTML 产物在 dist 中的目录结构如下:
/dist
└── html
└── main.html
如果需要设置 HTML 文件在 dist 目录中的路径,请使用 output.distPath.html
配置。
html.favicon
- 类型:
string | Function
- 默认值:
undefined
设置页面的 favicon 图标,可以设置为:
- URL 地址。
- 文件的绝对路径。
- 相对于项目根目录的相对路径。
配置该选项后,在编译过程中会自动将图标拷贝至 dist 目录下,并在 HTML 中添加相应的 link
标签。
示例
设置为相对路径:
export default {
html: {
favicon: './src/assets/icon.png',
},
};
设置为绝对路径:
import path from 'path';
export default {
html: {
favicon: path.resolve(__dirname, './src/assets/icon.png'),
},
};
设置为 URL:
import path from 'path';
export default {
html: {
favicon: 'https://foo.com/favicon.ico',
},
};
重新编译后,HTML 中自动生成了以下标签:
<link rel="icon" href="/favicon.ico" />
详细用法可参考 Rsbuild - html.favicon。
html.faviconByEntries
- 类型:
Record<string, string>
- 默认值:
undefined
用于在多页面的场景下,为不同的页面设置不同的 favicon。
整体用法与 favicon
一致,并且可以使用「入口名称」作为 key ,对各个页面进行单独设置。
faviconByEntries
的优先级高于 favicon
,因此会覆盖 favicon
中设置的值。
WARNING
Deprecated:该配置已废弃,请使用 favicon
的函数用法代替。
示例
export default {
html: {
favicon: './src/assets/default.png',
faviconByEntries: {
foo: './src/assets/foo.png',
},
},
};
重新编译后,可以看到:
html.inject
- 类型:
'head' | 'body' | boolean | Function
- 默认值:
'head'
修改构建产物中 <script>
标签在 HTML 中的插入位置。
可以设置为以下值:
'head'
: script 标签会插入在 HTML 的 head 标签内。
'body'
: script 标签会插入在 HTML 的 body 标签尾部。
true
: 最终表现取决于 html-webpack-plugin
的 scriptLoading 配置项。
false
: script 标签不插入 HTML 中。
默认插入位置
script 标签默认在 head 标签内:
<html>
<head>
<title></title>
<script defer src="/static/js/runtime-main.js"></script>
<script defer src="/static/js/main.js"></script>
<link href="/static/css/main.css" rel="stylesheet" />
</head>
<body>
<div id="root"></div>
</body>
</html>
插入至 body 标签
添加如下配置,可以将 script 插入至 body 标签:
export default {
html: {
inject: 'body',
},
};
可以看到 script 标签生成在 body 标签尾部:
<html>
<head>
<title></title>
<link href="/static/css/main.css" rel="stylesheet" />
</head>
<body>
<div id="root"></div>
<script defer src="/static/js/runtime-main.js"></script>
<script defer src="/static/js/main.js"></script>
</body>
</html>
详细用法可参考 Rsbuild - html.inject。
html.injectByEntries
- 类型:
Record<string, boolean | string>
- 默认值:
undefined
用于在多页面的场景下,为不同的页面设置不同的 script 标签插入位置。
整体用法与 inject
一致,并且可以使用「入口名称」作为 key ,对各个页面进行单独设置。
injectByEntries
的优先级高于 inject
,因此会覆盖 inject
中设置的值。
WARNING
Deprecated:该配置已废弃,请使用 inject
的函数用法代替。
示例
export default {
html: {
inject: 'head',
injectByEntries: {
foo: 'body',
},
},
};
重新编译后,可以看到:
html.meta
- 类型:
Object | Function
- 默认值:
undefined
配置 HTML 页面的 <meta>
标签。
示例
当 meta
对象的 value
为字符串时,会自动将对象的 key
映射为 name
,value
映射为 content
。
比如设置 description
:
export default {
html: {
meta: {
description: 'a description of the page',
},
},
};
最终在 HTML 中生成的 meta
标签为:
<meta name="description" content="a description of the page" />
详细用法可参考 Rsbuild - html.meta。
html.metaByEntries
- 类型:
Record<string, Meta>
- 默认值:
undefined
用于在多页面的场景下,为不同的页面设置不同的 meta 标签。
整体用法与 meta
一致,并且可以使用「入口名称」作为 key ,对各个页面进行单独设置。
metaByEntries
的优先级高于 meta
,因此会覆盖 meta
中设置的值。
WARNING
Deprecated:该配置已废弃,请使用 meta
的函数用法代替。
示例
export default {
html: {
meta: {
description: 'ByteDance',
},
metaByEntries: {
foo: {
description: 'TikTok',
},
},
},
};
编译后,可以看到页面 foo
的 meta 为:
<meta name="description" content="TikTok" />
其他页面的 meta 为:
<meta name="description" content="ByteDance" />
html.mountId
默认情况下,HTML 模板中包含了 root
节点用于组件挂载,通过 mountId
可以修改该节点的 id。
<body>
<div id="root"></div>
</body>
示例
修改 DOM 挂载节点 id
为 app
:
export default {
html: {
mountId: 'app',
},
};
编译后:
<body>
<div id="app"></div>
</body>
注意事项
更新相关代码
在修改 mountId
后,如果你的代码中有获取 root
根节点的逻辑,请更新对应的值:
- const domNode = document.getElementById('root');
+ const domNode = document.getElementById('app');
ReactDOM.createRoot(domNode).render(<App />);
自定义模板
如果你自定义了 HTML 模板,请确保模板中包含 <div id="<%= mountId %>"></div>
,否则 mountId
配置项无法生效。
html.scriptLoading
- 类型:
'defer' | 'blocking' | 'module'
- 默认值:
'defer'
用于设置 <script>
标签的加载方式。
defer
默认情况下,Builder 生成的 <script>
标签会自动设置 defer
属性,以避免阻塞页面的解析和渲染。
<head>
<script defer src="/static/js/main.js"></script>
</head>
<body></body>
TIP
当浏览器遇到带有 defer 属性的 <script>
标签时,它会异步地下载脚本文件,不会阻塞页面的解析和渲染。在页面解析和渲染完成后,浏览器会按照 <script>
标签在文档中出现的顺序依次执行它们。
blocking
将 scriptLoading
设置为 blocking
可以移除 defer
属性,此时脚本是同步执行的,这意味着它会阻塞浏览器的解析和渲染过程,直到脚本文件被下载并执行完毕。
export default {
html: {
inject: 'body',
scriptLoading: 'blocking',
},
};
当你需要设置 blocking
时,建议把 html.inject
设置为 body
,避免页面渲染被阻塞。
<head></head>
<body>
<script src="/static/js/main.js"></script>
</body>
module
将 scriptLoading
设置为 module
时,可以让脚本支持 ESModule 语法,同时浏览器也会自动默认延迟执行这些脚本,效果与 defer
类似。
export default {
html: {
scriptLoading: 'module',
},
};
<head>
<script type="module" src="/static/js/main.js"></script>
</head>
<body></body>
html.tags
- 类型:
ArrayOrNot<HtmlInjectTag | HtmlInjectTagHandler>
- 默认值:
undefined
添加和修改最终注入到 HTML 页面的标签。
对象形式
export interface HtmlInjectTag {
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);
/** @default false */
append?: boolean;
/**
* 仅对于允许包含在 head 中的元素会默认启用
* @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head#see_also}
*/
head?: boolean;
}
对象形式的配置项可以用于描述需要注入的标签,并可以通过参数控制注入的位置:
export default {
output: {
assetPrefix: '//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="//example.com/a.js?8327ec63"></script>
</head>
<body>
<!-- some other bodyTags... -->
</body>
</html>
标签最终的插入位置由 head
和 append
选项决定,两个配置相同的元素将被插入到相同区域,并且维持彼此之间的相对位置。
标签中表示外部资源文件路径的字段会受到 publicPath
和 hash
选项的影响,
这些字段包括 script
标签的 src
和 link
标签的 href
。
启用 publicPath
会让标签中表示路径的属性被拼接上 output.assetPrefix
字段。
而 hash
字段会让文件名后多出一个哈希查询用于控制浏览器缓存,哈希字符串与 HTML 文件产物的哈希值相同。
用户也可以向这两个配置传入函数,以自行控制路径拼接的逻辑。
函数形式
export type HtmlInjectTagUtils = {
outputName: string;
publicPath: string;
hash: string;
};
export type HtmlInjectTagHandler = (
tags: HtmlInjectTag[],
utils: HtmlInjectTagUtils,
) => HtmlInjectTag[] | void;
html.tags
也支持传入回调函数,通过在回调中编写逻辑可以任意修改标签列表,常用于修改标签列表或是在插入标签的同时确保其相对位置。
回调函数接受 tags 列表作为参数,并需要修改或直接返回新的 tags 数组:
export default {
html: {
tags: [
tags => {
tags.splice(0, 1);
},
/* ^?
* { tag: 'script', attrs: { src: 'b.js' } },
* ... some other headTags
* { tag: 'script', attrs: { src: 'c.js' } },
* ... some other bodyTags
* { tag: 'script', attrs: { src: 'a.js' }, head: false },
*/
{ tag: 'script', attrs: { src: 'a.js' }, head: false },
{ tag: 'script', attrs: { src: 'b.js' }, append: false },
{ tag: 'script', attrs: { src: 'c.js' } },
tags => [...tags, { tag: 'script', attrs: { src: 'd.js' } }],
/* ^?
* ... some other headTags
* { tag: 'script', attrs: { src: 'c.js' } },
* ... some other bodyTags
* { tag: 'script', attrs: { src: 'a.js' }, head: false },
*/
],
},
};
函数将在 HTML 处理流程的最后被执行,即如下的例子中不管回调函数在配置项中的位置如何,
参数 tags
都会包含配置项中所有的对象形式配置。
也因此在回调中修改 append
publicPath
hash
等属性都不会生效,因为这些属性都已经分别应用到了标签的位置和路径属性。
于是最终产物将会类似:
<html>
<head>
<!-- tags with `{ head: true, append: false }` here. -->
<!-- some other headTags... -->
<!-- tags with `{ head: true, append: true }` here. -->
<script src="//example.com/c.js"></script>
<script src="//example.com/d.js"></script>
</head>
<body>
<!-- tags with `{ head: false, append: false }` here. -->
<!-- some other bodyTags... -->
<!-- tags with `{ head: false, append: true }` here. -->
<script src="//example.com/a.js"></script>
</body>
</html>
限制
这个配置用于在 Builder 构建完成后修改 HTML 产物的内容,并不会引入和解析新的模块。因此,它无法用于引入未编译的源码文件,也无法代替 source.preEntry 等配置。
例如对于以下项目:
web-app
├── src
│ ├── index.tsx
│ └── polyfill.ts
└── modern.config.ts
modern.config.ts
export default {
output: {
assetPrefix: '//example.com/',
},
html: {
tags: [
{ tag: 'script', attrs: { src: './src/polyfill.ts' } },
],
},
};
这里的 tag 对象将会在简单处理后直接添加到 HTML 产物中,但对应的 polyfill.ts
将不会被转译、打包,也因此应用会在处理这行脚本时出现 404 错误。
<body>
<script src="//example.com/src/polyfill.ts"></script>
</body>
合理的使用场景包括:
- 注入 CDN 上 路径确定 的静态资源
- 注入需要首屏加载的内联脚本
例如以下示例的使用方式:
web-app
├── src
│ └── index.tsx
├── public
│ └── service-worker.js
└── modern.config.ts
modern.config.ts
function report() {
fetch('https://www.example.com/report')
}
export default {
html: {
output: {
assetPrefix: '//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="//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>
html.tagsByEntries
- 类型:
Record<string, ArrayOrNot<HtmlInjectTag | HtmlInjectTagHandler>>
- 默认值:
undefined
用于在多页面的场景下,为不同的页面注入不同的标签。
整体用法与 tags
一致,并且可以使用「入口名称」作为 key ,对各个页面进行单独设置。
tagsByEntries
的优先级高于 tags
,因此会覆盖 tags
中设置的值。
WARNING
Deprecated:该配置已废弃,请使用 tags
的函数用法代替。
示例
export default {
html: {
tags: [{ tag: 'script', attrs: { src: 'a.js' } }],
tagsByEntries: {
foo: [{ tag: 'script', attrs: { src: 'b.js' } }],
},
},
};
编译后,可以看到页面 foo
注入标签:
<script src="b.js"></script>
其他页面则注入了:
<script src="a.js"></script>
html.template
- 类型:
string | Function
- 默认值:
定义 HTML 模板的文件路径,对应 html-webpack-plugin 的 template
配置项。
示例
使用自定义的 HTML 模板文件替代默认模板,可以添加如下设置:
export default {
html: {
template: './static/index.html',
},
};
详细用法可参考 Rsbuild - html.template。
html.templateByEntries
- 类型:
Object
- 默认值:
undefined
用于在多页面的场景下,为不同的页面设置不同的 HTML 模板。
整体用法与 template
一致,并且可以使用「入口名称」作为 key ,对各个页面进行单独设置。
templateByEntries
的优先级高于 template
,因此会覆盖 template
设置的值。
WARNING
Deprecated:该配置已废弃,请使用 template
的函数用法代替。
示例
export default {
html: {
template: './static/index.html',
templateByEntries: {
foo: './src/pages/foo/index.html',
bar: './src/pages/bar/index.html',
},
},
};
html.templateParameters
- 类型:
Object | Function
- 默认值:
type DefaultParameters = {
mountId: string; // 对应 html.mountId 配置
entryName: string; // 入口名称
assetPrefix: string; // 对应 output.assetPrefix 配置
compilation: webpack.Compilation; // 对应 webpack 的 compilation 对象
webpackConfig: Configuration; // webpack 配置
// htmlWebpackPlugin 内置的参数
// 详见 https://github.com/jantimon/html-webpack-plugin
htmlWebpackPlugin: {
tags: object;
files: object;
options: object;
};
};
定义 HTML 模板中的参数,对应 html-webpack-plugin 的 templateParameters
配置项。你可以使用配置为对象或者函数。
如果是对象,会和默认参数合并。比如:
export default {
html: {
templateParameters: {
title: 'My App',
},
},
};
如果是函数,会传入默认参数,你可以返回一个对象,用于覆盖默认参数。比如:
export default {
html: {
templateParameters(defaultValue, { entryName }) {
const params = {
foo: {
...defaultValue,
type: 'Foo',
},
bar: {
...defaultValue,
type: 'Bar',
hello: 'world',
},
};
return params[entryName] || defaultValue;
},
},
};
详细用法可参考 Rsbuild - html.templateParameters。
html.templateParametersByEntries
- 类型:
Object
- 默认值:
undefined
用于在多页面的场景下,为不同的页面设置不同的模板参数。
整体用法与 templateParameters
一致,并且可以使用「入口名称」作为 key ,对各个页面进行单独设置。
templateParametersByEntries
的优先级高于 templateParameters
,因此会覆盖 templateParameters
中设置的值。
WARNING
Deprecated:该配置已废弃,请使用 templateParameters
的函数用法代替。
示例
export default {
html: {
templateParametersByEntries: {
foo: {
type: 'a',
},
bar: {
type: 'b',
},
},
},
};
html.title
- 类型:
string | Function
- 默认值:
undefined
配置 HTML 页面的 title 标签,例如:
export default {
html: {
title: 'example',
},
};
详细用法可参考 Rsbuild - html.title。
html.titleByEntries
- 类型:
Record<string, string>
- 默认值:
undefined
用于在多页面的场景下,为不同的页面设置不同的 title
。
整体用法与 title
一致,并且可以使用「入口名称」作为 key ,对各个页面进行单独设置。
titleByEntries
的优先级高于 title
,因此会覆盖 title
中设置的值。
WARNING
Deprecated:该配置已废弃,请使用 title
的函数用法代替。
示例
export default {
html: {
title: 'ByteDance',
titleByEntries: {
foo: 'TikTok',
},
},
};
重新编译后,可以看到:
- 页面
foo
的 title 为 TikTok
。
- 其他页面的 title 为
ByteDance
。