close
  • 简体中文
  • html.tags

    • 类型:
    type TagsConfig = HtmlTag | HtmlTagHandler | Array<HtmlTag | HtmlTagHandler>;
    • 默认值: undefined

    添加和修改最终注入到 HTML 页面的标签。

    在 Rsbuild 插件中,可以通过 api.modifyHTMLTags hook 来修改标签。

    基础示例

    例如,在 head 中添加 script 标签,并插入到已有标签之后:

    rsbuild.config.ts
    export default {
      html: {
        tags: [
          {
            tag: 'script',
            attrs: { src: 'https://example.com/script.js' },
          },
        ],
      },
    };

    生成的 HTML 文件:

    <html>
      <head>
        <!-- some other head tags... -->
        <script src="https://example.com/script.js"></script>
      </head>
      <body>
        <!-- some other body tags... -->
      </body>
    </html>

    Tag 对象

    html.tags 可以传入一个数组,数组中的每个元素都是一个 HtmlTag 对象,用于描述需要注入的标签。

    type HtmlTag = {
      tag: string;
      attrs?: Record<string, string | boolean | null | undefined>;
      children?: string;
      hash?: boolean | string | ((url: string, hash: string) => string);
      publicPath?: boolean | string | ((url: string, publicPath: string) => string);
      append?: boolean;
      head?: boolean;
      metadata?: Record<string, any>;
    };

    tag

    • 类型: string
    • 默认值: undefined

    要生成的 HTML 标签名称,需要设置为一个有效的 HTML 元素名称。

    例如,注入一个 script 标签和一个 link 标签:

    rsbuild.config.ts
    export default {
      html: {
        tags: [
          // 结果: <script src="https://example.com/script.js"></script>
          {
            tag: 'script',
            attrs: { src: 'https://example.com/script.js' },
          },
          // 结果: <link href="https://example.com/style.css" rel="stylesheet">
          {
            tag: 'link',
            attrs: { href: 'https://example.com/style.css', rel: 'stylesheet' },
          },
        ],
      },
    };

    attrs

    • 类型: Record<string, string | boolean | null | undefined>
    • 默认值: undefined

    标签的 HTML 属性。

    • string 值将渲染为 attribute="value"
    • true 渲染为布尔属性(例如,<input disabled>
    • falsenullundefined 值将不渲染该属性

    例如,注入一个带有 srctype 属性的 script 标签:

    rsbuild.config.ts
    export default {
      html: {
        tags: [
          // 结果: <script src="https://example.com/script.js" type="text/javascript" defer></script>
          {
            tag: 'script',
            attrs: {
              src: 'https://example.com/script.js',
              type: 'text/javascript',
              defer: true,
            },
          },
        ],
      },
    };

    children

    • 类型: string
    • 默认值: undefined

    标签的 innerHTML 内容,内容会按原样插入,不进行 HTML 转义,因此请确保内容安全以避免 XSS 漏洞。

    rsbuild.config.ts
    export default {
      html: {
        tags: [
          // 结果: <script>console.log("Hello, world!");</script>
          {
            tag: 'script',
            children: 'console.log("Hello, world!");',
          },
        ],
      },
    };

    hash

    • 类型: boolean | string | ((url: string, hash: string) => string)
    • 默认值: false

    控制是否为资源的 URL 添加 hash 作为 query 参数,以进行缓存失效,仅影响 script 标签的 src 属性和 link 标签的 href 属性。

    • false:不添加 hash query 参数
    • true:基于 HTML 内容生成 hash
    • string:使用自定义的 hash 字符串
    • function:通过函数自定义 hash 生成
    rsbuild.config.ts
    export default {
      html: {
        tags: [
          // 结果: <script src="https://example.com/script.js?8327ec63"></script>
          {
            tag: 'script',
            attrs: { src: 'https://example.com/script.js' },
            hash: true,
          },
        ],
      },
    };

    publicPath

    • 类型: boolean | string | ((url: string, publicPath: string) => string)
    • 默认值: true

    控制是否为资源的 URL 添加资源前缀,仅影响 script 标签的 src 属性和 link 标签的 href 属性。

    • true:为 URL 添加资源前缀
    • false:不添加资源前缀
    • string:使用自定义的前缀
    • function:通过函数自定义路径转换
    rsbuild.config.ts
    export default {
      output: {
        assetPrefix: 'https://cdn.example.com/',
      },
      html: {
        tags: [
          // 结果: <script src="https://cdn.example.com/script.js"></script>
          {
            tag: 'script',
            attrs: { src: '/script.js' },
            publicPath: true,
          },
        ],
      },
    };

    append

    • 类型: boolean
    • 默认值: true

    控制是否在现有标签之后插入标签。

    • true:在现有标签之后插入
    • false:在现有标签之前插入
    rsbuild.config.ts
    export default {
      html: {
        tags: [
          {
            tag: 'script',
            attrs: { src: 'https://example.com/script.js' },
            append: false,
          },
        ],
      },
    };

    查看 插入位置 了解更多。

    • 类型: boolean
    • 默认值: 自动检测

    指定是否将标签注入到 HTML <head> 元素中。

    • true:注入到 <head>
    • false:注入到 <body>
    rsbuild.config.ts
    export default {
      html: {
        tags: [
          {
            tag: 'script',
            attrs: { src: 'https://example.com/script.js' },
            head: false,
          },
        ],
      },
    };

    对于允许包含在 <head> 中的元素,默认值为 true;其他元素默认值为 false

    允许在 <head> 中包含的元素类型包括:

    • title
    • base
    • link
    • style
    • meta
    • script
    • noscript
    • template

    查看 插入位置 了解更多。

    metadata

    • 类型: Record<string, any>
    • 默认值: undefined

    标签的元信息对象,用于存储标签的附加信息。metadata 不会影响生成的 HTML 内容。

    例如,Rsbuild 插件可以为标签添加元信息,用于标识标签的来源;在后续的流程中,你可以基于元信息对标签进行特殊处理:

    rsbuild.config.ts
    const myPlugin = {
      name: 'my-plugin',
      setup(api) {
        api.modifyHTMLTags(({ headTags, bodyTags }) => {
          headTags.push({
            tag: 'script',
            attrs: { src: 'https://example.com/script.js' },
            metadata: {
              from: 'my-plugin',
            },
          });
          return { headTags, bodyTags };
        });
      },
    };
    
    export default {
      plugins: [myPlugin],
      html: {
        tags: [
          (tags) => {
            return tags.map((tag) => {
              if (tag.metadata?.from === 'my-plugin') {
                return {
                  ...tag,
                  // ...extra options
                };
              }
              return tag;
            });
          },
        ],
      },
    };

    插入位置

    标签的插入位置由 headappend 选项决定。

    • append 定义当前标签相对于已有标签的插入位置,默认值为 true
    • head 指定是否将当前标签添加到 HTML 的 <head> 元素中,对于允许在 <head> 中包含的元素类型,默认为 true,否则为 false
    • 如果两个标签对象的 headappend 选项一致,它们将被插入到相同区域,并且维持彼此之间的相对位置。
    <html>
      <head>
        <!-- 设置了 `{ head: true, append: false }` 的标签 -->
        <!-- 已有的 head tags... -->
        <!-- 设置了 `{ head: true, append: true }` 的标签 -->
      </head>
      <body>
        <!-- 设置了 `{ head: false, append: false }` 的标签 -->
        <!-- 已有的 body tags... -->
        <!-- 设置了 `{ head: false, append: true }` 的标签 -->
      </body>
    </html>

    函数形式

    type HtmlTagContext = {
      hash: string;
      entryName: string;
      outputName: string;
      publicPath: string;
    };
    
    type HtmlTagHandler = (tags: HtmlTag[], context: HtmlTagContext) => HtmlTag[] | void;

    html.tags 也支持传入回调函数,通过在回调中编写逻辑可以任意修改标签列表,常用于修改标签列表或是在插入标签的同时确保其相对位置

    回调函数接受 tags 列表作为参数,并需要修改或直接返回新的 tags 数组:

    rsbuild.config.ts
    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 ||= {};
              target.attrs.defer = true;
            }
          },
          (tags) => {
            // 将 'd.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>
        <!-- 其他 head 标签... -->
      </head>
      <body>
        <!-- 其他 body 标签... -->
      </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>

    版本历史

    版本变更内容
    v1.4.7新增 metadata 选项