RenderContext
RenderContext is the core class in the Esmx framework, responsible for managing the complete lifecycle of server-side rendering (SSR). It provides a comprehensive API for handling rendering context, resource management, state synchronization, and other critical tasks:
- Rendering Control: Manages server-side rendering workflows, supporting multi-entry rendering, conditional rendering, and other scenarios
- Resource Management: Intelligently collects and injects static resources like JS and CSS to optimize loading performance
- State Synchronization: Handles server-side state serialization to ensure proper client-side hydration
- Routing Control: Supports advanced features like server-side redirects and status code configuration
Type Definitions
ServerRenderHandle
Type definition for server-side rendering handler functions.
1type ServerRenderHandle = (rc: RenderContext) => Promise<void> | void;
A server-side rendering handler is an async or sync function that receives a RenderContext instance as parameter for processing SSR logic.
entry.node.ts
1// 1. Async handler
2export default async (rc: RenderContext) => {
3 const app = createApp();
4 const html = await renderToString(app);
5 rc.html = html;
6};
7
8// 2. Sync handler
9export const simple = (rc: RenderContext) => {
10 rc.html = '<h1>Hello World</h1>';
11};
RenderFiles
Type definition for resource file lists collected during rendering.
1interface RenderFiles {
2 js: string[];
3 css: string[];
4 modulepreload: string[];
5 resources: string[];
6}
- js: JavaScript file list
- css: Stylesheet file list
- modulepreload: List of ESM modules requiring preloading
- resources: Other resource file list (images, fonts, etc.)
1// Example resource file list
2rc.files = {
3 js: [
4 '/assets/entry-client.js',
5 '/assets/vendor.js'
6 ],
7 css: [
8 '/assets/main.css',
9 '/assets/vendor.css'
10 ],
11 modulepreload: [
12 '/assets/Home.js',
13 '/assets/About.js'
14 ],
15 resources: [
16 '/assets/logo.png',
17 '/assets/font.woff2'
18 ]
19};
ImportmapMode
Defines importmap generation modes.
1type ImportmapMode = 'inline' | 'js';
inline
: Inlines importmap content directly into HTML, suitable for:
- Reducing HTTP requests
- Smaller importmap content
- Critical first-load performance requirements
js
: Generates importmap as standalone JS file, suitable for:
- Larger importmap content
- Leveraging browser caching
- Shared importmaps across multiple pages
The rendering context class responsible for resource management and HTML generation during server-side rendering (SSR).
Instance Options
Configuration options for RenderContext.
1interface RenderContextOptions {
2 base?: string
3 entryName?: string
4 params?: Record<string, any>
5 importmapMode?: ImportmapMode
6}
base
Base path for static resources.
- All static resources (JS, CSS, images, etc.) will load relative to this path
- Supports runtime dynamic configuration without rebuild
- Commonly used for multilingual sites, micro-frontend applications, etc.
entryName
- Type:
string
- Default:
'default'
Server-side rendering entry function name. Specifies which entry function to use when a module exports multiple render functions.
src/entry.server.ts
1export const mobile = async (rc: RenderContext) => {
2 // Mobile rendering logic
3};
4
5export const desktop = async (rc: RenderContext) => {
6 // Desktop rendering logic
7};
params
- Type:
Record<string, any>
- Default:
{}
Rendering parameters. Can pass arbitrary parameters to render functions, commonly used for request information (URL, query params, etc.).
1const rc = await esmx.render({
2 params: {
3 url: req.url,
4 lang: 'zh-CN',
5 theme: 'dark'
6 }
7});
importmapMode
- Type:
'inline' | 'js'
- Default:
'inline'
Import Map generation mode:
Instance Properties
esmx
- Type:
Esmx
- Readonly:
true
Reference to the Esmx instance. Used to access core framework functionality and configuration.
redirect
- Type:
string | null
- Default:
null
Redirect URL. When set, the server can perform HTTP redirects based on this value, commonly used for login verification, permission control, etc.
entry.node.ts
1// Login verification example
2export default async (rc: RenderContext) => {
3 if (!isLoggedIn()) {
4 rc.redirect = '/login';
5 rc.status = 302;
6 return;
7 }
8 // Continue rendering...
9};
10
11// Permission control example
12export default async (rc: RenderContext) => {
13 if (!hasPermission()) {
14 rc.redirect = '/403';
15 rc.status = 403;
16 return;
17 }
18 // Continue rendering...
19};
status
- Type:
number | null
- Default:
null
HTTP response status code. Can set any valid HTTP status code, commonly used for error handling, redirects, etc.
entry.node.ts
1// 404 error handling example
2export default async (rc: RenderContext) => {
3 const page = await findPage(rc.params.url);
4 if (!page) {
5 rc.status = 404;
6 // Render 404 page...
7 return;
8 }
9 // Continue rendering...
10};
11
12// Temporary redirect example
13export default async (rc: RenderContext) => {
14 if (needMaintenance()) {
15 rc.redirect = '/maintenance';
16 rc.status = 307; // Temporary redirect preserving request method
17 return;
18 }
19 // Continue rendering...
20};
html
HTML content. Used to set and get final generated HTML content, automatically processes base path placeholders when setting.
entry.node.ts
1// Basic usage
2export default async (rc: RenderContext) => {
3 // Set HTML content
4 rc.html = `
5 <!DOCTYPE html>
6 <html>
7 <head>
8 ${rc.preload()}
9 ${rc.css()}
10 </head>
11 <body>
12 <div id="app">Hello World</div>
13 ${rc.importmap()}
14 ${rc.moduleEntry()}
15 ${rc.modulePreload()}
16 </body>
17 </html>
18 `;
19};
20
21// Dynamic base path
22const rc = await esmx.render({
23 base: '/app', // Set base path
24 params: { url: req.url }
25});
26
27// Placeholders in HTML are automatically replaced:
28// [[[___GEZ_DYNAMIC_BASE___]]]/your-app-name/css/style.css
29// Becomes:
30// /app/your-app-name/css/style.css
base
- Type:
string
- Readonly:
true
- Default:
''
Base path for static resources. All static resources (JS, CSS, images, etc.) load relative to this path, supports runtime dynamic configuration.
1// Basic usage
2const rc = await esmx.render({
3 base: '/esmx', // Set base path
4 params: { url: req.url }
5});
6
7// Multilingual site example
8const rc = await esmx.render({
9 base: '/cn', // Chinese site
10 params: { lang: 'zh-CN' }
11});
12
13// Micro-frontend example
14const rc = await esmx.render({
15 base: '/app1', // Sub-application 1
16 params: { appId: 1 }
17});
entryName
- Type:
string
- Readonly:
true
- Default:
'default'
Server-side rendering entry function name. Used to select which render function to use from entry.server.ts.
entry.node.ts
1// Default entry function
2export default async (rc: RenderContext) => {
3 // Default rendering logic
4};
5
6// Multiple entry functions
7export const mobile = async (rc: RenderContext) => {
8 // Mobile rendering logic
9};
10
11export const desktop = async (rc: RenderContext) => {
12 // Desktop rendering logic
13};
14
15// Select entry function by device type
16const rc = await esmx.render({
17 entryName: isMobile ? 'mobile' : 'desktop',
18 params: { url: req.url }
19});
params
- Type:
Record<string, any>
- Readonly:
true
- Default:
{}
Rendering parameters. Can pass and access parameters during SSR, commonly used for request information, page configuration, etc.
1// Basic usage - passing URL and language settings
2const rc = await esmx.render({
3 params: {
4 url: req.url,
5 lang: 'zh-CN'
6 }
7});
8
9// Page configuration - setting theme and layout
10const rc = await esmx.render({
11 params: {
12 theme: 'dark',
13 layout: 'sidebar'
14 }
15});
16
17// Environment configuration - injecting API address
18const rc = await esmx.render({
19 params: {
20 apiBaseUrl: process.env.API_BASE_URL,
21 version: '1.0.0'
22 }
23});
importMetaSet
Module dependency collection set. Automatically tracks and records module dependencies during component rendering, only collecting resources actually used during current page rendering.
1// Basic usage
2const renderToString = (app: any, context: { importMetaSet: Set<ImportMeta> }) => {
3 // Automatically collects module dependencies during rendering
4 // Framework automatically calls context.importMetaSet.add(import.meta) during component rendering
5 // Developers don't need to manually handle dependency collection
6 return '<div id="app">Hello World</div>';
7};
8
9// Usage example
10const app = createApp();
11const html = await renderToString(app, {
12 importMetaSet: rc.importMetaSet
13});
files
Resource file list:
- js: JavaScript file list
- css: Stylesheet file list
- modulepreload: List of ESM modules requiring preloading
- resources: Other resource file list (images, fonts, etc.)
1// Resource collection
2await rc.commit();
3
4// Resource injection
5rc.html = `
6 <!DOCTYPE html>
7 <html>
8 <head>
9 <!-- Preload resources -->
10 ${rc.preload()}
11 <!-- Inject stylesheets -->
12 ${rc.css()}
13 </head>
14 <body>
15 ${html}
16 ${rc.importmap()}
17 ${rc.moduleEntry()}
18 ${rc.modulePreload()}
19 </body>
20 </html>
21`;
importmapMode
- Type:
'inline' | 'js'
- Default:
'inline'
Import Map generation mode:
Instance Methods
serialize()
- Parameters:
input: any
- Data to serialize
options?: serialize.SerializeJSOptions
- Serialization options
- Returns:
string
Serializes JavaScript objects to strings. Used during SSR to serialize state data for safe embedding in HTML.
1const state = {
2 user: { id: 1, name: 'Alice' },
3 timestamp: new Date()
4};
5
6rc.html = `
7 <script>
8 window.__INITIAL_STATE__ = ${rc.serialize(state)};
9 </script>
10`;
state()
- Parameters:
varName: string
- Variable name
data: Record<string, any>
- State data
- Returns:
string
Serializes and injects state data into HTML. Uses safe serialization methods supporting complex data structures.
1const userInfo = {
2 id: 1,
3 name: 'John',
4 roles: ['admin']
5};
6
7rc.html = `
8 <head>
9 ${rc.state('__USER__', userInfo)}
10 </head>
11`;
commit()
Commits dependency collection and updates resource list. Collects all used modules from importMetaSet, resolves each module's specific resources based on manifest file.
1// Render and commit dependencies
2const html = await renderToString(app, {
3 importMetaSet: rc.importMetaSet
4});
5
6// Commit dependency collection
7await rc.commit();
preload()
Generates resource preload tags. Preloads CSS and JavaScript resources with priority configuration, automatically handles base paths.
1rc.html = `
2 <!DOCTYPE html>
3 <html>
4 <head>
5 ${rc.preload()}
6 ${rc.css()} <!-- Inject stylesheets -->
7 </head>
8 <body>
9 ${html}
10 ${rc.importmap()}
11 ${rc.moduleEntry()}
12 ${rc.modulePreload()}
13 </body>
14 </html>
15`;
css()
Generates CSS stylesheet tags. Injects collected CSS files ensuring proper loading order.
1rc.html = `
2 <head>
3 ${rc.css()} <!-- Inject all collected stylesheets -->
4 </head>
5`;
importmap()
Generates import map tags. Generates inline or external import maps based on importmapMode configuration.
1rc.html = `
2 <head>
3 ${rc.importmap()} <!-- Inject import map -->
4 </head>
5`;
moduleEntry()
Generates client entry module tags. Injects client entry module, must execute after importmap.
1rc.html = `
2 <body>
3 ${html}
4 ${rc.importmap()}
5 ${rc.moduleEntry()} <!-- Inject client entry module -->
6 </body>
7`;
modulePreload()
Generates module preload tags. Preloads collected ESM modules to optimize first-load performance.
1rc.html = `
2 <body>
3 ${html}
4 ${rc.importmap()}
5 ${rc.moduleEntry()}
6 ${rc.modulePreload()} <!-- Preload module dependencies -->
7 </body>
8`;