HTML
This tutorial will guide you through building an HTML SSR application from scratch using the Esmx framework. We'll demonstrate how to create a server-side rendered application through a complete example.
Project Structure
First, let's understand the basic project structure:
1.
2├── package.json # Project configuration file defining dependencies and scripts
3├── tsconfig.json # TypeScript configuration file with compilation options
4└── src # Source code directory
5 ├── app.ts # Main application component defining page structure and logic
6 ├── create-app.ts # Application instance factory for initialization
7 ├── entry.client.ts # Client entry file handling browser-side rendering
8 ├── entry.node.ts # Node.js server entry file for dev environment setup
9 └── entry.server.ts # Server entry file handling SSR rendering logic
Project Configuration
package.json
Create the package.json
file to configure project dependencies and scripts:
package.json
1{
2 "name": "ssr-demo-html",
3 "version": "1.0.0",
4 "type": "module",
5 "private": true,
6 "scripts": {
7 "dev": "esmx dev",
8 "build": "npm run build:dts && npm run build:ssr",
9 "build:ssr": "esmx build",
10 "preview": "esmx preview",
11 "start": "NODE_ENV=production node dist/index.mjs",
12 "build:dts": "tsc --declaration --emitDeclarationOnly --outDir dist/src"
13 },
14 "dependencies": {
15 "@esmx/core": "*"
16 },
17 "devDependencies": {
18 "@esmx/rspack": "*",
19 "@types/node": "22.8.6",
20 "typescript": "^5.7.3"
21 }
22}
After creating the package.json
file, install project dependencies using any of these commands:
1pnpm install
2# or
3yarn install
4# or
5npm install
This will install all required dependencies including TypeScript and SSR-related packages.
tsconfig.json
Create the tsconfig.json
file to configure TypeScript compilation:
tsconfig.json
1{
2 "compilerOptions": {
3 "module": "ESNext",
4 "moduleResolution": "node",
5 "isolatedModules": true,
6 "resolveJsonModule": true,
7
8 "target": "ESNext",
9 "lib": ["ESNext", "DOM"],
10
11 "strict": true,
12 "skipLibCheck": true,
13 "types": ["@types/node"],
14
15 "experimentalDecorators": true,
16 "allowSyntheticDefaultImports": true,
17
18 "baseUrl": ".",
19 "paths": {
20 "ssr-demo-html/src/*": ["./src/*"],
21 "ssr-demo-html/*": ["./*"]
22 }
23 },
24 "include": ["src"],
25 "exclude": ["dist", "node_modules"]
26}
Source Code Structure
app.ts
Create the main application component src/app.ts
implementing page structure and interaction logic:
src/app.ts
1/**
2 * @file Example component
3 * @description Demonstrates a page title with auto-updating time, showcasing basic Esmx framework functionality
4 */
5
6export default class App {
7 /**
8 * Current time in ISO format
9 * @type {string}
10 */
11 public time = '';
12
13 /**
14 * Creates application instance
15 * @param {SsrContext} [ssrContext] - Server context containing import metadata collection
16 */
17 public constructor(public ssrContext?: SsrContext) {
18 // No additional initialization needed in constructor
19 }
20
21 /**
22 * Renders page content
23 * @returns {string} Returns page HTML structure
24 */
25 public render(): string {
26 // Ensure proper import metadata collection in server environment
27 if (this.ssrContext) {
28 this.ssrContext.importMetaSet.add(import.meta);
29 }
30
31 return `
32 <div id="app">
33 <h1><a href="https://www.esmnext.com/guide/frameworks/html.html" target="_blank">Esmx Quick Start</a></h1>
34 <time datetime="${this.time}">${this.time}</time>
35 </div>
36 `;
37 }
38
39 /**
40 * Client-side initialization
41 * @throws {Error} Throws error when time display element is not found
42 */
43 public onClient(): void {
44 // Get time display element
45 const time = document.querySelector('#app time');
46 if (!time) {
47 throw new Error('Time display element not found');
48 }
49
50 // Set interval to update time every second
51 setInterval(() => {
52 this.time = new Date().toISOString();
53 time.setAttribute('datetime', this.time);
54 time.textContent = this.time;
55 }, 1000);
56 }
57
58 /**
59 * Server-side initialization
60 */
61 public onServer(): void {
62 this.time = new Date().toISOString();
63 }
64}
65
66/**
67 * Server context interface
68 * @interface
69 */
70export interface SsrContext {
71 /**
72 * Import metadata collection
73 * @type {Set<ImportMeta>}
74 */
75 importMetaSet: Set<ImportMeta>;
76}
create-app.ts
Create src/create-app.ts
file responsible for application instance creation:
src/create-app.ts
1/**
2 * @file Application instance creation
3 * @description Responsible for creating and configuring application instances
4 */
5
6import App from './app';
7
8export function createApp() {
9 const app = new App();
10 return {
11 app
12 };
13}
entry.client.ts
Create client entry file src/entry.client.ts
:
src/entry.client.ts
1/**
2 * @file Client entry file
3 * @description Handles client-side interaction logic and dynamic updates
4 */
5
6import { createApp } from './create-app';
7
8// Create application instance and initialize
9const { app } = createApp();
10app.onClient();
entry.node.ts
Create entry.node.ts
file for development environment configuration:
src/entry.node.ts
1/**
2 * @file Node.js server entry file
3 * @description Configures development environment and server startup, providing SSR runtime
4 */
5
6import http from 'node:http';
7import type { EsmxOptions } from '@esmx/core';
8
9export default {
10 /**
11 * Configures development environment application creator
12 * @description Creates and configures Rspack application instance for development builds and HMR
13 * @param esmx Esmx framework instance providing core functionality
14 * @returns Configured Rspack application instance supporting HMR and live preview
15 */
16 async devApp(esmx) {
17 return import('@esmx/rspack').then((m) =>
18 m.createRspackHtmlApp(esmx, {
19 config(context) {
20 // Customize Rspack compilation configuration here
21 }
22 })
23 );
24 },
25
26 /**
27 * Configures and starts HTTP server
28 * @description Creates HTTP server instance with Esmx middleware for SSR requests
29 * @param esmx Esmx framework instance providing middleware and rendering
30 */
31 async server(esmx) {
32 const server = http.createServer((req, res) => {
33 // Process requests with Esmx middleware
34 esmx.middleware(req, res, async () => {
35 // Perform server-side rendering
36 const rc = await esmx.render({
37 params: { url: req.url }
38 });
39 res.end(rc.html);
40 });
41 });
42
43 server.listen(3000, () => {
44 console.log('Server started: http://localhost:3000');
45 });
46 }
47} satisfies EsmxOptions;
This file serves as the entry point for development environment configuration and server startup, containing two core functions:
devApp
: Creates and configures Rspack application instance for development with HMR support.
server
: Creates and configures HTTP server with Esmx middleware for SSR requests.
entry.server.ts
Create server-side rendering entry file src/entry.server.ts
:
src/entry.server.ts
1/**
2 * @file Server-side rendering entry file
3 * @description Handles SSR process, HTML generation and resource injection
4 */
5
6import type { RenderContext } from '@esmx/core';
7import type App from './app';
8import type { SsrContext } from './app';
9import { createApp } from './create-app';
10
11// Encapsulates page content generation logic
12const renderToString = (app: App, ssrContext: SsrContext): string => {
13 // Inject server context into application instance
14 app.ssrContext = ssrContext;
15 // Initialize server-side
16 app.onServer();
17
18 // Generate page content
19 return app.render();
20};
21
22export default async (rc: RenderContext) => {
23 // Create application instance
24 const { app } = createApp();
25 // Generate page content using renderToString
26 const html = renderToString(app, {
27 importMetaSet: rc.importMetaSet
28 });
29
30 // Commit dependency collection to ensure all required resources are loaded
31 await rc.commit();
32
33 // Generate complete HTML structure
34 rc.html = `<!DOCTYPE html>
35<html lang="en">
36<head>
37 ${rc.preload()}
38 <title>Esmx Quick Start</title>
39 ${rc.css()}
40</head>
41<body>
42 ${html}
43 ${rc.importmap()}
44 ${rc.moduleEntry()}
45 ${rc.modulePreload()}
46</body>
47</html>
48`;
49};
Running the Project
After completing all configurations, use these commands to run the project:
- Development mode:
- Build project:
- Production environment:
Congratulations! You've successfully created an HTML SSR application using Esmx framework. Visit http://localhost:3000 to see the result.