@modern-js/main-doc 2.67.3 → 2.67.5

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.
Files changed (39) hide show
  1. package/docs/en/apis/app/hooks/src/routes.mdx +70 -0
  2. package/docs/en/configure/app/output/filename.mdx +8 -3
  3. package/docs/en/configure/app/plugins.mdx +13 -33
  4. package/docs/en/configure/app/runtime/master-app.mdx +1 -5
  5. package/docs/en/configure/app/runtime/plugins.mdx +58 -0
  6. package/docs/en/configure/app/usage.mdx +1 -3
  7. package/docs/en/guides/advanced-features/_meta.json +1 -0
  8. package/docs/en/guides/advanced-features/bff.mdx +1 -1
  9. package/docs/en/guides/advanced-features/compatibility.mdx +1 -1
  10. package/docs/en/guides/advanced-features/custom-server.mdx +218 -0
  11. package/docs/en/guides/advanced-features/page-performance/inline-assets.mdx +2 -0
  12. package/docs/en/guides/advanced-features/page-performance/optimize-bundle.mdx +1 -1
  13. package/docs/en/guides/advanced-features/web-server.mdx +174 -1
  14. package/docs/en/guides/basic-features/data/data-cache.mdx +216 -1
  15. package/docs/en/guides/basic-features/data/data-fetch.mdx +2 -1
  16. package/docs/en/guides/basic-features/deploy.mdx +3 -1
  17. package/docs/en/guides/basic-features/html.mdx +3 -3
  18. package/docs/en/guides/basic-features/render/ssr.mdx +2 -2
  19. package/docs/en/guides/concept/entries.mdx +1 -1
  20. package/docs/en/guides/get-started/quick-start.mdx +1 -1
  21. package/docs/en/plugin/cli-plugins/api.mdx +6 -0
  22. package/docs/en/plugin/runtime-plugins/api.mdx +37 -12
  23. package/docs/en/tutorials/first-app/c05-loader.mdx +1 -1
  24. package/docs/zh/configure/app/output/filename.mdx +8 -0
  25. package/docs/zh/configure/app/plugins.mdx +3 -24
  26. package/docs/zh/configure/app/runtime/master-app.mdx +1 -5
  27. package/docs/zh/configure/app/runtime/plugins.mdx +58 -0
  28. package/docs/zh/configure/app/usage.mdx +1 -2
  29. package/docs/zh/guides/advanced-features/_meta.json +1 -0
  30. package/docs/zh/guides/advanced-features/custom-server.mdx +216 -0
  31. package/docs/zh/guides/advanced-features/web-server.mdx +174 -1
  32. package/docs/zh/guides/basic-features/data/data-cache.mdx +205 -1
  33. package/docs/zh/guides/basic-features/routes.mdx +72 -0
  34. package/docs/zh/plugin/cli-plugins/api.mdx +6 -0
  35. package/docs/zh/plugin/runtime-plugins/api.mdx +37 -12
  36. package/package.json +2 -2
  37. package/src/i18n/index.ts +1 -1
  38. /package/docs/en/configure/app/source/{mainEntryName.mdx → main-entry-name.mdx} +0 -0
  39. /package/docs/zh/configure/app/source/{mainEntryName.mdx → main-entry-name.mdx} +0 -0
@@ -2,7 +2,11 @@
2
2
  sidebar_position: 16
3
3
  ---
4
4
 
5
- # Custom Web Server
5
+ # Custom Web Server (Not Recommended)
6
+
7
+ :::warning
8
+ Custom Web Server is compatible but no longer recommended. For extending Server capabilities, please refer to [Custom Server](/guides/advanced-features/custom-server.html). For migration guide, see [Migrate to the New Version of Custom Server](/guides/advanced-features/web-server.html#migrate-to-the-new-version-of-custom-server).
9
+ :::
6
10
 
7
11
  Modern.js encapsulates most server-side capabilities required by projects, typically eliminating the need for server-side development. However, in certain scenarios such as user authentication, request preprocessing, or adding page skeletons, custom server-side logic may still be necessary.
8
12
 
@@ -96,3 +100,172 @@ Best practices when using Hooks:
96
100
  :::info
97
101
  For detailed API and more usage, see [Hook](/apis/app/runtime/web-server/hook).
98
102
  :::
103
+
104
+
105
+ ## Migrate to the New Version of Custom Server
106
+
107
+ ### Migration Background
108
+
109
+ Modern.js Server is continuously evolving to provide more powerful features. We have optimized the definition and usage of middleware and Server plugins.
110
+ While the old custom Web Server approach is still compatible, we strongly recommend migrating according to this guide to fully leverage the advantages of the new version.
111
+
112
+ ### Migration Steps
113
+
114
+ 1. Upgrade Modern.js version to x.67.5 or above.
115
+ 2. Configure middleware or plugins in `server/modern.server.ts` according to the new definition method.
116
+ 3. Migrate the custom logic in `server/index.ts` to middleware or plugins, and update your code with reference to the differences between `Context` and `Next`.
117
+
118
+ ### Context Differences
119
+
120
+ In the new version, the middleware handler type is Hono's `MiddlewareHandler`, meaning the `Context` type is `Hono Context`. The differences from the old custom Web Server's `Context` are as follows:
121
+
122
+
123
+ #### UnstableMiddleware
124
+
125
+
126
+ ```ts
127
+ type Body = ReadableStream | ArrayBuffer | string | null;
128
+
129
+ type UnstableMiddlewareContext<
130
+ V extends Record<string, unknown> = Record<string, unknown>,
131
+ > = {
132
+ request: Request;
133
+ response: Response;
134
+ get: Get<V>;
135
+ set: Set<V>;
136
+ // Current Matched Routing Information
137
+ route: string;
138
+ header: (name: string, value: string, options?: { append?: boolean }) => void;
139
+ status: (code: number) => void;
140
+ redirect: (location: string, status?: number) => Response;
141
+ body: (data: Body, init?: ResponseInit) => Response;
142
+ html: (
143
+ data: string | Promise<string>,
144
+ init?: ResponseInit,
145
+ ) => Response | Promise<Response>;
146
+ };
147
+ ```
148
+
149
+ Differences between UnstableMiddleware Context and Hono Context:
150
+
151
+ | UnstableMiddleware | Hono | Description |
152
+ | :----------------------- | :---------------------------- | :------------------------------------------------------------------------ |
153
+ | `c.request` | `c.req.raw` | Refer to [HonoRequest raw](https://hono.dev/docs/api/request#raw) documentation |
154
+ | `c.response` | `c.res` | Refer to [Hono Context res](https://hono.dev/docs/api/context#res) documentation |
155
+ | `c.route` | `c.get('route')` | Get application context information. |
156
+ | `loaderContext.get` | `honoContext.get` | After injecting data using `c.set`, consume in dataLoader: the old version uses `loaderContext.get`, refer to the new version in [Plugin](/guides/advanced-features/custom-server.html#using-posture-2) example |
157
+
158
+
159
+ #### Middleware
160
+
161
+ ```ts
162
+ type MiddlewareContext = {
163
+ response: {
164
+ set: (key: string, value: string) => void;
165
+ status: (code: number) => void;
166
+ getStatus: () => number;
167
+ cookies: {
168
+ set: (key: string, value: string, options?: any) => void;
169
+ clear: () => void;
170
+ };
171
+ raw: (
172
+ body: string,
173
+ { status, headers }: { status: number; headers: Record<string, any> },
174
+ ) => void;
175
+ locals: Record<string, any>;
176
+ };
177
+ request: {
178
+ url: string;
179
+ host: string;
180
+ pathname: string;
181
+ query: Record<string, any>;
182
+ cookie: string;
183
+ cookies: {
184
+ get: (key: string) => string;
185
+ };
186
+ headers: IncomingHttpHeaders;
187
+ };
188
+ source: {
189
+ req: IncomingMessage;
190
+ res: ServerResponse;
191
+ };
192
+ };
193
+
194
+ ```
195
+
196
+ Differences between Middleware `Context` and Hono `Context`:
197
+ | UnstableMiddleware | Hono | Description |
198
+ | :----------------------- | :---------------------------- | :--------------------------------------------------------------------------- |
199
+ | `c.request.cookie` | `c.req.cookie()` | Refer to [Hono Cookie Helper](https://hono.dev/docs/helpers/cookie) documentation |
200
+ | `c.request.pathname` | `c.req.path` | Refer to [HonoRequest path](https://hono.dev/docs/api/request#path) documentation |
201
+ | `c.request.url` | - | Hono `c.req.url` provides the full request URL, calculate manually from URL |
202
+ | `c.request.host` | `c.req.header('Host')` | Obtain host through header |
203
+ | `c.request.query` | `c.req.query()` | Refer to [HonoRequest query](https://hono.dev/docs/api/request#query) documentation |
204
+ | `c.request.headers` | `c.req.header()` | Refer to [HonoRequest header](https://hono.dev/docs/api/request#header) documentation |
205
+ | `c.response.set` | `c.res.headers.set` | Example: `c.res.headers.set('custom-header', '1')` |
206
+ | `c.response.status` | `c.status` | Example: `c.status(201)` |
207
+ | `c.response.cookies` | `c.header` | Example: `c.header('Set-Cookie', 'user_id=123')` |
208
+ | `c.response.raw` | `c.res` | Refer to [Hono Context res](https://hono.dev/docs/api/context#res) documentation |
209
+
210
+ #### Hook
211
+
212
+ ```ts
213
+ type HookContext = {
214
+ response: {
215
+ set: (key: string, value: string) => void;
216
+ status: (code: number) => void;
217
+ getStatus: () => number;
218
+ cookies: {
219
+ set: (key: string, value: string, options?: any) => void;
220
+ clear: () => void;
221
+ };
222
+ raw: (
223
+ body: string,
224
+ { status, headers }: { status: number; headers: Record<string, any> },
225
+ ) => void;
226
+ };
227
+ request: {
228
+ url: string;
229
+ host: string;
230
+ pathname: string;
231
+ query: Record<string, any>;
232
+ cookie: string;
233
+ cookies: {
234
+ get: (key: string) => string;
235
+ };
236
+ headers: IncomingHttpHeaders;
237
+ };
238
+ };
239
+
240
+ type AfterMatchContext = HookContext & {
241
+ router: {
242
+ redirect: (url: string, status: number) => void;
243
+ rewrite: (entry: string) => void;
244
+ };
245
+ };
246
+
247
+ type AfterRenderContext = {
248
+ template: {
249
+ get: () => string;
250
+ set: (html: string) => void;
251
+ prependHead: (fragment: string) => void;
252
+ appendHead: (fragment: string) => void;
253
+ prependBody: (fragment: string) => void;
254
+ appendBody: (fragment: string) => void;
255
+ };
256
+ };
257
+ ```
258
+
259
+ Hook Context is mostly consistent with Middleware Context, so we need to pay extra attention to the additional parts of different Hooks.
260
+
261
+ | UnstableMiddleware | Hono | Description |
262
+ | :----------------------- | :---------------------------- | :------------------------------------ |
263
+ | `router.redirect` | `c.redirect` | Refer to [Hono Context redirect](https://hono.dev/docs/api/context#redirect) documentation |
264
+ | `router.rewrite` | - | No corresponding capability provided at the moment |
265
+ | template API | `c.res` | Refer to [Hono Context res](https://hono.dev/docs/api/context#res) documentation |
266
+
267
+
268
+ ### Differences in Next API
269
+
270
+ In Middleware and Hooks, the render function executes even without invoking `next`.
271
+ In the new design, subsequent Middleware will only execute if the `next` function is invoked.
@@ -4,7 +4,7 @@ sidebar_position: 4
4
4
  ---
5
5
  # Data Caching
6
6
 
7
- The `cache` function allows you to cache the results of data fetching or computation.
7
+ The `cache` function allows you to cache the results of data fetching or computation, Compared to full-page [rendering cache](/guides/basic-features/render/ssr-cache), it provides more fine-grained control over data granularity and is applicable to various scenarios such as Client-Side Rendering (CSR), Server-Side Rendering (SSR), and API services (BFF).
8
8
 
9
9
  :::info
10
10
  X.65.5 and above versions are required
@@ -12,6 +12,15 @@ X.65.5 and above versions are required
12
12
 
13
13
  ## Basic Usage
14
14
 
15
+ :::note
16
+
17
+ If you use the `cache` function in BFF, you should import the cache funtion from `@modern-js/server-runtime/cache`
18
+
19
+ `import { cache } from '@modern-js/server-runtime/cache'`
20
+
21
+ :::
22
+
23
+
15
24
  ```ts
16
25
  import { cache } from '@modern-js/runtime/cache';
17
26
  import { fetchUserData } from './api';
@@ -34,6 +43,8 @@ const loader = async () => {
34
43
  - `tag`: Tag to identify the cache, which can be used to invalidate the cache
35
44
  - `maxAge`: Cache validity period (milliseconds)
36
45
  - `revalidate`: Time window for revalidating the cache (milliseconds), similar to HTTP Cache-Control's stale-while-revalidate functionality
46
+ - `getKey`: Simplified cache key generation function based on function parameters
47
+ - `customKey`: Custom cache key function
37
48
 
38
49
  The type of the `options` parameter is as follows:
39
50
 
@@ -42,6 +53,12 @@ interface CacheOptions {
42
53
  tag?: string | string[];
43
54
  maxAge?: number;
44
55
  revalidate?: number;
56
+ getKey?: <Args extends any[]>(...args: Args) => string;
57
+ customKey?: <Args extends any[]>(options: {
58
+ params: Args;
59
+ fn: (...args: Args) => any;
60
+ generatedKey: string;
61
+ }) => string | symbol;
45
62
  }
46
63
  ```
47
64
 
@@ -153,6 +170,204 @@ revalidateTag('dashboard-stats'); // Invalidates the cache for both getDashboard
153
170
  ```
154
171
 
155
172
 
173
+ #### `getKey` Parameter
174
+
175
+ The `getKey` parameter simplifies cache key generation, especially useful when you only need to rely on part of the function parameters to differentiate caches. It's a function that receives the same parameters as the original function and returns a string or number as the cache key:
176
+
177
+ ```ts
178
+ import { cache, CacheTime } from '@modern-js/runtime/cache';
179
+ import { fetchUserData } from './api';
180
+
181
+ const getUser = cache(
182
+ async (userId, options) => {
183
+ // Here options might contain many configurations, but we only want to cache based on userId
184
+ return await fetchUserData(userId, options);
185
+ },
186
+ {
187
+ maxAge: CacheTime.MINUTE * 5,
188
+ // Only use the first parameter (userId) as the cache key
189
+ getKey: (userId, options) => userId,
190
+ }
191
+ );
192
+
193
+ // The following two calls will share the cache because getKey only uses userId
194
+ await getUser(123, { language: 'en' });
195
+ await getUser(123, { language: 'fr' }); // Cache hit, won't request again
196
+
197
+ // Different userId will use different cache
198
+ await getUser(456, { language: 'en' }); // Won't hit cache, will request again
199
+ ```
200
+
201
+ You can also use Modern.js's `generateKey` function together with getKey to generate the cache key:
202
+
203
+ :::info
204
+
205
+ The `generateKey` function in Modern.js ensures that a consistent and unique key is generated even if object property orders change, guaranteeing stable caching.
206
+
207
+ :::
208
+
209
+ ```ts
210
+ import { cache, CacheTime, generateKey } from '@modern-js/runtime/cache';
211
+ import { fetchUserData } from './api';
212
+
213
+ const getUser = cache(
214
+ async (userId, options) => {
215
+ return await fetchUserData(userId, options);
216
+ },
217
+ {
218
+ maxAge: CacheTime.MINUTE * 5,
219
+ getKey: (userId, options) => generateKey(userId),
220
+ }
221
+ );
222
+ ```
223
+
224
+ Additionally, `getKey` can also return a numeric type as a cache key:
225
+
226
+ ```ts
227
+ const getUserById = cache(
228
+ fetchUserDataById,
229
+ {
230
+ maxAge: CacheTime.MINUTE * 5,
231
+ // Directly use the numeric ID as the cache key
232
+ getKey: (id) => id,
233
+ }
234
+ );
235
+
236
+ await getUserById(42); // Uses 42 as the cache key
237
+ ```
238
+
239
+ #### `customKey` parameter
240
+
241
+ The `customKey` parameter is used to customize the cache key. It is a function that receives an object with the following properties and returns a string or Symbol type as the cache key:
242
+
243
+ - `params`: Array of arguments passed to the cached function
244
+ - `fn`: Reference to the original function being cached
245
+ - `generatedKey`: Cache key automatically generated by the framework based on input parameters
246
+
247
+ :::info
248
+
249
+ Generally, the cache will be invalidated in the following scenarios:
250
+ 1. The referenced cached function changes
251
+ 2. The function's input parameters change
252
+ 3. The maxAge condition is no longer satisfied
253
+ 4. The `revalidateTag` method has been called
254
+
255
+ `customKey` can be used in scenarios where function references are different but shared caching is desired. If it's just for customizing the cache key, it is recommended to use `getKey`.
256
+
257
+ :::
258
+
259
+ This is very useful in some scenarios, such as when the function reference changes , but you want to still return the cached data.
260
+
261
+ ```ts
262
+ import { cache } from '@modern-js/runtime/cache';
263
+ import { fetchUserData } from './api';
264
+
265
+ // Different function references, but share the same cache via customKey
266
+ const getUserA = cache(
267
+ fetchUserData,
268
+ {
269
+ maxAge: CacheTime.MINUTE * 5,
270
+ customKey: ({ params }) => {
271
+ // Return a stable string as the cache key
272
+ return `user-${params[0]}`;
273
+ },
274
+ }
275
+ );
276
+
277
+ // Even if the function reference changes,
278
+ // as long as customKey returns the same value, the cache will be hit
279
+ const getUserB = cache(
280
+ (...args) => fetchUserData(...args), // New function reference
281
+ {
282
+ maxAge: CacheTime.MINUTE * 5,
283
+ customKey: ({ params }) => {
284
+ // Return the same key as getUserA
285
+ return `user-${params[0]}`;
286
+ },
287
+ }
288
+ );
289
+
290
+ // You can also use Symbol as a cache key (usually used to share cache within the same application)
291
+ const USER_CACHE_KEY = Symbol('user-cache');
292
+ const getUserC = cache(
293
+ fetchUserData,
294
+ {
295
+ maxAge: CacheTime.MINUTE * 5,
296
+ customKey: () => USER_CACHE_KEY,
297
+ }
298
+ );
299
+
300
+ // You can utilize the generatedKey parameter to modify the default key
301
+ const getUserD = cache(
302
+ fetchUserData,
303
+ {
304
+ customKey: ({ generatedKey }) => `prefix-${generatedKey}`,
305
+ }
306
+ );
307
+ ```
308
+
309
+ #### `onCache` Parameter
310
+
311
+ The `onCache` parameter allows you to track cache statistics such as hit rate. It's a callback function that receives information about each cache operation, including the status, key, parameters, and result.
312
+
313
+ ```ts
314
+ import { cache, CacheTime } from '@modern-js/runtime/cache';
315
+
316
+ // Track cache statistics
317
+ const stats = {
318
+ total: 0,
319
+ hits: 0,
320
+ misses: 0,
321
+ stales: 0,
322
+ hitRate: () => stats.hits / stats.total
323
+ };
324
+
325
+ const getUser = cache(
326
+ fetchUserData,
327
+ {
328
+ maxAge: CacheTime.MINUTE * 5,
329
+ onCache({ status, key, params, result }) {
330
+ // status can be 'hit', 'miss', or 'stale'
331
+ stats.total++;
332
+
333
+ if (status === 'hit') {
334
+ stats.hits++;
335
+ } else if (status === 'miss') {
336
+ stats.misses++;
337
+ } else if (status === 'stale') {
338
+ stats.stales++;
339
+ }
340
+
341
+ console.log(`Cache ${status} for key: ${String(key)}`);
342
+ console.log(`Current hit rate: ${stats.hitRate() * 100}%`);
343
+ }
344
+ }
345
+ );
346
+
347
+ // Usage example
348
+ await getUser(1); // Cache miss
349
+ await getUser(1); // Cache hit
350
+ await getUser(2); // Cache miss
351
+ ```
352
+
353
+ The `onCache` callback receives an object with the following properties:
354
+
355
+ - `status`: The cache operation status, which can be:
356
+ - `hit`: Cache hit, returning cached content
357
+ - `miss`: Cache miss, executing the function and caching the result
358
+ - `stale`: Cache hit but data is stale, returning cached content while revalidating in the background
359
+ - `key`: The cache key, which is either the result of `customKey` or the default generated key
360
+ - `params`: The parameters passed to the cached function
361
+ - `result`: The result data (either from cache or newly computed)
362
+
363
+ This callback is only invoked when the `options` parameter is provided. When using the cache function without options, the `onCache` callback is not called.
364
+
365
+ The `onCache` callback is useful for:
366
+ - Monitoring cache performance
367
+ - Calculating hit rates
368
+ - Logging cache operations
369
+ - Implementing custom metrics
370
+
156
371
  ### Storage
157
372
 
158
373
  Currently, both client and server caches are stored in memory.
@@ -149,9 +149,10 @@ Having the `loader` function run only on the server in SSR applications brings s
149
149
  - **Simplifies usage**: Guarantees consistent data-fetching methods in SSR applications, so developers don't have to distinguish between client and server code.
150
150
  - **Reduces client bundle size**: Moves logic code and dependencies from the client to the server.
151
151
  - **Improves maintainability**: Less direct influence of data logic on front-end UI and avoids issues of accidentally including server dependencies in the client bundle or vice versa.
152
+
152
153
  :::
153
154
 
154
- We recommend using the `fetch` API in `loader` functions to make requests. Modern.js provides a default polyfill for the `fetch` API, allowing it to be used on the server. This means you can fetch data in a consistent manner whether in CSR or SSR:
155
+ We recommend using the `fetch` API in `loader` functions to make requests. Since `fetch` works similarly on the client and server, you can fetch data in a consistent manner whether in CSR or SSR:
155
156
 
156
157
  ```tsx
157
158
  export async function loader() {
@@ -136,13 +136,14 @@ Full-stack projects refer to projects that use Custom Web Server, SSR or BFF. Th
136
136
  :::info
137
137
  1. Currently, Modern.js does not support deployment on Netlify Edge Functions. We will support it in future versions.
138
138
  2. You can refer to the [deployment project example](https://github.com/web-infra-dev/modern-js-examples/tree/main/examples/modern-js-deploy-ssr).
139
+
139
140
  :::
140
141
 
141
142
 
142
143
  ### Monorepo
143
144
 
144
145
  :::info
145
- The following guide is mainly for full-stack projects, for pure CSR projects, just follow [Pure Frontend Project](#Pure Frontend Project) to deploy.
146
+ The following guide is mainly for full-stack projects, for pure CSR projects, just follow [Pure Frontend Project](#pure-front-end-project-1) to deploy.
146
147
  :::
147
148
 
148
149
  For Monorepo projects, in addition to building our current project, you also need to build other sub-projects in the repository that the current project depends on.
@@ -330,6 +331,7 @@ For branch deployment, follow these steps:
330
331
  :::info
331
332
  1. Running `MODERNJS_DEPLOY=ghPages modern deploy` will build the production output for GitHub in the .output directory.
332
333
  2. You can refer to the [project](https://github.com/web-infra-dev/modern-js-examples/tree/main/examples/modern-js-deploy-csr)
334
+
333
335
  :::
334
336
 
335
337
  For GitHub Actions deployment, select Settings > Pages > Source > GitHub Actions, and add a workflow file to the project. You can refer to the [example](https://github.com/web-infra-dev/modern-js-examples/tree/main/examples/modern-js-deploy-csr).
@@ -8,7 +8,7 @@ Modern.js provides **JSX syntax** and **HTML(EJS) syntax** to customize the HTML
8
8
 
9
9
  ## JSX Syntax
10
10
 
11
- According to Modern.js conventions, you can create a `Document.[jt]sx` file under `src/` or the entry directory and default export a component". The rendering result of this component can be used as the HTML template of the entry.
11
+ According to Modern.js conventions, you can create a `Document.[jt]sx` file under `src/` or the entry directory and default export a component. The rendering result of this component can be used as the HTML template of the entry.
12
12
 
13
13
  For example, consider the following directory structure:
14
14
 
@@ -218,9 +218,9 @@ The implementation of custom HTML fragments is to merge the fragments with the b
218
218
 
219
219
  :::
220
220
 
221
- ### Custom the entire HTML Template
221
+ ### Customize the entire HTML Template
222
222
 
223
- In some cases, HTML fragments may be is not better meet the customization requirements. Modern.js provides a fully customized way.
223
+ In some cases, HTML fragments may not offer enough control. Modern.js provides a fully customized way.
224
224
 
225
225
  :::caution Note
226
226
  It is generally not recommended to directly override the default HTML template, as some functional options may be lost. If it is truly necessary to customize the entire HTML template, it is recommended to modify based on the built-in template as needed.
@@ -1,6 +1,6 @@
1
1
  # Server-Side Rendering
2
2
 
3
- Server-Side Rendering (SSR) involves rendering the HTML content of a webpage-side and then sending the fully-rendered page to the browser. The browser only needs to display the page without additional rendering.
3
+ Server-Side Rendering (SSR) involves rendering the HTML content of a webpage server-side and then sending the fully-rendered page to the browser. The browser only needs to display the page without additional rendering.
4
4
 
5
5
  The main advantages are:
6
6
 
@@ -320,4 +320,4 @@ In this case, the `epicMiddleware` instance is created outside the component, an
320
320
 
321
321
  This code does not cause issues on the client-side. However, in SSR, the Middleware instance remains non-disposable. Each time the component renders, calling `epicMiddleware.run(rootEpic)` adds new event bindings internally, causing the entire object to grow continuously, ultimately affecting application performance.
322
322
 
323
- Such issues are not easily noticed in CSR. When transitioning from CSR to SSR, if you're unsure whether your application has such hidden pitfalls, consider stress testing the application.
323
+ Such issues are not easily noticed in CSR. When transitioning from CSR to SSR, if you're unsure whether your application has such hidden pitfalls, consider stress testing the application.
@@ -76,7 +76,7 @@ By default, Modern.js scans the files under `src/` before starting the project,
76
76
 
77
77
  :::tip
78
78
 
79
- - You can custom the recognition directory for page entries by using [source.entriesDir](/configure/app/source/entries-dir).
79
+ - You can customize the recognition directory for page entries by using [source.entriesDir](/configure/app/source/entries-dir).
80
80
  - If you need to customize the entry points, please refer to [Custom Entries](#custom-entries).
81
81
 
82
82
  :::
@@ -148,7 +148,7 @@ info Starting production server...
148
148
  > Network: http://192.168.0.1:8080/
149
149
  ```
150
150
 
151
- Open `http://localhost:8000/` in the browser, and the content should be consistent with that of `pnpm run dev`.
151
+ Open `http://localhost:8080/` in the browser, and the content should be consistent with that of `pnpm run dev`.
152
152
 
153
153
  ## Deployment
154
154
 
@@ -2,6 +2,12 @@
2
2
 
3
3
  This document details the API for Modern.js CLI plugins. CLI plugins allow you to extend and customize the functionality of Modern.js projects during the build and development process.
4
4
 
5
+ :::info
6
+
7
+ CLI plugins need to be configured via the [`plugins`](/configure/app/plugins) field in `modern.config.ts`.
8
+
9
+ :::
10
+
5
11
  ## Plugin Basic Structure
6
12
 
7
13
  A typical CLI plugin structure is as follows:
@@ -2,6 +2,12 @@
2
2
 
3
3
  Modern.js's Runtime Plugins allow you to extend and modify the behavior of your application during its React code execution. With Runtime Plugins, you can easily perform initialization tasks, implement React Higher-Order Component (HOC) wrapping, and more.
4
4
 
5
+ :::info
6
+
7
+ Runtime plugins need to be configured via the [`plugins`](/configure/app/runtime/plugins) field in `src/modern.runtime.ts`.
8
+
9
+ :::
10
+
5
11
  ## Plugin Structure
6
12
 
7
13
  A typical Runtime Plugin looks like this:
@@ -150,16 +156,35 @@ Allows you to wrap the application's root component with a custom React componen
150
156
  You can combine multiple hooks to implement more complex functionality. For example, you can use `onBeforeRender` to fetch data and then use `wrapRoot` to pass the data to the entire application via Context:
151
157
 
152
158
  ```ts
153
- api.onBeforeRender(async (context) => {
154
- const data = await fetchData(context.req);
155
- context.data = data;
156
- });
157
-
158
- api.wrapRoot((App) => {
159
- return (props) => (
160
- <DataContext.Provider value={props.data}>
161
- <App {...props} />
162
- </DataContext.Provider>
163
- );
164
- });
159
+ import { RuntimePluginFuture, RuntimeReactContext } from '@modern-js/runtime';
160
+ import { useContext, createContext } from 'react';
161
+
162
+ export const ThemeContext = createContext<{ theme: string } | null>(null);
163
+
164
+ export const themePlugin = (): RuntimePluginFuture => {
165
+ return {
166
+ name: 'theme-plugin',
167
+ setup: api => {
168
+ api.onBeforeRender(async context => {
169
+ const userPreference = await fetch('/api/user/theme-settings').then(
170
+ res => res.json(),
171
+ );
172
+ context.data = {
173
+ theme: userPreference.theme,
174
+ };
175
+ });
176
+
177
+ api.wrapRoot(App => {
178
+ return props => {
179
+ const context = useContext(RuntimeReactContext);
180
+ return (
181
+ <ThemeContext.Provider value={context.data}>
182
+ <App {...props} />
183
+ </ThemeContext.Provider>
184
+ );
185
+ };
186
+ });
187
+ },
188
+ };
189
+ };
165
190
  ```
@@ -7,7 +7,7 @@ In the previous chapter, we learned how to add client route.
7
7
 
8
8
  In this chapter, we will learn how to add **Loader** to the routing component.
9
9
 
10
- By far, we have provided data to components through hardcoding. If you want to get data from the remote, you usually use `useEffect` to do it. But when SSR is enabled, `useEffect` will not be executed at the server level, so this SSR can only render a very limited UI.
10
+ So far, we have provided data to components through hardcoding. If you want to get data from the remote, you usually use `useEffect` to do it. But when SSR is enabled, `useEffect` will not be executed at the server level, so this SSR can only render a very limited UI.
11
11
 
12
12
  Modern.js provides the ability of Data Loader to support homogeneous data acquisition in components to maximize the value of SSR.
13
13
 
@@ -3,6 +3,14 @@ title: filename
3
3
  configName: output.filename
4
4
  ---
5
5
 
6
+ :::warning
7
+
8
+ 在 Modern.js 开发阶段,或是使用 Modern.js 服务器部署应用时,应避免使用该配置修改 html 产物文件名,会导致页面 404。
9
+
10
+ 通常情况下,无需修改 html 产物文件名。常见的需求是将 `main.html` 修改为 `index.html`,请使用 [source.mainEntryName](/configure/app/source/main-entry-name)。
11
+
12
+ :::
13
+
6
14
  # output.filename
7
15
 
8
16
  - **类型:**
@@ -1,39 +1,18 @@
1
- ---
2
- sidebar_position: 9
3
- ---
4
-
5
1
  # plugins
6
2
 
7
3
  - **类型:** `CliPlugin[]`
8
4
  - **默认值:** `[]`
9
5
 
10
- 用于配置自定义的 Modern.js 框架插件。
11
-
12
- 自定义插件的编写方式请参考 [如何编写插件](/plugin/plugin-system)。
6
+ 用于配置自定义的 Modern.js 框架 CLI 插件。自定义 CLI 插件的编写方式请参考 [如何编写 CLI 插件](/plugin/introduction.html#cli-插件)。
13
7
 
14
8
  ## 注意事项
15
9
 
16
- 该选项**用于配置框架插件**,如果你需要配置其他类型的插件,请选择对应的配置方式:
10
+ 该选项**用于配置框架 CLI 插件**,如果你需要配置其他类型的插件,请选择对应的配置方式:
17
11
 
18
12
  - 配置 Rsbuild 插件,请使用 [builderPlugins](/configure/app/builder-plugins) 配置项。
19
13
  - 配置 Rspack 或 webpack 插件,请使用 [tools.bundlerChain](/configure/app/tools/bundler-chain) 配置项。
20
14
  - 配置 Babel 插件,请使用 [tools.babel](/configure/app/tools/babel) 配置项。
21
-
22
- ## 插件类型
23
-
24
- Modern.js 中内置了三种不同的框架插件:
25
-
26
- - `CLI 插件`,适用于本地开发、编译构建阶段,可以在命令行和编译阶段扩展各种能力。
27
- - `Server 插件`,适用于服务端。
28
- - `Runtime 插件`,适用于前端运行时。
29
-
30
- 目前 Modern.js 开放了自定义 CLI 插件的能力,Server 插件和 Runtime 插件会在后续开放。
31
-
32
- ## 插件执行顺序
33
-
34
- 默认情况下,自定义插件会按照 `plugins` 数组的顺序依次执行,Modern.js 内置插件的执行时机早于自定义插件。
35
-
36
- 当插件内部使用了控制顺序的相关字段,比如 `pre`、`post` 时,会基于声明的字段对执行顺序进行调整,详见 [插件结构](/plugin/plugin-system)。
15
+ - 配置框架 Runtime 插件,请使用 [runtime 配置文件 plugins](/configure/app/runtime/plugins) 配置项。
37
16
 
38
17
  ## 示例
39
18