配置 HTML 模板

在构建的过程中,Rsbuild 会基于 HTML 模板文件和模板参数进行编译,生成若干份 HTML 文件。

Rsbuild 提供了一些配置项来对 HTML 模板进行设置。通过本章节你可以了解到这些配置项的基本用法。

设置模板文件

在 Rsbuild 中,你可以使用 html.template 配置项来设置自定义的 HTML 模板文件。

export default {
  html: {
    template: './static/index.html',
  },
};

设置页面标题

你可以通过 html.title 配置项来设置 HTML 的 <title> 标签。

当你的项目中只有一个页面时,直接使用 html.title 设置即可:

export default {
  html: {
    title: 'example',
  },
};

当你的项目中有多个页面时,可以基于入口名称来为不同的页面设置对应的标题。

export default {
  html: {
    title({ entryName }) {
      const titles = {
        foo: 'Foo',
        bar: 'Bar',
      };
      return titles[entryName];
    },
  },
};

设置页面图标

Rsbuild 支持设置 favicon 图标 和 iOS 系统下的 apple-touch-icon 图标。

你可以通过 html.favicon 配置项来设置 favicon 图标。

export default {
  html: {
    favicon: './src/assets/icon.png',
  },
};

也可以通过 html.appIcon 配置项来设置 iOS 系统下的 apple-touch-icon 图标。

export default {
  html: {
    appIcon: './src/assets/icon.png',
  },
};

设置 meta 标签

你可以通过 html.meta 配置项来设置 HTML 的 <meta> 标签。

比如设置 description:

export default {
  html: {
    meta: {
      description: 'a description of the page',
    },
  },
};

最终在 HTML 中生成的 meta 标签为:

<meta name="description" content="a description of the page" />

设置模板参数

在 HTML 模板中,你可以使用丰富的模板参数,Rsbuild 默认注入的模板参数包括:

type DefaultParameters = {
  mountId: string; // 对应 html.mountId 配置
  entryName: string; // 入口名称
  assetPrefix: string; // 对应 dev.assetPrefix 和 output.assetPrefix 配置
  compilation: Compilation; // 对应 Rspack 的 compilation 对象
  // htmlWebpackPlugin 内置的参数
  // 详见 https://github.com/jantimon/html-webpack-plugin
  htmlWebpackPlugin: {
    tags: object;
    files: object;
    options: object;
  };
};

你也可以通过 html.templateParameters 配置项来传入自定义的模板参数。

比如:

export default {
  html: {
    templateParameters: {
      text: 'World',
    },
  },
};

接下来,你可以在 HTML 模板中,通过 <%= text %> 来读取参数:

<div>hello <%= text %>!</div>

经过编译后的最终 HTML 代码如下:

<div>hello world!</div>

模板引擎

Rsbuild 支持 Lodash TemplateEJSPug 等多个模板引擎,默认使用最基础的 Lodash Template 作为模板引擎。

Lodash Template

当模板文件的后缀为 .html 时,Rsbuild 会使用 Lodash Template 对模板进行编译。

例如,在模板中定义一个 text 参数,值为 'world',在构建时会自动将 <%= text %> 替换为对应的值。

<!-- 输入  -->
<div>hello <%= text %>!</div>

<!-- 输出 -->
<div>hello world!</div>

请阅读 Lodash Template 文档来了解完整用法。

EJS

当模板文件的后缀为 .ejs 时,Rsbuild 会使用 EJS 模板引擎对模板进行编译。EJS 是一套简单的模板语言,支持直接在标签内书写简单、直白的 JavaScript 代码,并通过 JavaScript 输出最终所需的 HTML。

例如,你可以先通过 html.template 配置项来引用一个 .ejs 模板文件:

export default {
  html: {
    template: './static/index.ejs',
  },
};

接着在模板中定义一个 user 参数,值为 { name: 'Jack' }。在构建时,会自动将 <%= user.name %> 替换为对应的值。

<!-- 输入  -->
<% if (user) { %>
<h2><%= user.name %></h2>
<% } %>

<!-- 输出 -->
<h2>Jack</h2>

请阅读 EJS 文档来了解完整用法。

Pug

Rsbuild 通过 Pug 插件来支持 Pug 模板引擎,请阅读 Pug 插件文档 来了解用法。

注入标签

通过配置 html.tags 选项可以在最终生成的 HTML 产物中插入任意标签。

使用场景

前端应用的产物最终都会直接或间接地被 HTML 入口引用,但大多数时候直接向 HTML 注入标签都并非首选。

模版文件中可以通过 htmlWebpackPlugin.tags 变量来访问需要最终注入到 HTML 的所有标签:

<html>
  <head>
    <%= htmlWebpackPlugin.tags.headTags %>
  </head>
  <body>
    <%= htmlWebpackPlugin.tags.bodyTags %>
  </body>
</html>

html.tags 的作用就是调整这些模板变量进而修改 HTML,配置的具体定义参考 API References

对象形式

export default {
  output: {
    assetPrefix: 'https://example.com/'
  },
  html: {
    tags: [
      { tag: 'script', attrs: { src: 'a.js' } },
      { tag: 'script', attrs: { src: 'b.js' }, append: false },
      { tag: 'link', attrs: { href: 'style.css', rel: 'stylesheet' }, append: true }
      { tag: 'link', attrs: { href: 'page.css', rel: 'stylesheet' }, publicPath: false }
      { tag: 'script', attrs: { src: 'c.js' }, head: false },
      { tag: 'meta', attrs: { name: 'referrer', content: 'origin' } },
    ],
  },
};

标签最终的插入位置由 headappend 选项决定,两个配置相同的元素将被插入到相同区域,并且维持彼此之间的相对位置。

标签默认会启用 publicPath 配置,即会将 output.assetPrefix 的值拼接到 script 标签的 src 等表示路径的属性上。

所以以上配置构建出的 HTML 产物将会类似:

<html>
  <head>
    <script src="https://example.com/b.js"></script>
    <link href="https://example.com/style.css" rel="stylesheet" />
    <link href="page.css" rel="stylesheet" />
    <!-- some other headTags... -->
    <script src="https://example.com/a.js"></script>
    <meta name="referrer" content="origin" />
  </head>
  <body>
    <!-- some other bodyTags... -->
    <script src="https://example.com/c.js"></script>
  </body>
</html>

函数形式

html.tags 也支持传入回调函数,常用于修改标签列表或是在插入标签的同时确保其相对位置:

export default {
  html: {
    tags: [
      (tags) => {
        tags.splice(0, 1);
      },
      { 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' } }],
    ],
  },
};

最终产物将会类似:

<html>
  <head>
    <!-- some other headTags... -->
    <script src="https://example.com/c.js"></script>
    <script src="https://example.com/d.js"></script>
  </head>
  <body>
    <!-- some other bodyTags... -->
    <script src="https://example.com/a.js"></script>
  </body>
</html>

HTML 插件

Rsbuild 内部基于 html-rspack-plugin 实现 HTML 相关的能力。它是 html-webpack-plugin 的一个 fork 版本,具备完全一致的功能和选项。

你可以通过 tools.htmlPlugin 来修改 html-rspack-plugin 的选项,也可以禁用内置的 html-rspack-plugin 插件。

比如:

rsbuild.config.ts
export default {
  tools: {
    htmlPlugin(config, { entryName }) {
      if (process.env.NODE_ENV === 'production') {
        config.filename = `${entryName}.[contenthash:8].html`;
      }
    },
  },
};