RenderContext 是 Esmx 框架中的核心类,负责管理服务端渲染(SSR)的完整生命周期。它提供了一套完整的 API 来处理渲染上下文、资源管理、状态同步等关键任务:
服务端渲染处理函数的类型定义。
type ServerRenderHandle = (rc: RenderContext) => Promise<void>;服务端渲染处理函数是一个异步或同步函数,接收 RenderContext 实例作为参数,用于处理服务端渲染逻辑。
export default async (rc: RenderContext) => {
const app = createApp();
const html = await renderToString(app);
rc.html = html;
};
export const simple = async (rc: RenderContext) => {
rc.html = '<h1>Hello World</h1>';
};渲染过程中收集的资源文件列表的类型定义。
interface RenderFiles {
js: string[];
css: string[];
modulepreload: string[];
resources: string[];
}rc.files = {
js: [
'/assets/entry-client.js',
'/assets/vendor.js'
],
css: [
'/assets/main.css',
'/assets/vendor.css'
],
modulepreload: [
'/assets/Home.js',
'/assets/About.js'
],
resources: [
'/assets/logo.png',
'/assets/font.woff2'
]
};定义导入映射(Import Maps)的生成模式。
type ImportmapMode = 'inline' | 'js';inline: 将 importmap 内容直接内联到 HTML 中,适用于以下场景:
js: 将 importmap 内容生成为独立的 JS 文件,适用于以下场景:
渲染上下文类,负责服务端渲染(SSR)过程中的资源管理和 HTML 生成。
定义渲染上下文的配置选项。
interface RenderContextOptions {
base?: string
entryName?: string
params?: Record<string, any>
importmapMode?: ImportmapMode
}string''静态资源的基础路径。
string'default'服务端渲染入口函数名称。用于指定服务端渲染时使用的入口函数,当一个模块导出多个渲染函数时使用。
export const mobile = async (rc: RenderContext) => {
};
export const desktop = async (rc: RenderContext) => {
};Record<string, any>{}渲染参数。可以传递任意类型的参数给渲染函数,常用于传递请求信息(URL、query 参数等)。
const rc = await esmx.render({
params: {
url: req.url,
lang: 'zh-CN',
theme: 'dark'
}
});'inline' | 'js''inline'导入映射(Import Maps)的生成模式:
inline: 将 importmap 内容直接内联到 HTML 中js: 将 importmap 内容生成为独立的 JS 文件EsmxtrueEsmx 实例引用。用于访问框架核心功能和配置信息。
string | nullnull重定向地址。设置后,服务端可以根据此值进行 HTTP 重定向,常用于登录验证、权限控制等场景。
export default async (rc: RenderContext) => {
if (!isLoggedIn()) {
rc.redirect = '/login';
rc.status = 302;
return;
}
};
export default async (rc: RenderContext) => {
if (!hasPermission()) {
rc.redirect = '/403';
rc.status = 403;
return;
}
};number | nullnullHTTP 响应状态码。可以设置任意有效的 HTTP 状态码,常用于错误处理、重定向等场景。
export default async (rc: RenderContext) => {
const page = await findPage(rc.params.url);
if (!page) {
rc.status = 404;
return;
}
};
export default async (rc: RenderContext) => {
if (needMaintenance()) {
rc.redirect = '/maintenance';
rc.status = 307;
return;
}
};string''HTML 内容。用于设置和获取最终生成的 HTML 内容,在设置时自动处理基础路径占位符。
export default async (rc: RenderContext) => {
rc.html = `
<!DOCTYPE html>
<html>
<head>
${rc.preload()}
${rc.css()}
</head>
<body>
<div id="app">Hello World</div>
${rc.importmap()}
${rc.moduleEntry()}
${rc.modulePreload()}
</body>
</html>
`;
};
const rc = await esmx.render({
base: '/app',
params: { url: req.url }
});
stringtrue''静态资源的基础路径。所有静态资源(JS、CSS、图片等)都会基于此路径加载,支持运行时动态配置。
const rc = await esmx.render({
base: '/esmx',
params: { url: req.url }
});
const rc = await esmx.render({
base: '/cn',
params: { lang: 'zh-CN' }
});
const rc = await esmx.render({
base: '/app1',
params: { appId: 1 }
});stringtrue'default'服务端渲染入口函数名称。用于从 entry.server.ts 中选择要使用的渲染函数。
export default async (rc: RenderContext) => {
};
export const mobile = async (rc: RenderContext) => {
};
export const desktop = async (rc: RenderContext) => {
};
const rc = await esmx.render({
entryName: isMobile ? 'mobile' : 'desktop',
params: { url: req.url }
});Record<string, any>true{}渲染参数。可以在服务端渲染过程中传递和访问参数,常用于传递请求信息、页面配置等。
const rc = await esmx.render({
params: {
url: req.url,
lang: 'zh-CN'
}
});
const rc = await esmx.render({
params: {
theme: 'dark',
layout: 'sidebar'
}
});
const rc = await esmx.render({
params: {
apiBaseUrl: process.env.API_BASE_URL,
version: '1.0.0'
}
});Set<ImportMeta>模块依赖收集集合。在组件渲染过程中自动追踪和记录模块依赖,只收集当前页面渲染时真正使用到的资源。
const renderToString = (app: any, context: { importMetaSet: Set<ImportMeta> }) => {
return '<div id="app">Hello World</div>';
};
const app = createApp();
const html = await renderToString(app, {
importMetaSet: rc.importMetaSet
});RenderFiles资源文件列表:
await rc.commit();
rc.html = `
<!DOCTYPE html>
<html>
<head>
${rc.preload()}
${rc.css()}
</head>
<body>
${html}
${rc.importmap()}
${rc.moduleEntry()}
${rc.modulePreload()}
</body>
</html>
`;'inline' | 'js''inline'导入映射的生成模式:
inline: 将 importmap 内容直接内联到 HTML 中js: 将 importmap 内容生成为独立的 JS 文件input: any - 需要序列化的数据options?: serialize.SerializeJSOptions - 序列化选项string将 JavaScript 对象序列化为字符串。用于在服务端渲染过程中序列化状态数据,确保数据可以安全地嵌入到 HTML 中。
const state = {
user: { id: 1, name: 'Alice' },
timestamp: new Date()
};
rc.html = `
<script>
window.__INITIAL_STATE__ = ${rc.serialize(state)};
</script>
`;varName: string - 变量名data: Record<string, any> - 状态数据string将状态数据序列化并注入到 HTML 中。使用安全的序列化方法处理数据,支持复杂的数据结构。
const userInfo = {
id: 1,
name: 'John',
roles: ['admin']
};
rc.html = `
<head>
${rc.state('__USER__', userInfo)}
</head>
`;Promise<void>提交依赖收集并更新资源列表。从 importMetaSet 中收集所有使用到的模块,基于 manifest 文件解析每个模块的具体资源。
const html = await renderToString(app, {
importMetaSet: rc.importMetaSet
});
await rc.commit();string生成资源预加载标签。用于预加载 CSS 和 JavaScript 资源,支持优先级配置,自动处理基础路径。
rc.html = `
<!DOCTYPE html>
<html>
<head>
${rc.preload()}
${rc.css()}
</head>
<body>
${html}
${rc.importmap()}
${rc.moduleEntry()}
${rc.modulePreload()}
</body>
</html>
`;string生成 CSS 样式表标签。注入收集到的 CSS 文件,确保样式表按正确顺序加载。
rc.html = `
<head>
${rc.css()}
</head>
`;string生成导入映射标签。根据 importmapMode 配置生成内联或外部导入映射。
rc.html = `
<head>
${rc.importmap()}
</head>
`;string生成客户端入口模块标签。注入客户端入口模块,必须在 importmap 之后执行。
rc.html = `
<body>
${html}
${rc.importmap()}
${rc.moduleEntry()}
</body>
`;string生成模块预加载标签。预加载收集到的 ESM 模块,优化首屏加载性能。
rc.html = `
<body>
${html}
${rc.importmap()}
${rc.moduleEntry()}
${rc.modulePreload()}
</body>
`;