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
会优先使用当前入口下的 Docoument.[jt]sx
文件。如果当前入口没有 Document.[jt]sx
文件,例如 entry-b
,则会查找根目录下的 Document.[jt]sx
文件。
如果未找到,将会使用 Modern.js 的默认模板。
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