@modern-js/main-doc 2.42.1 → 2.43.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. package/docs/en/apis/app/runtime/web-server/middleware.mdx +3 -3
  2. package/docs/en/configure/app/server/ssr.mdx +2 -0
  3. package/docs/en/guides/advanced-features/inline-assets.mdx +161 -0
  4. package/docs/en/guides/advanced-features/optimize-bundle.mdx +8 -7
  5. package/docs/en/guides/advanced-features/ssr/_category_.json +8 -0
  6. package/docs/en/guides/advanced-features/ssr/cache.mdx +186 -0
  7. package/docs/en/guides/advanced-features/ssr/index.mdx +22 -0
  8. package/docs/en/guides/advanced-features/ssr/stream.mdx +236 -0
  9. package/docs/en/guides/advanced-features/ssr/usage.mdx +341 -0
  10. package/docs/en/guides/basic-features/alias.mdx +80 -2
  11. package/docs/en/guides/basic-features/css-modules.mdx +228 -0
  12. package/docs/en/guides/basic-features/css.mdx +2 -13
  13. package/docs/en/guides/basic-features/json-files.mdx +106 -0
  14. package/docs/en/guides/basic-features/output-files.mdx +173 -0
  15. package/docs/en/guides/basic-features/static-assets.mdx +165 -0
  16. package/docs/en/guides/basic-features/svg-assets.mdx +155 -0
  17. package/docs/en/guides/basic-features/wasm-assets.mdx +66 -0
  18. package/docs/en/guides/get-started/quick-start.mdx +1 -1
  19. package/docs/en/guides/get-started/tech-stack.mdx +1 -1
  20. package/docs/en/guides/topic-detail/framework-plugin/introduction.mdx +63 -16
  21. package/docs/zh/apis/app/runtime/web-server/middleware.mdx +4 -4
  22. package/docs/zh/configure/app/server/ssr.mdx +2 -0
  23. package/docs/zh/guides/advanced-features/inline-assets.mdx +162 -0
  24. package/docs/zh/guides/advanced-features/optimize-bundle.mdx +8 -7
  25. package/docs/zh/guides/advanced-features/ssr/_category_.json +8 -0
  26. package/docs/zh/guides/advanced-features/ssr/cache.mdx +189 -0
  27. package/docs/zh/guides/advanced-features/ssr/index.mdx +22 -0
  28. package/docs/zh/guides/advanced-features/ssr/stream.mdx +240 -0
  29. package/docs/zh/guides/advanced-features/{ssr.mdx → ssr/usage.mdx} +7 -225
  30. package/docs/zh/guides/basic-features/alias.mdx +80 -2
  31. package/docs/zh/guides/basic-features/css-modules.mdx +229 -0
  32. package/docs/zh/guides/basic-features/css.mdx +2 -13
  33. package/docs/zh/guides/basic-features/data/data-write.mdx +1 -1
  34. package/docs/zh/guides/basic-features/json-files.mdx +106 -0
  35. package/docs/zh/guides/basic-features/output-files.mdx +173 -0
  36. package/docs/zh/guides/basic-features/static-assets.mdx +165 -0
  37. package/docs/zh/guides/basic-features/svg-assets.mdx +157 -0
  38. package/docs/zh/guides/basic-features/wasm-assets.mdx +66 -0
  39. package/docs/zh/guides/get-started/quick-start.mdx +1 -1
  40. package/docs/zh/guides/get-started/tech-stack.mdx +1 -1
  41. package/docs/zh/guides/topic-detail/framework-plugin/introduction.mdx +61 -16
  42. package/package.json +7 -7
@@ -91,7 +91,7 @@ The execution of the `next` function does not affect built-in processes, only co
91
91
  ```ts
92
92
  export const Middleware = () => async (ctx, next) => {
93
93
  const start = Date.now();
94
- ctx.res.once('finish', () => {
94
+ ctx.source.res.once('finish', () => {
95
95
  console.log(Date.now() - start);
96
96
  });
97
97
  };
@@ -103,8 +103,8 @@ Modern.js provides `res.locals` to store local variables for the current request
103
103
 
104
104
  ```ts
105
105
  export const Middleware = () => async (ctx, next) => {
106
- ctx.res.locals.id = 'Modern.js';
107
- ctx.res.locals.rpc = createRpcInstance();
106
+ ctx.response.locals.id = 'Modern.js';
107
+ ctx.response.locals.rpc = createRpcInstance();
108
108
  };
109
109
  ```
110
110
 
@@ -30,6 +30,7 @@ When the value type is `Object`, the following properties can be configured:
30
30
  - `inlineScript`: `boolean = true`, by default, SSR data is injected into HTML as inline scripts and assigned directly to global variables. Configure `false` to distribute JSON instead of assigning to global variables.
31
31
  - `disablePrerender`: `boolean = fasle`, To ensure compatibility with the old data request method (`useLoader`), by default, Modern.js performs pre-rendering of components.
32
32
  However, if developers want to reduce one rendering when there is no use of the useLoader API in your project, you can set the configuration `disablePrerender=true`.
33
+ - `unsafeHeaders`: `string[] = []`, For safety reasons, Modern.js does not add excessive content to SSR_DATA. Developers can use this configuration to specify the headers that need to be injected.
33
34
 
34
35
  ```ts title="modern.config.ts"
35
36
  export default defineConfig({
@@ -38,6 +39,7 @@ export default defineConfig({
38
39
  forceCSR: true,
39
40
  mode: 'stream',
40
41
  inlineScript: false,
42
+ unsafeHeaders: ['User-Agent'],
41
43
  },
42
44
  },
43
45
  });
@@ -0,0 +1,161 @@
1
+ ---
2
+ sidebar_position: 13
3
+ ---
4
+
5
+ # Inline Static Assets
6
+
7
+ Inline static assets refer to the practice of including the content of a static asset directly in a HTML or JS file, instead of linking to an external file. This can improve the performance of a website by reducing the number of HTTP requests that the browser has to make to load the page.
8
+
9
+ However, static assets inlining also has some disadvantages, such as increasing the size of a single file, which may lead to slower loading. Therefore, in the actual scenario, it is necessary to decide whether to use static assets inlining according to the specific situation.
10
+
11
+ Modern.js will automatically inline static assets that are less than 10KB, but sometimes you may need to manually control assets to force them to be inlined or not, and this document explains how to precisely control the inlining behavior of static assets.
12
+
13
+ ## Automatic Inlining
14
+
15
+ By default, Modern.js will inline assets when the file size of is less than a threshold (the default is 10KB). When inlined, the asset will be converted to a Base64 encoded string and will no longer send a separate HTTP request. When the file size is greater than this threshold, it is loaded as a separate file with a separate HTTP request.
16
+
17
+ The threshold can be modified with the [output.dataUriLimit](/configure/app/output/data-uri-limit) config. For example, set the threshold of images to 5000 Bytes, and set media assets not to be inlined:
18
+
19
+ ```ts
20
+ export default {
21
+ output: {
22
+ dataUriLimit: {
23
+ image: 5000,
24
+ media: 0,
25
+ },
26
+ },
27
+ };
28
+ ```
29
+
30
+ ## Force Inlining
31
+
32
+ You can force an asset to be inlined by adding the `inline` query when importing the asset, regardless of whether the asset's size is smaller than the size threshold.
33
+
34
+ ```tsx
35
+ import React from 'react';
36
+ import img from '. /foo.png?inline';
37
+
38
+ export default function Foo() {
39
+ return <img src={img} />;
40
+ }
41
+ ```
42
+
43
+ In the above example, the `foo.png` image will always be inlined, regardless of whether the size of the image is larger than the threshold.
44
+
45
+ In addition to the `inline` query, you can also use the `__inline` query to force inlining of the asset:
46
+
47
+ ```tsx
48
+ import img from '. /foo.png?__inline';
49
+ ```
50
+
51
+ ### Referenced from CSS file
52
+
53
+ When you reference a static asset in your CSS file, you can also force inline the asset with the `inline` or `__inline` queries.
54
+
55
+ ```css
56
+ .foo {
57
+ background-image: url('. /icon.png?inline');
58
+ }
59
+ ```
60
+
61
+ :::tip Do you really need to force inlining?
62
+ Inline large assets will significantly increase the first paint time or first contentful paint time of a page, which will hurt user experience. And when you inline a static asset multiple times into a CSS file, the base64 content will be repeatedly injected, causing the bundle size to grow . Please use forced inlining with caution.
63
+ :::
64
+
65
+ ## Force no inlining
66
+
67
+ When you want to always treat some assets as separate files, no matter how small the asset is, you can add the `url` query to force the asset not to be inlined.
68
+
69
+ ```tsx
70
+ import React from 'react';
71
+ import img from '. /foo.png?url';
72
+
73
+ export default function Foo() {
74
+ return <img src={img} />;
75
+ }
76
+ ```
77
+
78
+ In the above example, the `foo.png` image will always be loaded as a separate file, even if the size of the image is smaller than the threshold.
79
+
80
+ In addition to the `url` query, you can also use the `__inline=false` query to force the asset not to be inlined:
81
+
82
+ ```tsx
83
+ import img from '. /foo.png?__inline=false';
84
+ ```
85
+
86
+ ### Referenced from CSS file
87
+
88
+ When you reference a static asset in your CSS file, you can also force the asset not to be inlined with `url` or `__inline=false` queries.
89
+
90
+ ```css
91
+ .foo {
92
+ background-image: url('. /icon.png?url');
93
+ }
94
+ ```
95
+
96
+ :::tip Do you really need to exclude assets from inlining?
97
+ Excluding assets from inlining will increase the number of assets that the Web App needs to load. This will reduce the efficiency of loading assets in a weak network environment or in scenarios where HTTP2 is not enabled. Please use force no Inline with caution.
98
+
99
+ ## Inline JS files
100
+
101
+ In addition to inlining static assets into JS files, Modern.js also supports inlining JS files into HTML files.
102
+
103
+ Just enable the [output.enableInlineScripts](/configure/app/output/enable-inline-scripts) config, and the generated JS files will not be written into the output directory, but will be directly inlined to the corresponding in the HTML file.
104
+
105
+ ```ts
106
+ export default {
107
+ output: {
108
+ enableInlineScripts: true,
109
+ },
110
+ };
111
+ ```
112
+
113
+ :::tip
114
+ Inline JS files may cause the single HTML file to be too large, and it will break the HTTP caching. Please use it with caution.
115
+ :::
116
+
117
+ ## Inline CSS files
118
+
119
+ You can also inline CSS files into HTML files.
120
+
121
+ Just enable the [output.enableInlineStyles](/configure/app/output/enable-inline-styles) config, the generated CSS file will not be written into the output directory, but will be directly inlined to the corresponding in the HTML file.
122
+
123
+ ```ts
124
+ export default {
125
+ output: {
126
+ enableInlineStyles: true,
127
+ },
128
+ };
129
+ ```
130
+
131
+ ## Add Type Declaration
132
+
133
+ When you use URL queries such as `?inline` and `?url` in TypeScript code, TypeScript may prompt that the module is missing a type definition:
134
+
135
+ ```
136
+ TS2307: Cannot find module './logo.png?inline' or its corresponding type declarations.
137
+ ```
138
+
139
+ To fix this, you can add type declarations for these URL queries, please create `src/global.d.ts` file and add the following type declarations:
140
+
141
+ ```ts
142
+ declare module '*?inline' {
143
+ const content: string;
144
+ export default content;
145
+ }
146
+
147
+ declare module '*?inline' {
148
+ const content: string;
149
+ export default content;
150
+ }
151
+
152
+ declare module '*?__inline' {
153
+ const content: string;
154
+ export default content;
155
+ }
156
+
157
+ declare module '*?inline=false' {
158
+ const content: string;
159
+ export default content;
160
+ }
161
+ ```
@@ -44,9 +44,9 @@ See the [performance.bundleAnalyze](/configure/app/performance/bundle-analyze.ht
44
44
 
45
45
  ## Adjust Browserslist
46
46
 
47
- The Builder will compile the code according to the project's Browserslist config, and inject some Polyfills. If the project does not need to be compatible with legacy browsers, you can adjust the Browserslist and drop some legacy browsers, thereby reducing the compilation overhead on syntax and polyfill.
47
+ Modern.js will compile the code according to the project's Browserslist config, and inject some Polyfills. If the project does not need to be compatible with legacy browsers, you can adjust the Browserslist and drop some legacy browsers, thereby reducing the compilation overhead on syntax and polyfill.
48
48
 
49
- Builder's default Browserslist config is:
49
+ Modern.js's default Browserslist config is:
50
50
 
51
51
  ```js
52
52
  ['> 0.01%', 'not dead', 'not op_mini all'];
@@ -66,7 +66,7 @@ Please read the [Browserslist](https://modernjs.dev/builder/en/guide/advanced/br
66
66
 
67
67
  When it is clear that third-party dependencies do not require additional polyfill, you can set [output.polyfill](/configure/app/output/polyfill.html) to `usage`.
68
68
 
69
- In `usage` mode, Builder analyzes the syntax used in the source code and injects the required polyfill code on demand to reduce the size of polyfill.
69
+ In `usage` mode, Modern.js analyzes the syntax used in the source code and injects the required polyfill code on demand to reduce the size of polyfill.
70
70
 
71
71
  ```js
72
72
  export default {
@@ -77,18 +77,19 @@ export default {
77
77
  ```
78
78
 
79
79
  :::tip
80
- Please read the [Browser Compatibility](https://modernjs.dev/builder/en/guide/advanced/browser-compatibility.html) chapter to know more about the usage of Browserslist.
80
+ Please read the [Browser Compatibility](/guides/advanced-features/compatibility) chapter to know more about the usage of Browserslist.
81
81
  :::
82
82
 
83
83
  ## Image Compression
84
84
 
85
85
  In general front-end projects, the size of image often accounts for a large proportion of the total bundle size of the project.So if the image size can be reduced as much as possible, it will have a significant optimization effect on the project bundle size. You can enable image compression by registering a plugin in the Builder:
86
86
 
87
- ```js
87
+ ```ts title="modern.config.ts"
88
88
  import { builderPluginImageCompress } from '@modern-js/builder-plugin-image-compress';
89
89
 
90
- // Add the plugin to the Builder
91
- builder.addPlugins([builderPluginImageCompress()]);
90
+ export default {
91
+ builderPlugins: [builderPluginImageCompress()],
92
+ };
92
93
  ```
93
94
 
94
95
  See details in [plugin-image-compress](https://modernjs.dev/builder/en/plugins/plugin-image-compress.html).
@@ -0,0 +1,8 @@
1
+ {
2
+ "label": "SSR",
3
+ "position": 3,
4
+ "link": {
5
+ "type": "doc",
6
+ "id": "guides/advanced-features/ssr/index"
7
+ }
8
+ }
@@ -0,0 +1,186 @@
1
+ ---
2
+ sidebar_position: 3
3
+ title: Cache
4
+ ---
5
+
6
+ # Render Cache
7
+
8
+ Sometimes we cache computation results, such as with the React useMemo, useCallback Hook. By caching, we can reduce the number of computations, thus reducing CPU resource usage and enhancing the user experience.
9
+
10
+ Caching the results of server-side rendering (SSR) can reduce the computation and rendering time for each server request, enabling faster page load speeds and improving the user experience. It also lowers the server load, saves computational resources, and speeds up user access.
11
+
12
+ :::info
13
+ Need x.43.0+
14
+ :::
15
+
16
+ ## Configuration
17
+
18
+ You can enable caching by configuring it in `server/cache.[t|j]s`:
19
+
20
+ ```ts title="server/cache.ts"
21
+ import type { CacheOption } from '@modern-js/runtime/server';
22
+
23
+ export const cacheOption: CacheOption = {
24
+ maxAge: 500, // ms
25
+ staleWhileRevalidate: 1000, // ms
26
+ };
27
+ ```
28
+
29
+ ## Configuration Explanation
30
+
31
+ ### Cache Configuration
32
+
33
+ The caching policy is implemented based on [stale-while-revalidate](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control).
34
+
35
+ During the `maxAge` period, cache content will be returned directly. After `maxAge` but within `staleWhileRevalidate`, the cache content will also be returned directly, but at the same time, re-rendering will be executed asynchronously.
36
+
37
+ **Object type**
38
+
39
+ ```ts
40
+ export interface CacheControl {
41
+ maxAge: number;
42
+
43
+ staleWhileRevalidate: number;
44
+
45
+ customKey?: string | ((pathname: string) => string);
46
+ }
47
+ ```
48
+
49
+ In this, customKey is used for custom cache key. By default, Modern.js will use the request pathname as key for caching, but in some cases, this may not meet your needs, so developers can customise it.
50
+
51
+ **Function type**
52
+
53
+ ```ts
54
+ export type CacheOptionProvider = (
55
+ req: IncomingMessage,
56
+ ) => Promise<CacheControl> | CacheControl;
57
+ ```
58
+
59
+ Sometimes developers need to customise the cache key through req, which can be handled using the function form, as shown in the following code:
60
+
61
+ ```ts title="server/cache.ts"
62
+ import type { CacheOption, CacheOptionProvider } from '@modern-js/runtime/server';
63
+
64
+ const provider: CacheOptionProvider = (req) => {
65
+ const { url, headers, ... } = req;
66
+
67
+ const key = computedKey(url, headers, ...);
68
+
69
+ return {
70
+ maxAge: 500, // ms
71
+ staleWhileRevalidate: 1000, // ms
72
+ customKey: key,
73
+ }
74
+ }
75
+
76
+ export const cacheOption: CacheOption = provider;
77
+ ```
78
+
79
+ **Mapping type**
80
+
81
+ ```ts
82
+ export type CacheOptions = Record<string, CacheControl | CacheOptionProvider>;
83
+ ```
84
+
85
+ Sometimes, developers need to apply different caching policies for different routes. We also provide a mapping way for configuration, as shown in example below:
86
+
87
+ ```ts title="server/cache.ts"
88
+ import type { CacheOption } from '@modern-js/runtime/server';
89
+
90
+ export const cacheOption: CacheOption = {
91
+ '/home': {
92
+ maxAge: 50,
93
+ staleWhileRevalidate: 100,
94
+ },
95
+ '/about': {
96
+ maxAge: 1000 * 60 * 60 * 24, // one day
97
+ staleWhileRevalidate: 1000 * 60 * 60 * 24 * 2 // two day
98
+ },
99
+ '*': (req) => { // If the above routes cannot be matched, it will match to '*'
100
+ const { url, headers, ... } = req;
101
+ const key = computedKey(url, headers, ...);
102
+
103
+ return {
104
+ maxAge: 500,
105
+ staleWhileRevalidate: 1000,
106
+ customKey: key,
107
+ }
108
+ }
109
+ }
110
+ ```
111
+
112
+ - The route `http://xxx/home` will apply the first rule.
113
+ - The route `http://xxx/about` will apply the second rule.
114
+ - The route `http://xxx/abc` will apply the last rule.
115
+
116
+ The above-mentioned `/home` and `/about` will be used as patterns for matching, which means that `/home/abc` will also comply with this rule.
117
+ Simultaneously, you can also include regular expression syntax in it, such as `/home/.+`.
118
+
119
+ ### Cache Container
120
+
121
+ By default, Server will use memory for caching. But typically, services will be deployed on serverless. Each service access may be a new process, so caching cannot be applied every time.
122
+
123
+ Therefore, developers can also customise the cache container, which needs to implement the `Containter` interface.
124
+
125
+ ```ts
126
+ export interface Containter<K = string, V = string> {
127
+ /**
128
+ * Returns a specified element from the containter. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Containter.
129
+ * @returns Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned.
130
+ */
131
+ get: (key: K) => Promise<V | undefined>;
132
+
133
+ /**
134
+ * Adds a new element with a specified key and value to the containter. If an element with the same key already exists, the element will be updated.
135
+ *
136
+ * The ttl indicates cache expiration time.
137
+ */
138
+ set: (key: K, value: V, options?: { ttl?: number }) => Promise<this>;
139
+
140
+ /**
141
+ * @returns boolean indicating whether an element with the specified key exists or not.
142
+ */
143
+ has: (key: K) => Promise<boolean>;
144
+
145
+ /**
146
+ * @returns true if an element in the containter existed and has been removed, or false if the element does not exist.
147
+ */
148
+ delete: (key: K) => Promise<boolean>;
149
+ }
150
+ ```
151
+
152
+ As an example in the following code, a developer can implement a Redis container.
153
+
154
+ ```ts
155
+ import type { Containter, CacheOption } from '@modern-js/runtime/server';
156
+
157
+ class RedisContainter implements Containter {
158
+ redis = new Redis();
159
+
160
+ async get(key: string) {
161
+ return this.redis.get(key);
162
+ }
163
+
164
+ async set(key: string, value: string): Promise<this> {
165
+ this.redis.set(key, value);
166
+ return this;
167
+ }
168
+
169
+ async has(key: string): Promise<boolean> {
170
+ return this.redis.has(key);
171
+ }
172
+
173
+ async delete(key: string): Promise<boolean> {
174
+ return this.redis.delete(key);
175
+ }
176
+ }
177
+
178
+ const containter = new RedisContainter();
179
+
180
+ export const customContainer: Containter = containter;
181
+
182
+ export const cacheOption: CacheOption = {
183
+ maxAge: 500, // ms
184
+ staleWhileRevalidate: 1000, // ms
185
+ };
186
+ ```
@@ -0,0 +1,22 @@
1
+ # SSR
2
+
3
+ By rendering the HTML content of web pages into complete web pages on the server side, and then sending the generated web pages to the client, the client only needs to display the web pages without further rendering.
4
+
5
+ Its main advantages are:
6
+
7
+ - Improve first screen load speed: SSR can generate complete websites on the server side, the client only needs to download the content of the website, no additional renderings are required, thus improving the first screen load speed.
8
+ - Improve user experience: SSR can improve the responsiveness of web pages, thereby enhancing the user experience.
9
+ - Good for SEO: SSR can generate complete HTML content. Search engines can directly index HTML content to improve website ranking.
10
+
11
+ If you have the following scenarios, developers can consider using SSR to render your pages:
12
+
13
+ 1. Websites with higher first-screen loading speed requirements, such as e-commerce websites, news websites, etc.
14
+ 2. Websites with higher user experience requirements, such as social networking sites, gaming sites, etc.
15
+ 3. Websites with higher SEO requirements, such as corporate websites, blogs, etc.
16
+
17
+ In Modern.js, SSR is also out-of-the-box. Developers do not need to write complex server-side logic for SSR, nor do they need to worry about the operation and maintenance of SSR, or create separate services.
18
+ In addition to the out-of-the-box SSR service, to ensure the developer's development experience, we also have:
19
+
20
+ - A complete SSR downgrade strategy to ensure that the page can run safely.
21
+ - Automatically split sub-routes to load on demand, reducing the size of the first screen resources.
22
+ - Built-in caching system to solve the problem of high server-side load.