Html
本章节描述了 Rsbuild 中与 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
可以被设置为以下几个值:
anonymous
:请求使用 CORS 头,并将证书标志设置为 "same-origin"。除非目标是相同的 origin,否则不会通过 cookie、客户端 SSL 证书或 HTTP 身份验证交换用户凭据。
use-credentials
:请求使用 CORS 头,证书标志设置为 "include",并始终包含用户凭据。
html.outputStructure
Type: 'flat' | 'nested'
Default: 'flat'
用于定义 HTML 产物文件的目录结构。
示例
默认情况下,HTML 产物在 dist
目录下的结构为 flat
:
你可以将 html.outputStructure
配置为 nested
:
export default {
html : {
outputStructure : 'nested' ,
} ,
} ;
重新构建后,HTML 产物的目录结构如下:
/dist
└── [ name ]
└── index.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 " />
函数用法
type FaviconFunction = ( { value : string ; entryName : string } ) => string | void ;
当 html.favicon
为 Function 类型时,函数接收一个对象作为入参,对象的值包括:
value
:Rsbuild 的默认 favicon 配置。
entryName
: 当前入口的名称。
在 MPA(多页面应用)场景下,你可以基于入口名称返回不同的 favicon
,从而为每个页面生成不同的标签:
export default {
html : {
favicon ( { entryName } ) {
const icons = {
foo : 'https://example.com/foo.ico' ,
bar : 'https://example.com/bar.ico' ,
} ;
return icons [ entryName ] || 'https://example.com/default.ico' ;
} ,
} ,
} ;
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 >
函数用法
type InjectFunction = ( { value : ScriptInject ; entryName : string } ) => string | void ;
当 html.inject
为 Function 类型时,函数接收一个对象作为入参,对象的值包括:
value
:Rsbuild 的默认 inject 配置。
entryName
: 当前入口的名称。
在 MPA(多页面应用)场景下,你可以基于入口名称设置不同的 inject
方式:
export default {
html : {
inject ( { entryName } ) {
return entryName === 'foo' ? 'body' : 'head' ;
} ,
} ,
} ;
html.meta
类型: Object | Function
默认值:
const defaultMeta = {
// <meta charset="UTF-8" />
charset : {
charset : 'UTF-8' ,
} ,
// <meta name="viewport" content="width=device-width, initial-scale=1.0" />
viewport : 'width=device-width, initial-scale=1.0' ,
} ;
配置 HTML 页面的 <meta>
标签。
String 类型
type MetaOptions = {
[ name : string ] : string ;
} ;
当 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 " />
Object 类型
type MetaOptions = {
[ name : string ] :
| string
| false
| {
[ attr : string ] : string | boolean ;
} ;
} ;
当 meta
对象的 value
为对象时,会将该对象的 key: value
映射为 meta
标签的属性。
比如设置 charset
:
export default {
html : {
meta : {
charset : {
charset : 'UTF-8' ,
} ,
} ,
} ,
} ;
最终在 HTML 中生成的 meta
标签为:
函数用法
type MetaFunction = ( {
value : MetaOptions ,
entryName : string ,
} ) => MetaOptions | void ;
当 html.meta
为 Function 类型时,函数接收一个对象作为入参,对象的值包括:
value
:Rsbuild 的默认 meta 配置。
entryName
: 当前入口的名称。
你可以直接修改配置对象不做返回,也可以返回一个对象作为最终的配置。
比如,你可以直接修改内置的 meta
配置对象:
export default {
html : {
meta ( { value } ) {
value . description = 'this is my page' ;
return value ;
} ,
} ,
} ;
在 MPA(多页面应用)场景下,你可以基于入口名称返回不同的 meta
配置,从而为每个页面生成不同的 meta
标签:
export default {
html : {
meta ( { entryName } ) {
switch ( entryName ) {
case 'foo' :
return {
description : 'this is foo page' ,
} ;
case 'bar' :
return {
description : 'this is bar page' ,
} ;
default :
return {
description : 'this is other pages' ,
} ;
}
} ,
} ,
} ;
移除默认值
将 meta
对象的 value
设置为 false
,则表示不生成对应的 meta 标签。
比如移除 Rsbuild 预设的 viewport
:
export default {
html : {
meta : {
viewport : false ,
} ,
} ,
} ;
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
默认情况下,Rsbuild 生成的 <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 >
限制
这个配置用于在 Rsbuild 构建完成后修改 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.template
类型: string | Function
默认值:
定义 HTML 模板的文件路径,可以是相对路径或绝对路径。
如果没有指定 template
,默认会使用 Rsbuild 内置的 HTML 模板:
<! doctype html >
< html >
< head > </ head >
< body >
< div id = " <%= mountId %> " > </ div >
</ body >
</ html >
字符串用法
例如,使用 static/index.html
文件替代默认 HTML 模板,可以添加如下设置:
export default {
html : {
template : './static/index.html' ,
} ,
} ;
函数用法
type TemplateFunction = ( { value : string ; entryName : string } ) => string | void ;
当 html.template
为 Function 类型时,函数接收一个对象作为入参,对象的值包括:
value
:Rsbuild 的默认 template 配置。
entryName
: 当前入口的名称。
在 MPA(多页面应用)场景下,你可以基于入口名称返回不同的 template
路口,从而为每个页面设置不同的模板:
export default {
html : {
template ( { entryName } ) {
const templates = {
foo : './static/foo.html' ,
bar : './static/bar.html' ,
} ;
return templates [ entryName ] || './static/index.html' ,
} ,
} ,
} ;
html.templateParameters
类型: Record<string, unknown> | Function
默认值:
type DefaultParameters = {
mountId : string ; // 对应 html.mountId 配置
entryName : string ; // 入口名称
assetPrefix : string ; // 对应 output.assetPrefix 配置
compilation : Compilation ; // Rspack 的 compilation 对象
// htmlWebpackPlugin 内置的参数
// 详见 https://github.com/jantimon/html-webpack-plugin
htmlWebpackPlugin : {
tags : object ;
files : object ;
options : object ;
} ;
} ;
定义 HTML 模板中的参数,对应 html-webpack-plugin 的 templateParameters
配置项。
对象用法
如果 templateParameters
的值是一个对象,它会和默认参数通过 Object.assign
合并。
比如,如果你需要在 HTML 模板中使用 foo
参数,可以添加如下设置:
export default {
html : {
templateParameters : {
foo : 'bar' ,
} ,
} ,
} ;
接下来,你可以在 HTML 模板中,通过 <%= foo %>
来读取参数:
< script >
window . foo = '<%= foo %>' ;
</ script >
编译后的 HTML 代码如下:
< script >
window . foo = 'bar' ;
</ script >
函数用法
type TemplateParametersFunction = (
defaultValue : Record < string , unknown > ,
utils : { entryName : string } ,
) => Record < string , unknown > | void ;
当 html.templateParameters
为 Function 类型时,函数接收两个参数:
value
:Rsbuild 的默认 templateParameters 配置。
utils
: 一个对象,其中包含了 entryName
字段,对应当前入口的名称。
在 MPA(多页面应用)场景下,你可以基于入口名称设置不同的 templateParameters
参数:
export default {
html : {
templateParameters ( defaultValue , { entryName } ) {
const params = {
foo : {
... defaultValue ,
type : 'Foo' ,
} ,
bar : {
... defaultValue ,
type : 'Bar' ,
hello : 'world' ,
} ,
} ;
return params [ entryName ] || defaultValue ;
} ,
} ,
} ;
html.title
类型: string | Function
默认值: 'Rsbuild App'
配置 HTML 页面的 title 标签。
字符串用法
当 html.title
可以直接设置为一个字符串:
export default {
html : {
title : 'Example' ,
} ,
} ;
最终在 HTML 中生成的 title
标签为:
函数用法
type TitleFunction = ( { value : string ; entryName : string } ) => string | void ;
当 html.title
为 Function 类型时,函数接收一个对象作为入参,对象的值包括:
value
:Rsbuild 的默认 title 配置。
entryName
: 当前入口的名称。
在 MPA(多页面应用)场景下,你可以基于入口名称返回不同的 title
字符串,从而为每个页面生成不同的 title
标签:
export default {
html : {
title ( { entryName } ) {
const titles = {
foo : 'Foo Page' ,
bar : 'Bar Page' ,
} ;
return titles [ entryName ] || 'Other Page' ;
} ,
} ,
} ;