For AI agents: the complete documentation index is available at /zh/llms.txt, the full documentation bundle is available at /zh/llms-full.txt, and this page is available as Markdown at /zh/guides/basic-features/html.md.
  • 简体中文
  • HTML 模板

    Modern.js 提供了 JSX 语法和 HTML(EJS) 语法两种方式用于自定义 HTML 模板。

    JSX 语法

    Modern.js 约定,在 src/ 或入口目录下,可以创建 Document.tsx 文件并默认导出组件,该组件的渲染结果可以作为入口的 HTML 模板。

    例如以下目录结构:

    .
    └── src
        ├── Document.tsx
        ├── entry-a
        │   ├── Document.tsx
        │   └── routes
        └── entry-b
             └── routes

    entry-a 会优先使用当前入口下的 Document.tsx 文件。如果当前入口没有 Document.tsx 文件,例如 entry-b,则会查找根目录下的 Document.tsx 文件。

    如果未找到,将会使用 Modern.js 的默认模板。

    Tip

    Document.tsx 会在构建时由 Modern.js 的 Document 插件创建 Rspack 子编译器流程,编译为面向 Node.js 的产物,并在编译时以 renderToStaticMarkup 渲染为字符串作为 HTML 模板内容,其行为类似静态站点生成。HTML 模板模块不会经过页面 Bundler 的常规编译打包,因此组件中的 React Hooks 不会在浏览器运行时被执行,也不支持导入 JavaScript 以外的图片等资源模块。

    HTML 组件

    Modern.js 提供了一系列渲染页面的组件,用来帮助开发者生成模板,可以从 @modern-js/runtime/document 中使用这些组件:

    import { Html, Body, Root, Head, Scripts } from '@modern-js/runtime/document';

    这些组件分别用于渲染:

    • Html:提供原生 HTML Element 的能力,并能默认渲染开发者未添加的必须的组件。<Head> 和 <Body> 是必须要存在的,其它组件可以按需选择合适的组件进行组装。

    • Body:提供原生 Body Element 的能力,内部需要包含 <Root> 组件,也支持其它元素同时作为子元素,例如添加页脚。

    • Root:渲染的根节点 <div id='root'></div>。默认根节点的 id = 'root'。可以设置 props.rootId 来更改 id 属性。可以添加子组件,也会被渲染到 HTML 模板中,当 React 渲染完成后会被覆盖,一般用来实现全局 Loading。

    • Head:提供原生 Head Element 的能力,并会自动填充 <meta>,以及 <Scripts> 组件。

    • Scripts:用于控制构建生成的 <script> 标签的位置,默认放在 <Head> 组件中。

    • Comment:将用户编写的 <!-- gateway --> 这种注释,保留输出到最新渲染的 html 中。

    模板参数

    因为是 JSX 形式,Document.tsx 里,可以比较自由的在组件内使用各种变量去赋值给各种自定义组件。

    Modern.js 也提供了 DocumentContext 来提供一些配置、环境参数,方便直接获取。主要以下参数:

    • processEnv:提供构建时的 process.env。
    • config:Modern.js 项目的配置。目前只暴露出 output 相关的配置。
    • entryName:当前的入口名。
    • templateParams:HTML 模板的参数(为了兼容传统模板,不推荐使用)。

    基础示例

    import React, { useContext } from 'react';
    import {
      Html,
      Root,
      Head,
      Body,
      Comment,
      DocumentContext,
    } from '@modern-js/runtime/document';
    
    export default function Document(): React.ReactElement {
      // DocumentContext 提供一些构建时的参数
      const {
        config: { output: htmlConfig },
        entryName,
        templateParams,
      } = useContext(DocumentContext);
    
      return (
        <Html>
          <Head>
            <link href="https://modernjs.dev" />
            <Comment>{'<!-- Need a Comment -->'}</Comment>
          </Head>
          <Body>
            <Root rootId="root">
              <h1 style={{ color: 'red' }}>以下为构建时传过来的参数:</h1>
              <h2>entryName: {entryName}</h2>
              <h2>title: {htmlConfig.title}</h2>
              <h2>rootId: {templateParams.mountId}</h2>
            </Root>
            <h1>bottom</h1>
          </Body>
        </Html>
      );
    }

    以上 JSX 组件,将会生成以下 HTML 模板:

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1.0, shrink-to-fit=no, viewport-fit=cover, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
        />
        <meta http-equiv="x-ua-compatible" content="ie=edge" />
        <meta name="renderer" content="webkit" />
        <meta name="layoutmode" content="standard" />
        <meta name="imagemode" content="force" />
        <meta name="wap-font-scale" content="no" />
        <meta name="format-detection" content="telephone=no" />
        <link rel="icon" href="/a.icon" />
        <script defer src="/static/js/builder-runtime.js"></script>
        <script defer src="/static/js/lib-react.js"></script>
        <script defer src="/static/js/lib-polyfill.js"></script>
        <script defer src="/static/js/lib-router.js"></script>
        <script defer src="/static/js/sub.js"></script>
        <link href="https://modernjs.dev" />
        <!-- Need a Comment -->
      </head>
    
      <body>
        <div id="root">
          <!--<?- html ?>-->
          <h1 style="color:red">以下为构建时传过来的参数:</h1>
          <h2>entryName: sub</h2>
          <h2>title:</h2>
          <h2>rootId: root</h2>
        </div>
        <h1>bottom</h1>
        <!--<?- chunksMap.js ?>-->
        <!--<?- SSRDataScript ?>-->
      </body>
    </html>

    Scripts 组件示例

    你可以使用 <Scripts> 组件,将构建生成的 <script> 标签插入到 <body> 标签内:

    import React from 'react';
    import { Html, Root, Head, Body, Scripts } from '@modern-js/runtime/document';
    
    export default function Document(): React.ReactElement {
      return (
        <Html>
          <Head></Head>
          <Body>
            <Root rootId="root"></Root>
            <Scripts />
          </Body>
        </Html>
      );
    }

    HTML 语法

    Modern.js 也支持通过 HTML(EJS) 语法来生成 HTML 文件。

    默认情况下,Modern.js 的工程中会内置一份 HTML 模板,用于生成 HTML 代码。如果你需要自定义 HTML 模板,可以使用自定义 HTML 片段和完全自定义 HTML 模板两种方式。

    自定义 HTML 片段

    在应用根目录下,创建 config/html/ 目录,该目录下支持创建四种 HTML 片段。

    • top.html
    • head.html
    • body.html
    • bottom.html

    这些片段将按位置注入到默认的 HTML 模板中。

    <!DOCTYPE html>
    <html>
      <head>
        <%= topTemplate %>
        <%= headTemplate %>
        {/* rspack inject css  */}
      </head>
      <body>
        <noscript>
          We're sorry but react app doesn't work properly without JavaScript
          enabled. Please enable it to continue.
        </noscript>
        <div id="<%= mountId %>"></div>
        <%= bodyTemplate %>
        {/* rspack inject js  */}
        {/* <?- bottomTemplate ?> */}
      </body>
    </html>

    代码片段支持使用 Lodash template 语法。

    例如在 body.html 里插入一个外链脚本:

    config/html/body.html
    <script src="//example.com/assets/a.js"></script>
    Info

    自定义 HTML 片段的实现方式是将片段与框架内置的模板进行合并,由于框架的默认模板中已经存在 <title>,因此自定义 HTML 模板中的 title 标签无法生效,请通过 html.title 来修改页面标题。

    完全自定义 HTML 模板

    某些情况下,HTML 片段无法满足自定义需求,Modern.js 提供了完全自定义方式。

    注意

    通常不建议直接覆盖默认的 HTML 模板,可能会失去一部分功能选项。即使需要替换,建议以内置模板为基础,按需修改。

    在 config/html/ 目录下,创建 index.html 文件,该文件将替代默认的 HTML 模板。

    Info

    内部默认 HTML 模板可以在 node_modules/.modern-js/${entryName}/index.html 中查看。

    模板参数

    模板中使用的参数可以通过 html.templateParameters 配置项来定义。

    按入口设置

    config/html/ 目录中的 HTML 片段对应用中的所有入口都生效。如果希望按入口自定义 HTML 片段,可以在 config/html/ 目录下新建一个以入口名命名的目录,然后在这个目录中自定义 HTML 片段。

    例如,如下设置的 HTML 片段仅对入口 entry1 生效:

    .
    ├── config/
    │   └── html/
    │       └── entry1
    │           ├── head.html
    │           └── body.html
    └── src/
        ├── entry1/
        │   └── routes
        └── entry2/
            └── routes