dojo dragon main logo

构建时渲染

构建时渲染 (BTR) 在构建过程中将路由渲染为 HTML,并内联显示初始视图所需的必要 CSS 和资源。这使 Dojo 能够预先渲染路由使用的初始 HTML 并将其直接注入页面,从而实现与服务器端渲染 (SSR) 相同的许多优势,例如性能提升和搜索引擎优化,而无需 SSR 的复杂性。

使用 BTR

首先确保 index.html 包含一个具有 id 属性的 DOM 节点。Dojo 的虚拟 DOM 将使用此节点来比较和渲染应用程序的 HTML。BTR 需要此设置,以便它可以渲染构建时生成的 HTML。这将创建路由的非常快速且响应的初始渲染。

index.html

<!DOCTYPE html>
<html lang="en-us">
	<head>
		<title>sample-app</title>
		<meta name="theme-color" content="#222127" />
		<meta name="viewport" content="width=device-width, initial-scale=1" />
	</head>
	<body>
		<div id="app"></div>
	</body>
</html>

然后,应用程序应挂载到指定的 DOM 节点

main.ts

const r = renderer(() => w(App, {}));
const domNode = document.getElementById('app') as HTMLElement;
r.mount({ registry, domNode });

然后,项目的 .dojorc 配置文件应使用根 DOM 节点的 id 和在构建时渲染的路由进行更新。

.dojorc

{
	"build-app": {
		"build-time-render": {
			"root": "app",
			"paths": [
				"#home",
				{
					"path": "#comments/9999",
					"match": ["#comments/.*"]
				}
			]
		}
	}
}

此配置描述了两个路由。一个 home 路由和一个更复杂的 comments 路由。comments 路由是一个更复杂的路由,具有参数数据。match 用于确保为此路由创建的构建时 HTML 应用于与正则表达式匹配的任何路由。

BTR 为构建期间渲染的每个路径在 ./output/info/screenshots 项目目录中生成屏幕截图。

历史管理器

构建时渲染支持使用 @dojo/framework/routing/history/HashHistory@dojo/framework/routing/history/StateHistory 历史管理器的应用程序。使用 HashHistory 时,请确保所有路径都以 # 字符为前缀。

build-time-render 特性标志

构建时渲染公开了一个 build-time-render 特性标志,可用于跳过无法在构建时执行的功能。这可用于避免对外部系统进行 fetch 调用,而是提供可用于创建初始渲染的静态数据。

if (has('build-time-render')) {
	const response = await fetch(/* remote JSON */);
	return response.json();
} else {
	return Promise.resolve({
		/* predefined Object */
	});
}

Dojo 块

Dojo 提供了一个块系统,该系统可以在 Node.js 中执行代码,作为构建时渲染过程的一部分。执行结果将写入缓存,然后可以在浏览器中以相同的方式透明地使用。这为使用可能在浏览器中不可用或性能不佳的操作提供了新的机会。

例如,Dojo 块模块可以读取一组 Markdown 文件,将它们转换为 VNode,并使它们可用于在应用程序中渲染,所有这些都在构建时完成。然后,此 Dojo 块模块的结果被缓存到应用程序捆绑包中,以便在浏览器中运行时使用。

Dojo 块模块的使用方式与 Dojo 小部件中的任何中间件或元数据相同。为了使 Dojo 构建系统能够识别和运行块模块,必须满足三个要求

  1. 模块必须具有 .block 后缀,例如 src/readFile.block.ts
  2. 块只能有一个默认导出
  3. 块的返回值(来自 promise 解析或作为立即返回值)必须可序列化为 json

除了这些要求之外,不需要任何配置或替代创作模式。

例如,块模块可以读取文本文件并将内容返回到应用程序。

src/readFile.block.ts

import * as fs from 'fs';
import { resolve } from 'path';

export default (path: string) => {
	path = resolve(__dirname, path);
	return fs.readFileSync(path, 'utf8');
};

src/widgets/MyBlockWidget.tsx

import { create, tsx } from '@dojo/framework/core/vdom';
import block from '@dojo/framework/core/middleware/block';

import readFile from '../readFile.block';

const factory = create({ block });

export default factory(function MyBlockWidget({ middleware: { block } }) {
	const message = block(readFile)('../content/hello-dojo-blocks.txt');
	return <div>{message}</div>;
});

此小部件在构建时运行 src/readFile.block.ts 模块以读取给定文件的内容,以用于小部件的渲染输出。