logo
  • 指南
  • 配置
  • 插件
  • API
  • 示例
  • 社区
  • Modern.js 2.x 文档
  • 简体中文
    • 简体中文
    • English
    • 开始
      介绍
      快速上手
      版本升级
      名词解释
      技术栈
      核心概念
      页面入口
      构建工具
      Web 服务器
      基础功能
      路由
      路由基础
      配置式路由
      数据管理
      数据获取
      数据写入
      数据缓存
      渲染
      服务端渲染(SSR)
      服务端流式渲染(Streaming SSR)
      渲染缓存
      静态站点生成(SSG)
      渲染预处理 (Render Preprocessing)
      样式开发
      引入 CSS
      使用 CSS Modules
      使用 CSS-in-JS
      使用 Tailwind CSS
      HTML 模板
      引用静态资源
      引用 JSON 文件
      引用 SVG 资源
      引用 Wasm 资源
      调试
      数据模拟(Mock)
      网络代理
      使用 Rsdoctor
      使用 Storybook
      测试
      Playwright
      Vitest
      Jest
      Cypress
      路径别名
      环境变量
      构建产物目录
      部署应用
      进阶功能
      使用 Rspack
      使用 BFF
      基础用法
      运行时框架
      扩展 BFF Server
      扩展一体化调用 SDK
      文件上传
      跨项目调用
      优化页面性能
      代码分割
      静态资源内联
      产物体积优化
      React Compiler
      提升构建性能
      浏览器兼容性
      配置底层工具
      源码构建模式
      服务端监控
      Monitors
      日志事件
      指标事件
      国际化
      基础概念
      快速开始
      配置说明
      语言检测
      资源加载
      路由集成
      API 参考
      高级用法
      最佳实践
      自定义 Web Server
      专题详解
      模块联邦
      简介
      开始使用
      应用级别模块
      服务端渲染
      部署
      集成国际化能力
      常见问题
      依赖安装问题
      命令行问题
      构建相关问题
      热更新问题
      已下线功能
      📝 编辑此页面
      上一页使用 Tailwind CSS下一页引用静态资源

      #HTML 模板

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

      #JSX 语法

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

      例如以下目录结构:

      .
      └── src
          ├── Document.tsx
          ├── entry-a
          │   ├── Document.tsx
          │   └── routes
          ├── entry-b
          │    └── routes
          └── modern-app-env.d.ts

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

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

      Tip

      Document.[jt]sx 模块将会被使用 esbuild 编译为 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.[jt]sx 里,可以比较自由的在组件内使用各种变量去赋值给各种自定义组件。

      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, { useContext } 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 %>
          {/* webpack 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 %>
          {/* webpack 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