@esmx/core 3.0.0-rc.60 → 3.0.0-rc.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/README.zh-CN.md +4 -4
- package/dist/app.d.ts +27 -27
- package/dist/core.d.ts +274 -272
- package/dist/core.mjs +235 -232
- package/dist/pack-config.d.ts +92 -92
- package/dist/render-context.d.ts +465 -465
- package/dist/render-context.mjs +338 -338
- package/dist/utils/cache.d.ts +15 -15
- package/dist/utils/import-map.d.ts +31 -1
- package/dist/utils/import-map.mjs +18 -0
- package/dist/utils/import-map.test.mjs +577 -1
- package/dist/utils/middleware.d.ts +19 -19
- package/dist/utils/static-import-lexer.d.ts +12 -12
- package/dist/utils/static-import-lexer.mjs +1 -1
- package/package.json +3 -3
- package/src/app.ts +34 -34
- package/src/core.ts +320 -317
- package/src/pack-config.ts +92 -92
- package/src/render-context.ts +465 -465
- package/src/utils/cache.ts +15 -15
- package/src/utils/import-map.test.ts +713 -1
- package/src/utils/import-map.ts +53 -1
- package/src/utils/middleware.ts +19 -19
- package/src/utils/static-import-lexer.ts +18 -18
package/dist/render-context.mjs
CHANGED
|
@@ -3,35 +3,35 @@ import serialize from "serialize-javascript";
|
|
|
3
3
|
export class RenderContext {
|
|
4
4
|
esmx;
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Redirect address
|
|
7
7
|
* @description
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
10
|
-
* -
|
|
8
|
+
* - Defaults to null, indicating no redirect
|
|
9
|
+
* - When set, the server can perform HTTP redirection based on this value
|
|
10
|
+
* - Commonly used for scenarios like login verification, permission control, etc.
|
|
11
11
|
*
|
|
12
12
|
* @example
|
|
13
13
|
* ```ts
|
|
14
|
-
* // 1.
|
|
14
|
+
* // 1. Login verification example
|
|
15
15
|
* export default async (rc: RenderContext) => {
|
|
16
16
|
* if (!isLoggedIn()) {
|
|
17
17
|
* rc.redirect = '/login';
|
|
18
18
|
* rc.status = 302;
|
|
19
19
|
* return;
|
|
20
20
|
* }
|
|
21
|
-
* //
|
|
21
|
+
* // Continue rendering page...
|
|
22
22
|
* };
|
|
23
23
|
*
|
|
24
|
-
* // 2.
|
|
24
|
+
* // 2. Permission control example
|
|
25
25
|
* export default async (rc: RenderContext) => {
|
|
26
26
|
* if (!hasPermission()) {
|
|
27
27
|
* rc.redirect = '/403';
|
|
28
28
|
* rc.status = 403;
|
|
29
29
|
* return;
|
|
30
30
|
* }
|
|
31
|
-
* //
|
|
31
|
+
* // Continue rendering page...
|
|
32
32
|
* };
|
|
33
33
|
*
|
|
34
|
-
* // 3.
|
|
34
|
+
* // 3. Server-side processing example
|
|
35
35
|
* app.use(async (req, res) => {
|
|
36
36
|
* const rc = await esmx.render({
|
|
37
37
|
* params: {
|
|
@@ -39,7 +39,7 @@ export class RenderContext {
|
|
|
39
39
|
* }
|
|
40
40
|
* });
|
|
41
41
|
*
|
|
42
|
-
* //
|
|
42
|
+
* // Handle redirect
|
|
43
43
|
* if (rc.redirect) {
|
|
44
44
|
* res.statusCode = rc.status || 302;
|
|
45
45
|
* res.setHeader('Location', rc.redirect);
|
|
@@ -47,49 +47,49 @@ export class RenderContext {
|
|
|
47
47
|
* return;
|
|
48
48
|
* }
|
|
49
49
|
*
|
|
50
|
-
* //
|
|
50
|
+
* // Set status code
|
|
51
51
|
* if (rc.status) {
|
|
52
52
|
* res.statusCode = rc.status;
|
|
53
53
|
* }
|
|
54
54
|
*
|
|
55
|
-
* //
|
|
55
|
+
* // Respond with HTML content
|
|
56
56
|
* res.end(rc.html);
|
|
57
57
|
* });
|
|
58
58
|
* ```
|
|
59
59
|
*/
|
|
60
60
|
redirect = null;
|
|
61
61
|
/**
|
|
62
|
-
* HTTP
|
|
62
|
+
* HTTP response status code
|
|
63
63
|
* @description
|
|
64
|
-
* -
|
|
65
|
-
* -
|
|
66
|
-
* -
|
|
67
|
-
* -
|
|
64
|
+
* - Defaults to null, indicating use of 200 status code
|
|
65
|
+
* - Can set any valid HTTP status code
|
|
66
|
+
* - Commonly used for scenarios like error handling, redirection, etc.
|
|
67
|
+
* - Usually used in conjunction with the redirect property
|
|
68
68
|
*
|
|
69
69
|
* @example
|
|
70
70
|
* ```ts
|
|
71
|
-
* // 1. 404
|
|
71
|
+
* // 1. 404 error handling example
|
|
72
72
|
* export default async (rc: RenderContext) => {
|
|
73
73
|
* const page = await findPage(rc.params.url);
|
|
74
74
|
* if (!page) {
|
|
75
75
|
* rc.status = 404;
|
|
76
|
-
* //
|
|
76
|
+
* // Render 404 page...
|
|
77
77
|
* return;
|
|
78
78
|
* }
|
|
79
|
-
* //
|
|
79
|
+
* // Continue rendering page...
|
|
80
80
|
* };
|
|
81
81
|
*
|
|
82
|
-
* // 2.
|
|
82
|
+
* // 2. Temporary redirect example
|
|
83
83
|
* export default async (rc: RenderContext) => {
|
|
84
84
|
* if (needMaintenance()) {
|
|
85
85
|
* rc.redirect = '/maintenance';
|
|
86
|
-
* rc.status = 307; //
|
|
86
|
+
* rc.status = 307; // Temporary redirect, keep request method unchanged
|
|
87
87
|
* return;
|
|
88
88
|
* }
|
|
89
|
-
* //
|
|
89
|
+
* // Continue rendering page...
|
|
90
90
|
* };
|
|
91
91
|
*
|
|
92
|
-
* // 3.
|
|
92
|
+
* // 3. Server-side processing example
|
|
93
93
|
* app.use(async (req, res) => {
|
|
94
94
|
* const rc = await esmx.render({
|
|
95
95
|
* params: {
|
|
@@ -97,7 +97,7 @@ export class RenderContext {
|
|
|
97
97
|
* }
|
|
98
98
|
* });
|
|
99
99
|
*
|
|
100
|
-
* //
|
|
100
|
+
* // Handle redirect
|
|
101
101
|
* if (rc.redirect) {
|
|
102
102
|
* res.statusCode = rc.status || 302;
|
|
103
103
|
* res.setHeader('Location', rc.redirect);
|
|
@@ -105,12 +105,12 @@ export class RenderContext {
|
|
|
105
105
|
* return;
|
|
106
106
|
* }
|
|
107
107
|
*
|
|
108
|
-
* //
|
|
108
|
+
* // Set status code
|
|
109
109
|
* if (rc.status) {
|
|
110
110
|
* res.statusCode = rc.status;
|
|
111
111
|
* }
|
|
112
112
|
*
|
|
113
|
-
* //
|
|
113
|
+
* // Respond with HTML content
|
|
114
114
|
* res.end(rc.html);
|
|
115
115
|
* });
|
|
116
116
|
* ```
|
|
@@ -118,80 +118,80 @@ export class RenderContext {
|
|
|
118
118
|
status = null;
|
|
119
119
|
_html = "";
|
|
120
120
|
/**
|
|
121
|
-
*
|
|
121
|
+
* Base path for static assets
|
|
122
122
|
* @description
|
|
123
|
-
* base
|
|
123
|
+
* The base property is used to control the loading path of static assets and is the core of Esmx framework's dynamic base path configuration:
|
|
124
124
|
*
|
|
125
|
-
* 1.
|
|
126
|
-
* -
|
|
127
|
-
* -
|
|
128
|
-
* -
|
|
125
|
+
* 1. **Build-time Processing**
|
|
126
|
+
* - Static asset paths are marked with special placeholders: `[[[___ESMX_DYNAMIC_BASE___]]]/your-app-name/`
|
|
127
|
+
* - Placeholders are injected into all static asset reference paths
|
|
128
|
+
* - Supports various static assets like CSS, JavaScript, images, etc.
|
|
129
129
|
*
|
|
130
|
-
* 2.
|
|
131
|
-
* -
|
|
132
|
-
* - RenderContext
|
|
130
|
+
* 2. **Runtime Replacement**
|
|
131
|
+
* - Set the actual base path through the `base` parameter of `esmx.render()`
|
|
132
|
+
* - RenderContext automatically replaces placeholders in HTML with actual paths
|
|
133
133
|
*
|
|
134
|
-
* 3.
|
|
135
|
-
* -
|
|
136
|
-
* -
|
|
137
|
-
* -
|
|
134
|
+
* 3. **Technical Advantages**
|
|
135
|
+
* - Deployment flexibility: The same set of build artifacts can be deployed to any path
|
|
136
|
+
* - Performance optimization: Maintain the best caching strategy for static assets
|
|
137
|
+
* - Development-friendly: Simplify multi-environment configuration management
|
|
138
138
|
*
|
|
139
139
|
* @example
|
|
140
140
|
* ```ts
|
|
141
|
-
* // 1.
|
|
141
|
+
* // 1. Basic usage
|
|
142
142
|
* const rc = await esmx.render({
|
|
143
|
-
* base: '/esmx', //
|
|
143
|
+
* base: '/esmx', // Set base path
|
|
144
144
|
* params: { url: req.url }
|
|
145
145
|
* });
|
|
146
146
|
*
|
|
147
|
-
* // 2.
|
|
147
|
+
* // 2. Multi-language site example
|
|
148
148
|
* const rc = await esmx.render({
|
|
149
|
-
* base: '/cn', //
|
|
149
|
+
* base: '/cn', // Chinese site
|
|
150
150
|
* params: { lang: 'zh-CN' }
|
|
151
151
|
* });
|
|
152
152
|
*
|
|
153
|
-
* // 3.
|
|
153
|
+
* // 3. Micro-frontend application example
|
|
154
154
|
* const rc = await esmx.render({
|
|
155
|
-
* base: '/app1', //
|
|
155
|
+
* base: '/app1', // Sub-application 1
|
|
156
156
|
* params: { appId: 1 }
|
|
157
157
|
* });
|
|
158
158
|
* ```
|
|
159
159
|
*/
|
|
160
160
|
base;
|
|
161
161
|
/**
|
|
162
|
-
*
|
|
162
|
+
* Server-side rendering entry function name
|
|
163
163
|
* @description
|
|
164
|
-
* entryName
|
|
164
|
+
* The entryName property is used to specify the entry function used during server-side rendering:
|
|
165
165
|
*
|
|
166
|
-
* 1.
|
|
167
|
-
* -
|
|
168
|
-
* -
|
|
169
|
-
* -
|
|
166
|
+
* 1. **Basic Usage**
|
|
167
|
+
* - Default value is 'default'
|
|
168
|
+
* - Used to select the rendering function to use from entry.server.ts
|
|
169
|
+
* - Supports scenarios where a module exports multiple rendering functions
|
|
170
170
|
*
|
|
171
|
-
* 2.
|
|
172
|
-
* -
|
|
173
|
-
* - A/B
|
|
174
|
-
* -
|
|
171
|
+
* 2. **Use Cases**
|
|
172
|
+
* - Multi-template rendering: Different pages use different rendering templates
|
|
173
|
+
* - A/B testing: The same page uses different rendering logic
|
|
174
|
+
* - Special rendering: Some pages need custom rendering processes
|
|
175
175
|
*
|
|
176
176
|
* @example
|
|
177
177
|
* ```ts
|
|
178
|
-
* // 1.
|
|
178
|
+
* // 1. Default entry function
|
|
179
179
|
* // entry.server.ts
|
|
180
180
|
* export default async (rc: RenderContext) => {
|
|
181
|
-
* //
|
|
181
|
+
* // Default rendering logic
|
|
182
182
|
* };
|
|
183
183
|
*
|
|
184
|
-
* // 2.
|
|
184
|
+
* // 2. Multiple entry functions
|
|
185
185
|
* // entry.server.ts
|
|
186
186
|
* export const mobile = async (rc: RenderContext) => {
|
|
187
|
-
* //
|
|
187
|
+
* // Mobile rendering logic
|
|
188
188
|
* };
|
|
189
189
|
*
|
|
190
190
|
* export const desktop = async (rc: RenderContext) => {
|
|
191
|
-
* //
|
|
191
|
+
* // Desktop rendering logic
|
|
192
192
|
* };
|
|
193
193
|
*
|
|
194
|
-
* // 3.
|
|
194
|
+
* // 3. Select entry function based on device type
|
|
195
195
|
* const rc = await esmx.render({
|
|
196
196
|
* entryName: isMobile ? 'mobile' : 'desktop',
|
|
197
197
|
* params: { url: req.url }
|
|
@@ -200,29 +200,29 @@ export class RenderContext {
|
|
|
200
200
|
*/
|
|
201
201
|
entryName;
|
|
202
202
|
/**
|
|
203
|
-
*
|
|
203
|
+
* Rendering parameters
|
|
204
204
|
* @description
|
|
205
|
-
* params
|
|
205
|
+
* The params property is used to pass and access parameters during the server-side rendering process:
|
|
206
206
|
*
|
|
207
|
-
* 1.
|
|
208
|
-
* -
|
|
209
|
-
* -
|
|
210
|
-
* -
|
|
207
|
+
* 1. **Parameter Types**
|
|
208
|
+
* - Supports key-value pairs of any type
|
|
209
|
+
* - Defined through Record<string, any> type
|
|
210
|
+
* - Remains unchanged throughout the entire rendering lifecycle
|
|
211
211
|
*
|
|
212
|
-
* 2.
|
|
213
|
-
* -
|
|
214
|
-
* -
|
|
215
|
-
* -
|
|
216
|
-
* -
|
|
212
|
+
* 2. **Common Use Cases**
|
|
213
|
+
* - Pass request information (URL, query parameters, etc.)
|
|
214
|
+
* - Set page configuration (language, theme, etc.)
|
|
215
|
+
* - Inject environment variables (API address, version number, etc.)
|
|
216
|
+
* - Share server-side state (user information, permissions, etc.)
|
|
217
217
|
*
|
|
218
|
-
* 3.
|
|
219
|
-
* -
|
|
220
|
-
* -
|
|
221
|
-
* -
|
|
218
|
+
* 3. **Access Methods**
|
|
219
|
+
* - Accessed through rc.params in server-side rendering functions
|
|
220
|
+
* - Can destructure to get specific parameters
|
|
221
|
+
* - Supports setting default values
|
|
222
222
|
*
|
|
223
223
|
* @example
|
|
224
224
|
* ```ts
|
|
225
|
-
* // 1.
|
|
225
|
+
* // 1. Basic usage - Pass URL and language settings
|
|
226
226
|
* const rc = await esmx.render({
|
|
227
227
|
* params: {
|
|
228
228
|
* url: req.url,
|
|
@@ -230,7 +230,7 @@ export class RenderContext {
|
|
|
230
230
|
* }
|
|
231
231
|
* });
|
|
232
232
|
*
|
|
233
|
-
* // 2.
|
|
233
|
+
* // 2. Page configuration - Set theme and layout
|
|
234
234
|
* const rc = await esmx.render({
|
|
235
235
|
* params: {
|
|
236
236
|
* theme: 'dark',
|
|
@@ -238,7 +238,7 @@ export class RenderContext {
|
|
|
238
238
|
* }
|
|
239
239
|
* });
|
|
240
240
|
*
|
|
241
|
-
* // 3.
|
|
241
|
+
* // 3. Environment configuration - Inject API address
|
|
242
242
|
* const rc = await esmx.render({
|
|
243
243
|
* params: {
|
|
244
244
|
* apiBaseUrl: process.env.API_BASE_URL,
|
|
@@ -246,17 +246,17 @@ export class RenderContext {
|
|
|
246
246
|
* }
|
|
247
247
|
* });
|
|
248
248
|
*
|
|
249
|
-
* // 4.
|
|
249
|
+
* // 4. Use in rendering function
|
|
250
250
|
* export default async (rc: RenderContext) => {
|
|
251
|
-
* //
|
|
251
|
+
* // Destructure to get parameters
|
|
252
252
|
* const { url, lang = 'en' } = rc.params;
|
|
253
253
|
*
|
|
254
|
-
* //
|
|
254
|
+
* // Execute different logic based on parameters
|
|
255
255
|
* if (lang === 'zh-CN') {
|
|
256
|
-
* //
|
|
256
|
+
* // Chinese version processing...
|
|
257
257
|
* }
|
|
258
258
|
*
|
|
259
|
-
* //
|
|
259
|
+
* // Pass parameters to component
|
|
260
260
|
* const html = await renderToString(createApp({
|
|
261
261
|
* props: {
|
|
262
262
|
* currentUrl: url,
|
|
@@ -264,7 +264,7 @@ export class RenderContext {
|
|
|
264
264
|
* }
|
|
265
265
|
* }));
|
|
266
266
|
*
|
|
267
|
-
* //
|
|
267
|
+
* // Set HTML
|
|
268
268
|
* rc.html = `
|
|
269
269
|
* <!DOCTYPE html>
|
|
270
270
|
* <html lang="${lang}">
|
|
@@ -276,50 +276,50 @@ export class RenderContext {
|
|
|
276
276
|
*/
|
|
277
277
|
params;
|
|
278
278
|
/**
|
|
279
|
-
*
|
|
279
|
+
* Module dependency collection set
|
|
280
280
|
* @description
|
|
281
|
-
* importMetaSet
|
|
281
|
+
* importMetaSet is the core of Esmx framework's intelligent dependency collection mechanism, used to track and record module dependencies during the server-side rendering process:
|
|
282
282
|
*
|
|
283
|
-
* 1.
|
|
284
|
-
* -
|
|
285
|
-
* -
|
|
286
|
-
* -
|
|
283
|
+
* 1. **On-demand Collection**
|
|
284
|
+
* - Automatically tracks and records module dependencies during the actual component rendering process
|
|
285
|
+
* - Only collects resources actually used during the current page rendering
|
|
286
|
+
* - Precisely records the module dependency relationships of each component
|
|
287
287
|
*
|
|
288
|
-
* 2.
|
|
289
|
-
* -
|
|
290
|
-
* -
|
|
291
|
-
* -
|
|
288
|
+
* 2. **Performance Optimization**
|
|
289
|
+
* - Avoids loading unused modules, significantly reducing first-screen loading time
|
|
290
|
+
* - Precisely controls resource loading order, optimizing page rendering performance
|
|
291
|
+
* - Automatically generates optimal import maps
|
|
292
292
|
*
|
|
293
|
-
* 3.
|
|
294
|
-
* -
|
|
295
|
-
* -
|
|
296
|
-
* -
|
|
293
|
+
* 3. **Usage**
|
|
294
|
+
* - Passed to renderToString in the rendering function
|
|
295
|
+
* - Framework automatically collects dependencies, no manual handling required
|
|
296
|
+
* - Supports dependency collection for async components and dynamic imports
|
|
297
297
|
*
|
|
298
298
|
* @example
|
|
299
299
|
* ```ts
|
|
300
|
-
* // 1.
|
|
300
|
+
* // 1. Basic usage
|
|
301
301
|
* const renderToString = (app: any, context: { importMetaSet: Set<ImportMeta> }) => {
|
|
302
|
-
* //
|
|
303
|
-
* //
|
|
304
|
-
* //
|
|
302
|
+
* // Automatically collect module dependencies during the rendering process
|
|
303
|
+
* // Framework will automatically call context.importMetaSet.add(import.meta) during component rendering
|
|
304
|
+
* // Developers do not need to manually handle dependency collection
|
|
305
305
|
* return '<div id="app">Hello World</div>';
|
|
306
306
|
* };
|
|
307
307
|
*
|
|
308
|
-
* //
|
|
308
|
+
* // Usage example
|
|
309
309
|
* const app = createApp();
|
|
310
310
|
* const html = await renderToString(app, {
|
|
311
311
|
* importMetaSet: rc.importMetaSet
|
|
312
312
|
* });
|
|
313
313
|
*
|
|
314
|
-
* // 2.
|
|
314
|
+
* // 2. Commit dependencies
|
|
315
315
|
* await rc.commit();
|
|
316
316
|
*
|
|
317
|
-
* // 3.
|
|
317
|
+
* // 3. Generate HTML
|
|
318
318
|
* rc.html = `
|
|
319
319
|
* <!DOCTYPE html>
|
|
320
320
|
* <html>
|
|
321
321
|
* <head>
|
|
322
|
-
* <!--
|
|
322
|
+
* <!-- Automatically inject resources based on collected dependencies -->
|
|
323
323
|
* ${rc.preload()}
|
|
324
324
|
* ${rc.css()}
|
|
325
325
|
* </head>
|
|
@@ -335,35 +335,35 @@ export class RenderContext {
|
|
|
335
335
|
*/
|
|
336
336
|
importMetaSet = /* @__PURE__ */ new Set();
|
|
337
337
|
/**
|
|
338
|
-
*
|
|
338
|
+
* Resource file list
|
|
339
339
|
* @description
|
|
340
|
-
* files
|
|
340
|
+
* The files property stores all static resource file paths collected during the server-side rendering process:
|
|
341
341
|
*
|
|
342
|
-
* 1.
|
|
343
|
-
* - js: JavaScript
|
|
344
|
-
* - css:
|
|
345
|
-
* - modulepreload:
|
|
346
|
-
* - importmap:
|
|
347
|
-
* - resources:
|
|
342
|
+
* 1. **Resource Types**
|
|
343
|
+
* - js: List of JavaScript files, containing all scripts and modules
|
|
344
|
+
* - css: List of stylesheet files
|
|
345
|
+
* - modulepreload: List of ESM modules that need to be preloaded
|
|
346
|
+
* - importmap: List of import map files
|
|
347
|
+
* - resources: List of other resource files (images, fonts, etc.)
|
|
348
348
|
*
|
|
349
|
-
* 2.
|
|
350
|
-
* -
|
|
351
|
-
* -
|
|
352
|
-
* -
|
|
349
|
+
* 2. **Use Cases**
|
|
350
|
+
* - Automatically collect and categorize resources in the commit() method
|
|
351
|
+
* - Inject resources into HTML through methods like preload(), css(), etc.
|
|
352
|
+
* - Supports base path configuration, implementing dynamic loading of resources
|
|
353
353
|
*
|
|
354
354
|
* @example
|
|
355
355
|
* ```ts
|
|
356
|
-
* // 1.
|
|
356
|
+
* // 1. Resource collection
|
|
357
357
|
* await rc.commit();
|
|
358
358
|
*
|
|
359
|
-
* // 2.
|
|
359
|
+
* // 2. Resource injection
|
|
360
360
|
* rc.html = `
|
|
361
361
|
* <!DOCTYPE html>
|
|
362
362
|
* <html>
|
|
363
363
|
* <head>
|
|
364
|
-
* <!--
|
|
364
|
+
* <!-- Preload resources -->
|
|
365
365
|
* ${rc.preload()}
|
|
366
|
-
* <!--
|
|
366
|
+
* <!-- Inject stylesheets -->
|
|
367
367
|
* ${rc.css()}
|
|
368
368
|
* </head>
|
|
369
369
|
* <body>
|
|
@@ -387,47 +387,47 @@ export class RenderContext {
|
|
|
387
387
|
code: ""
|
|
388
388
|
};
|
|
389
389
|
/**
|
|
390
|
-
*
|
|
390
|
+
* Define the generation mode for importmap
|
|
391
391
|
*
|
|
392
392
|
* @description
|
|
393
|
-
* ImportmapMode
|
|
394
|
-
* - `inline`:
|
|
395
|
-
* -
|
|
396
|
-
* -
|
|
397
|
-
* -
|
|
398
|
-
* - `js`:
|
|
399
|
-
* -
|
|
400
|
-
* -
|
|
401
|
-
* -
|
|
402
|
-
*
|
|
403
|
-
*
|
|
404
|
-
* 1.
|
|
405
|
-
* -
|
|
406
|
-
* -
|
|
407
|
-
* -
|
|
408
|
-
* 2.
|
|
409
|
-
* -
|
|
410
|
-
* -
|
|
411
|
-
* -
|
|
412
|
-
* 3.
|
|
413
|
-
* -
|
|
414
|
-
* -
|
|
415
|
-
* -
|
|
393
|
+
* ImportmapMode is used to control the generation method of importmap, supporting two modes:
|
|
394
|
+
* - `inline`: Inline importmap content directly into HTML (default value), suitable for the following scenarios:
|
|
395
|
+
* - Need to reduce the number of HTTP requests
|
|
396
|
+
* - Importmap content is small
|
|
397
|
+
* - High requirements for first-screen loading performance
|
|
398
|
+
* - `js`: Generate importmap content as an independent JS file, suitable for the following scenarios:
|
|
399
|
+
* - Importmap content is large
|
|
400
|
+
* - Need to utilize browser caching mechanisms
|
|
401
|
+
* - Multiple pages share the same importmap
|
|
402
|
+
*
|
|
403
|
+
* Reasons for choosing 'inline' as the default value:
|
|
404
|
+
* 1. Simple and direct
|
|
405
|
+
* - Reduce additional HTTP requests
|
|
406
|
+
* - No additional resource management required
|
|
407
|
+
* - Suitable for most application scenarios
|
|
408
|
+
* 2. First-screen performance
|
|
409
|
+
* - Avoid additional network requests
|
|
410
|
+
* - Ensure import maps are immediately available
|
|
411
|
+
* - Reduce page loading time
|
|
412
|
+
* 3. Easy to debug
|
|
413
|
+
* - Import maps are directly visible
|
|
414
|
+
* - Facilitate problem diagnosis
|
|
415
|
+
* - Simplify development process
|
|
416
416
|
*
|
|
417
417
|
* @example
|
|
418
418
|
* ```ts
|
|
419
|
-
* //
|
|
419
|
+
* // Use inline mode (default)
|
|
420
420
|
* const rc = await esmx.render({
|
|
421
421
|
* params: { url: req.url }
|
|
422
422
|
* });
|
|
423
423
|
*
|
|
424
|
-
* //
|
|
424
|
+
* // Explicitly specify inline mode
|
|
425
425
|
* const rc = await esmx.render({
|
|
426
426
|
* importmapMode: 'inline',
|
|
427
427
|
* params: { url: req.url }
|
|
428
428
|
* });
|
|
429
429
|
*
|
|
430
|
-
* //
|
|
430
|
+
* // Use JS file mode
|
|
431
431
|
* const rc = await esmx.render({
|
|
432
432
|
* importmapMode: 'js',
|
|
433
433
|
* params: { url: req.url }
|
|
@@ -436,25 +436,25 @@ export class RenderContext {
|
|
|
436
436
|
*/
|
|
437
437
|
importmapMode;
|
|
438
438
|
/**
|
|
439
|
-
* HTML
|
|
439
|
+
* HTML content
|
|
440
440
|
* @description
|
|
441
|
-
* html
|
|
441
|
+
* The html property is used to set and get the final generated HTML content:
|
|
442
442
|
*
|
|
443
|
-
* 1.
|
|
444
|
-
* -
|
|
445
|
-
* -
|
|
446
|
-
* -
|
|
443
|
+
* 1. **Base Path Replacement**
|
|
444
|
+
* - Automatically handles base path placeholders when setting HTML
|
|
445
|
+
* - Replaces `[[[___ESMX_DYNAMIC_BASE___]]]/your-app-name/` with the actual base path
|
|
446
|
+
* - Ensures all static asset reference paths are correct
|
|
447
447
|
*
|
|
448
|
-
* 2.
|
|
449
|
-
* -
|
|
450
|
-
* -
|
|
451
|
-
* -
|
|
448
|
+
* 2. **Use Cases**
|
|
449
|
+
* - Set HTML content generated by server-side rendering
|
|
450
|
+
* - Support dynamic base path configuration
|
|
451
|
+
* - Automatically handle static asset reference paths
|
|
452
452
|
*
|
|
453
453
|
* @example
|
|
454
454
|
* ```ts
|
|
455
|
-
* // 1.
|
|
455
|
+
* // 1. Basic usage
|
|
456
456
|
* export default async (rc: RenderContext) => {
|
|
457
|
-
* //
|
|
457
|
+
* // Set HTML content
|
|
458
458
|
* rc.html = `
|
|
459
459
|
* <!DOCTYPE html>
|
|
460
460
|
* <html>
|
|
@@ -472,15 +472,15 @@ export class RenderContext {
|
|
|
472
472
|
* `;
|
|
473
473
|
* };
|
|
474
474
|
*
|
|
475
|
-
* // 2.
|
|
475
|
+
* // 2. Dynamic base path
|
|
476
476
|
* const rc = await esmx.render({
|
|
477
|
-
* base: '/app', //
|
|
477
|
+
* base: '/app', // Set base path
|
|
478
478
|
* params: { url: req.url }
|
|
479
479
|
* });
|
|
480
480
|
*
|
|
481
|
-
* // HTML
|
|
482
|
-
* // [[[
|
|
483
|
-
* //
|
|
481
|
+
* // Placeholders in HTML will be automatically replaced:
|
|
482
|
+
* // [[[___ESMX_DYNAMIC_BASE___]]]/your-app-name/css/style.css
|
|
483
|
+
* // Replaced with:
|
|
484
484
|
* // /app/your-app-name/css/style.css
|
|
485
485
|
* ```
|
|
486
486
|
*/
|
|
@@ -499,23 +499,23 @@ export class RenderContext {
|
|
|
499
499
|
this.importmapMode = options.importmapMode ?? "inline";
|
|
500
500
|
}
|
|
501
501
|
/**
|
|
502
|
-
*
|
|
502
|
+
* Serialize JavaScript object to string
|
|
503
503
|
* @description
|
|
504
|
-
* serialize
|
|
504
|
+
* The serialize method is used to serialize state data during the server-side rendering process for passing to the client:
|
|
505
505
|
*
|
|
506
|
-
* 1.
|
|
507
|
-
* -
|
|
508
|
-
* -
|
|
509
|
-
* -
|
|
506
|
+
* 1. **Main Uses**
|
|
507
|
+
* - Serialize server-side state data
|
|
508
|
+
* - Ensure data can be safely embedded in HTML
|
|
509
|
+
* - Support complex data structures (such as Date, RegExp, etc.)
|
|
510
510
|
*
|
|
511
|
-
* 2.
|
|
512
|
-
* -
|
|
513
|
-
* -
|
|
514
|
-
* -
|
|
511
|
+
* 2. **Security Handling**
|
|
512
|
+
* - Automatically escape special characters
|
|
513
|
+
* - Prevent XSS attacks
|
|
514
|
+
* - Maintain data type integrity
|
|
515
515
|
*
|
|
516
516
|
* @example
|
|
517
517
|
* ```ts
|
|
518
|
-
* // 1.
|
|
518
|
+
* // 1. Basic usage - Serialize state data
|
|
519
519
|
* export default async (rc: RenderContext) => {
|
|
520
520
|
* const state = {
|
|
521
521
|
* user: { id: 1, name: 'Alice' },
|
|
@@ -528,7 +528,7 @@ export class RenderContext {
|
|
|
528
528
|
* <html>
|
|
529
529
|
* <head>
|
|
530
530
|
* <script>
|
|
531
|
-
* //
|
|
531
|
+
* // Inject serialized state into global variable
|
|
532
532
|
* window.__INITIAL_STATE__ = ${rc.serialize(state)};
|
|
533
533
|
* <\/script>
|
|
534
534
|
* </head>
|
|
@@ -537,43 +537,43 @@ export class RenderContext {
|
|
|
537
537
|
* `;
|
|
538
538
|
* };
|
|
539
539
|
*
|
|
540
|
-
* // 2.
|
|
540
|
+
* // 2. Custom serialization options
|
|
541
541
|
* const state = { sensitive: 'data' };
|
|
542
542
|
* const serialized = rc.serialize(state, {
|
|
543
|
-
* isJSON: true, //
|
|
544
|
-
* unsafe: false //
|
|
543
|
+
* isJSON: true, // Use JSON compatible mode
|
|
544
|
+
* unsafe: false // Disable unsafe serialization
|
|
545
545
|
* });
|
|
546
546
|
* ```
|
|
547
547
|
*
|
|
548
|
-
* @param {any} input -
|
|
549
|
-
* @param {serialize.SerializeJSOptions} [options] -
|
|
550
|
-
* @returns {string}
|
|
548
|
+
* @param {any} input - Input data to be serialized
|
|
549
|
+
* @param {serialize.SerializeJSOptions} [options] - Serialization options
|
|
550
|
+
* @returns {string} Serialized string
|
|
551
551
|
*/
|
|
552
552
|
serialize(input, options) {
|
|
553
553
|
return serialize(input, options);
|
|
554
554
|
}
|
|
555
555
|
/**
|
|
556
|
-
*
|
|
556
|
+
* Serialize state data and inject it into HTML
|
|
557
557
|
* @description
|
|
558
|
-
* state
|
|
558
|
+
* The state method is used to serialize state data and inject it into HTML during server-side rendering, so that the client can restore these states when activating:
|
|
559
559
|
*
|
|
560
|
-
* 1.
|
|
561
|
-
* -
|
|
562
|
-
* -
|
|
563
|
-
* -
|
|
560
|
+
* 1. **Serialization Mechanism**
|
|
561
|
+
* - Use safe serialization methods to process data
|
|
562
|
+
* - Support complex data structures (objects, arrays, etc.)
|
|
563
|
+
* - Automatically handle special characters and XSS protection
|
|
564
564
|
*
|
|
565
|
-
* 2.
|
|
566
|
-
* -
|
|
567
|
-
* -
|
|
568
|
-
* -
|
|
565
|
+
* 2. **Use Cases**
|
|
566
|
+
* - Synchronize server-side state to client
|
|
567
|
+
* - Initialize client application state
|
|
568
|
+
* - Implement seamless server-side rendering to client activation
|
|
569
569
|
*
|
|
570
|
-
* @param varName
|
|
571
|
-
* @param data
|
|
572
|
-
* @returns
|
|
570
|
+
* @param varName Global variable name, used to access injected data on the client
|
|
571
|
+
* @param data Data object that needs to be serialized
|
|
572
|
+
* @returns Script tag string containing serialized data
|
|
573
573
|
*
|
|
574
574
|
* @example
|
|
575
575
|
* ```ts
|
|
576
|
-
* // 1.
|
|
576
|
+
* // 1. Basic usage - Inject user information
|
|
577
577
|
* export default async (rc: RenderContext) => {
|
|
578
578
|
* const userInfo = {
|
|
579
579
|
* id: 1,
|
|
@@ -594,12 +594,12 @@ export class RenderContext {
|
|
|
594
594
|
* `;
|
|
595
595
|
* };
|
|
596
596
|
*
|
|
597
|
-
* // 2.
|
|
598
|
-
* //
|
|
597
|
+
* // 2. Client-side usage
|
|
598
|
+
* // Can directly access injected data on the client
|
|
599
599
|
* const userInfo = window.__USER__;
|
|
600
|
-
* console.log(userInfo.name); //
|
|
600
|
+
* console.log(userInfo.name); // Output: 'John'
|
|
601
601
|
*
|
|
602
|
-
* // 3.
|
|
602
|
+
* // 3. Complex data structures
|
|
603
603
|
* export default async (rc: RenderContext) => {
|
|
604
604
|
* const appState = {
|
|
605
605
|
* user: {
|
|
@@ -633,42 +633,42 @@ export class RenderContext {
|
|
|
633
633
|
return `<script>window[${serialize(varName)}] = ${serialize(data, { isJSON: true })};<\/script>`;
|
|
634
634
|
}
|
|
635
635
|
/**
|
|
636
|
-
*
|
|
636
|
+
* Commit dependency collection and update resource list
|
|
637
637
|
* @description
|
|
638
|
-
* commit
|
|
639
|
-
*
|
|
640
|
-
* 1.
|
|
641
|
-
* -
|
|
642
|
-
* -
|
|
643
|
-
* -
|
|
644
|
-
* -
|
|
645
|
-
*
|
|
646
|
-
* 2.
|
|
647
|
-
* - js: JavaScript
|
|
648
|
-
* - css:
|
|
649
|
-
* - modulepreload:
|
|
650
|
-
* - importmap:
|
|
651
|
-
* - resources:
|
|
652
|
-
*
|
|
653
|
-
* 3.
|
|
654
|
-
* -
|
|
655
|
-
* -
|
|
656
|
-
* -
|
|
638
|
+
* The commit method is the core of RenderContext's dependency collection mechanism, responsible for handling all collected module dependencies and updating the file resource list:
|
|
639
|
+
*
|
|
640
|
+
* 1. **Dependency Processing Flow**
|
|
641
|
+
* - Collect all used modules from importMetaSet
|
|
642
|
+
* - Parse specific resources for each module based on manifest files
|
|
643
|
+
* - Handle different types of dependencies such as JS, CSS, resource files, etc.
|
|
644
|
+
* - Automatically handle module preloading and import maps
|
|
645
|
+
*
|
|
646
|
+
* 2. **Resource Classification**
|
|
647
|
+
* - js: JavaScript files, containing all scripts and modules
|
|
648
|
+
* - css: Stylesheet files
|
|
649
|
+
* - modulepreload: ESM modules that need to be preloaded
|
|
650
|
+
* - importmap: Import map files
|
|
651
|
+
* - resources: Other resource files (images, fonts, etc.)
|
|
652
|
+
*
|
|
653
|
+
* 3. **Path Processing**
|
|
654
|
+
* - Automatically add base path prefix
|
|
655
|
+
* - Ensure the correctness of resource paths
|
|
656
|
+
* - Support resource isolation for multi-application scenarios
|
|
657
657
|
*
|
|
658
658
|
* @example
|
|
659
659
|
* ```ts
|
|
660
|
-
* // 1.
|
|
660
|
+
* // 1. Basic usage
|
|
661
661
|
* export default async (rc: RenderContext) => {
|
|
662
|
-
* //
|
|
662
|
+
* // Render page and collect dependencies
|
|
663
663
|
* const app = createApp();
|
|
664
664
|
* const html = await renderToString(app, {
|
|
665
665
|
* importMetaSet: rc.importMetaSet
|
|
666
666
|
* });
|
|
667
667
|
*
|
|
668
|
-
* //
|
|
668
|
+
* // Commit dependency collection
|
|
669
669
|
* await rc.commit();
|
|
670
670
|
*
|
|
671
|
-
* //
|
|
671
|
+
* // Generate HTML
|
|
672
672
|
* rc.html = `
|
|
673
673
|
* <!DOCTYPE html>
|
|
674
674
|
* <html>
|
|
@@ -686,18 +686,18 @@ export class RenderContext {
|
|
|
686
686
|
* `;
|
|
687
687
|
* };
|
|
688
688
|
*
|
|
689
|
-
* // 2.
|
|
689
|
+
* // 2. Multi-application scenario
|
|
690
690
|
* const rc = await esmx.render({
|
|
691
|
-
* base: '/app1', //
|
|
691
|
+
* base: '/app1', // Set base path
|
|
692
692
|
* params: { appId: 1 }
|
|
693
693
|
* });
|
|
694
694
|
*
|
|
695
|
-
* //
|
|
695
|
+
* // Render and commit dependencies
|
|
696
696
|
* const html = await renderApp(rc);
|
|
697
697
|
* await rc.commit();
|
|
698
698
|
*
|
|
699
|
-
* //
|
|
700
|
-
* //
|
|
699
|
+
* // Resource paths will automatically add base path prefix
|
|
700
|
+
* // For example: /app1/your-app-name/js/main.js
|
|
701
701
|
* ```
|
|
702
702
|
*/
|
|
703
703
|
async commit() {
|
|
@@ -741,37 +741,37 @@ export class RenderContext {
|
|
|
741
741
|
this._importMap = await esmx.getImportMapClientInfo(this.importmapMode);
|
|
742
742
|
}
|
|
743
743
|
/**
|
|
744
|
-
*
|
|
744
|
+
* Generate resource preload tags
|
|
745
745
|
* @description
|
|
746
|
-
* preload()
|
|
746
|
+
* The preload() method is used to generate resource preload tags, optimizing page performance by loading critical resources in advance:
|
|
747
747
|
*
|
|
748
|
-
* 1.
|
|
749
|
-
* - CSS
|
|
750
|
-
* - JS
|
|
748
|
+
* 1. **Resource Types**
|
|
749
|
+
* - CSS files: Use `as="style"` to preload stylesheets
|
|
750
|
+
* - JS files: Use `as="script"` to preload import map scripts
|
|
751
751
|
*
|
|
752
|
-
* 2.
|
|
753
|
-
* -
|
|
754
|
-
* -
|
|
755
|
-
* -
|
|
756
|
-
* -
|
|
752
|
+
* 2. **Performance Optimization**
|
|
753
|
+
* - Discover and load critical resources in advance
|
|
754
|
+
* - Load in parallel with HTML parsing
|
|
755
|
+
* - Optimize resource loading order
|
|
756
|
+
* - Reduce page rendering blocking
|
|
757
757
|
*
|
|
758
|
-
* 3.
|
|
759
|
-
* -
|
|
760
|
-
* -
|
|
761
|
-
* -
|
|
758
|
+
* 3. **Best Practices**
|
|
759
|
+
* - Use as early as possible in the head
|
|
760
|
+
* - Only preload resources necessary for the current page
|
|
761
|
+
* - Use in conjunction with other resource loading methods
|
|
762
762
|
*
|
|
763
|
-
* @returns
|
|
763
|
+
* @returns Returns HTML string containing all preload tags
|
|
764
764
|
*
|
|
765
765
|
* @example
|
|
766
766
|
* ```ts
|
|
767
|
-
* //
|
|
767
|
+
* // Use in HTML head
|
|
768
768
|
* rc.html = `
|
|
769
769
|
* <!DOCTYPE html>
|
|
770
770
|
* <html>
|
|
771
771
|
* <head>
|
|
772
|
-
* <!--
|
|
772
|
+
* <!-- Preload critical resources -->
|
|
773
773
|
* ${rc.preload()}
|
|
774
|
-
* <!--
|
|
774
|
+
* <!-- Inject stylesheets -->
|
|
775
775
|
* ${rc.css()}
|
|
776
776
|
* </head>
|
|
777
777
|
* <body>
|
|
@@ -797,34 +797,34 @@ export class RenderContext {
|
|
|
797
797
|
return list.join("");
|
|
798
798
|
}
|
|
799
799
|
/**
|
|
800
|
-
*
|
|
800
|
+
* Inject first-screen stylesheets
|
|
801
801
|
* @description
|
|
802
|
-
* css()
|
|
802
|
+
* The css() method is used to inject stylesheet resources required by the page:
|
|
803
803
|
*
|
|
804
|
-
* 1.
|
|
805
|
-
* -
|
|
806
|
-
* -
|
|
807
|
-
* -
|
|
804
|
+
* 1. **Injection Position**
|
|
805
|
+
* - Must be injected in the head tag
|
|
806
|
+
* - Avoid page flickering (FOUC) and reflow
|
|
807
|
+
* - Ensure styles are in place when content is rendered
|
|
808
808
|
*
|
|
809
|
-
* 2.
|
|
810
|
-
* -
|
|
811
|
-
* -
|
|
812
|
-
* -
|
|
809
|
+
* 2. **Performance Optimization**
|
|
810
|
+
* - Support critical CSS extraction
|
|
811
|
+
* - Automatically handle style dependency relationships
|
|
812
|
+
* - Utilize browser parallel loading capabilities
|
|
813
813
|
*
|
|
814
|
-
* 3.
|
|
815
|
-
* -
|
|
816
|
-
* -
|
|
817
|
-
* -
|
|
814
|
+
* 3. **Use Cases**
|
|
815
|
+
* - Inject styles necessary for the first screen
|
|
816
|
+
* - Handle component-level styles
|
|
817
|
+
* - Support theme switching and dynamic styles
|
|
818
818
|
*
|
|
819
819
|
* @example
|
|
820
820
|
* ```ts
|
|
821
|
-
* // 1.
|
|
821
|
+
* // 1. Basic usage
|
|
822
822
|
* rc.html = `
|
|
823
823
|
* <!DOCTYPE html>
|
|
824
824
|
* <html>
|
|
825
825
|
* <head>
|
|
826
|
-
* ${rc.preload()} <!--
|
|
827
|
-
* ${rc.css()} <!--
|
|
826
|
+
* ${rc.preload()} <!-- Preload resources -->
|
|
827
|
+
* ${rc.css()} <!-- Inject stylesheets -->
|
|
828
828
|
* </head>
|
|
829
829
|
* <body>
|
|
830
830
|
* <div id="app">Hello World</div>
|
|
@@ -832,13 +832,13 @@ export class RenderContext {
|
|
|
832
832
|
* </html>
|
|
833
833
|
* `;
|
|
834
834
|
*
|
|
835
|
-
* // 2.
|
|
835
|
+
* // 2. Use in conjunction with other resources
|
|
836
836
|
* rc.html = `
|
|
837
837
|
* <!DOCTYPE html>
|
|
838
838
|
* <html>
|
|
839
839
|
* <head>
|
|
840
|
-
* ${rc.preload()} <!--
|
|
841
|
-
* ${rc.css()} <!--
|
|
840
|
+
* ${rc.preload()} <!-- Preload resources -->
|
|
841
|
+
* ${rc.css()} <!-- Inject stylesheets -->
|
|
842
842
|
* </head>
|
|
843
843
|
* <body>
|
|
844
844
|
* ${html}
|
|
@@ -854,35 +854,35 @@ export class RenderContext {
|
|
|
854
854
|
return this.files.css.map((url) => `<link rel="stylesheet" href="${url}">`).join("");
|
|
855
855
|
}
|
|
856
856
|
/**
|
|
857
|
-
*
|
|
857
|
+
* Inject module import map
|
|
858
858
|
* @description
|
|
859
|
-
* importmap()
|
|
860
|
-
*
|
|
861
|
-
* 1.
|
|
862
|
-
* -
|
|
863
|
-
* -
|
|
864
|
-
* -
|
|
865
|
-
*
|
|
866
|
-
* 2.
|
|
867
|
-
* -
|
|
868
|
-
* -
|
|
869
|
-
* -
|
|
870
|
-
* -
|
|
871
|
-
* - JS
|
|
872
|
-
* -
|
|
873
|
-
* -
|
|
874
|
-
* -
|
|
875
|
-
*
|
|
876
|
-
* 3.
|
|
877
|
-
* -
|
|
878
|
-
* -
|
|
879
|
-
* -
|
|
859
|
+
* The importmap() method is used to inject path resolution rules for ESM modules:
|
|
860
|
+
*
|
|
861
|
+
* 1. **Injection Position**
|
|
862
|
+
* - Must be injected in the body
|
|
863
|
+
* - Must be executed before moduleEntry
|
|
864
|
+
* - Avoid blocking the first page render
|
|
865
|
+
*
|
|
866
|
+
* 2. **Import Map Modes**
|
|
867
|
+
* - Inline mode (inline):
|
|
868
|
+
* - Inline map content directly into HTML
|
|
869
|
+
* - Suitable for scenarios with smaller map content
|
|
870
|
+
* - Reduce the number of HTTP requests
|
|
871
|
+
* - JS file mode (js):
|
|
872
|
+
* - Generate independent JS files
|
|
873
|
+
* - Suitable for scenarios with larger map content
|
|
874
|
+
* - Can utilize browser caching mechanisms
|
|
875
|
+
*
|
|
876
|
+
* 3. **Technical Reasons**
|
|
877
|
+
* - Define path resolution rules for ESM modules
|
|
878
|
+
* - Client entry modules and their dependencies need to use these maps
|
|
879
|
+
* - Ensure the map is correctly set before executing module code
|
|
880
880
|
*
|
|
881
881
|
* @example
|
|
882
882
|
* ```ts
|
|
883
|
-
* // 1.
|
|
883
|
+
* // 1. Basic usage - Inline mode
|
|
884
884
|
* const rc = await esmx.render({
|
|
885
|
-
* importmapMode: 'inline' //
|
|
885
|
+
* importmapMode: 'inline' // Default mode
|
|
886
886
|
* });
|
|
887
887
|
*
|
|
888
888
|
* rc.html = `
|
|
@@ -894,16 +894,16 @@ export class RenderContext {
|
|
|
894
894
|
* </head>
|
|
895
895
|
* <body>
|
|
896
896
|
* ${html}
|
|
897
|
-
* ${rc.importmap()} <!--
|
|
898
|
-
* ${rc.moduleEntry()} <!--
|
|
897
|
+
* ${rc.importmap()} <!-- Inject import map -->
|
|
898
|
+
* ${rc.moduleEntry()} <!-- Execute after import map -->
|
|
899
899
|
* ${rc.modulePreload()}
|
|
900
900
|
* </body>
|
|
901
901
|
* </html>
|
|
902
902
|
* `;
|
|
903
903
|
*
|
|
904
|
-
* // 2. JS
|
|
904
|
+
* // 2. JS file mode - Suitable for large applications
|
|
905
905
|
* const rc = await esmx.render({
|
|
906
|
-
* importmapMode: 'js' //
|
|
906
|
+
* importmapMode: 'js' // Use JS file mode
|
|
907
907
|
* });
|
|
908
908
|
* ```
|
|
909
909
|
*/
|
|
@@ -911,27 +911,27 @@ export class RenderContext {
|
|
|
911
911
|
return this._importMap.code;
|
|
912
912
|
}
|
|
913
913
|
/**
|
|
914
|
-
*
|
|
914
|
+
* Inject client entry module
|
|
915
915
|
* @description
|
|
916
|
-
* moduleEntry()
|
|
917
|
-
* 1.
|
|
918
|
-
* -
|
|
919
|
-
* -
|
|
920
|
-
* -
|
|
921
|
-
*
|
|
922
|
-
* 2.
|
|
923
|
-
* -
|
|
924
|
-
* -
|
|
925
|
-
* -
|
|
926
|
-
*
|
|
927
|
-
* 3.
|
|
928
|
-
* -
|
|
929
|
-
* -
|
|
930
|
-
* -
|
|
916
|
+
* The moduleEntry() method is used to inject the client's entry module:
|
|
917
|
+
* 1. **Injection Position**
|
|
918
|
+
* - Must be executed after importmap
|
|
919
|
+
* - Ensure the import map is correctly set before executing module code
|
|
920
|
+
* - Control the start timing of client activation (Hydration)
|
|
921
|
+
*
|
|
922
|
+
* 2. **Technical Reasons**
|
|
923
|
+
* - Serve as the entry point for client code
|
|
924
|
+
* - Need to wait for infrastructure (such as import maps) to be ready
|
|
925
|
+
* - Ensure correct module path resolution
|
|
926
|
+
*
|
|
927
|
+
* 3. **Use Cases**
|
|
928
|
+
* - Start the client application
|
|
929
|
+
* - Execute client activation
|
|
930
|
+
* - Initialize client state
|
|
931
931
|
*
|
|
932
932
|
* @example
|
|
933
933
|
* ```ts
|
|
934
|
-
* // 1.
|
|
934
|
+
* // 1. Basic usage
|
|
935
935
|
* rc.html = `
|
|
936
936
|
* <!DOCTYPE html>
|
|
937
937
|
* <html>
|
|
@@ -941,16 +941,16 @@ export class RenderContext {
|
|
|
941
941
|
* </head>
|
|
942
942
|
* <body>
|
|
943
943
|
* ${html}
|
|
944
|
-
* ${rc.importmap()} <!--
|
|
945
|
-
* ${rc.moduleEntry()} <!--
|
|
944
|
+
* ${rc.importmap()} <!-- Inject import map first -->
|
|
945
|
+
* ${rc.moduleEntry()} <!-- Then inject entry module -->
|
|
946
946
|
* ${rc.modulePreload()}
|
|
947
947
|
* </body>
|
|
948
948
|
* </html>
|
|
949
949
|
* `;
|
|
950
950
|
*
|
|
951
|
-
* // 2.
|
|
951
|
+
* // 2. Multiple entry configuration
|
|
952
952
|
* const rc = await esmx.render({
|
|
953
|
-
* entryName: 'mobile', //
|
|
953
|
+
* entryName: 'mobile', // Specify entry name
|
|
954
954
|
* params: { device: 'mobile' }
|
|
955
955
|
* });
|
|
956
956
|
* ```
|
|
@@ -959,28 +959,28 @@ export class RenderContext {
|
|
|
959
959
|
return `<script type="module">import "${this.esmx.name}/src/entry.client";<\/script>`;
|
|
960
960
|
}
|
|
961
961
|
/**
|
|
962
|
-
*
|
|
962
|
+
* Preload module dependencies
|
|
963
963
|
* @description
|
|
964
|
-
* modulePreload()
|
|
964
|
+
* The modulePreload() method is used to preload modules that may be needed later:
|
|
965
965
|
*
|
|
966
|
-
* 1.
|
|
967
|
-
* -
|
|
968
|
-
* -
|
|
969
|
-
* -
|
|
966
|
+
* 1. **Injection Position**
|
|
967
|
+
* - Must be after importmap and moduleEntry
|
|
968
|
+
* - Ensure the correct module path mapping is used
|
|
969
|
+
* - Avoid competing with first-screen rendering for resources
|
|
970
970
|
*
|
|
971
|
-
* 2.
|
|
972
|
-
* -
|
|
973
|
-
* -
|
|
974
|
-
* -
|
|
971
|
+
* 2. **Performance Optimization**
|
|
972
|
+
* - Preload modules that may be needed later
|
|
973
|
+
* - Improve runtime performance
|
|
974
|
+
* - Optimize on-demand loading experience
|
|
975
975
|
*
|
|
976
|
-
* 3.
|
|
977
|
-
* -
|
|
978
|
-
* -
|
|
979
|
-
* -
|
|
976
|
+
* 3. **Technical Reasons**
|
|
977
|
+
* - Need correct path resolution rules
|
|
978
|
+
* - Avoid duplicate loading
|
|
979
|
+
* - Control loading priority
|
|
980
980
|
*
|
|
981
981
|
* @example
|
|
982
982
|
* ```ts
|
|
983
|
-
* // 1.
|
|
983
|
+
* // 1. Basic usage
|
|
984
984
|
* rc.html = `
|
|
985
985
|
* <!DOCTYPE html>
|
|
986
986
|
* <html>
|
|
@@ -992,16 +992,16 @@ export class RenderContext {
|
|
|
992
992
|
* ${html}
|
|
993
993
|
* ${rc.importmap()}
|
|
994
994
|
* ${rc.moduleEntry()}
|
|
995
|
-
* ${rc.modulePreload()} <!--
|
|
995
|
+
* ${rc.modulePreload()} <!-- Preload module dependencies -->
|
|
996
996
|
* </body>
|
|
997
997
|
* </html>
|
|
998
998
|
* `;
|
|
999
999
|
*
|
|
1000
|
-
* // 2.
|
|
1000
|
+
* // 2. Use with async components
|
|
1001
1001
|
* const AsyncComponent = defineAsyncComponent(() =>
|
|
1002
1002
|
* import('./components/AsyncComponent.vue')
|
|
1003
1003
|
* );
|
|
1004
|
-
* // modulePreload
|
|
1004
|
+
* // modulePreload will automatically collect and preload dependencies of async components
|
|
1005
1005
|
* ```
|
|
1006
1006
|
*/
|
|
1007
1007
|
modulePreload() {
|