@modern-js/main-doc 2.54.6 → 2.56.0
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/docs/en/apis/app/hooks/src/entry.mdx +42 -0
- package/docs/en/apis/app/hooks/src/entry.server.mdx +52 -0
- package/docs/en/apis/app/hooks/src/index_.mdx +4 -0
- package/docs/en/apis/app/runtime/core/bootstrap.mdx +4 -0
- package/docs/en/apis/app/runtime/core/create-app.mdx +5 -1
- package/docs/en/apis/app/runtime/core/create-root.mdx +22 -0
- package/docs/en/apis/app/runtime/core/render.mdx +42 -0
- package/docs/en/apis/app/runtime/ssr/renderStreaming.mdx +69 -0
- package/docs/en/apis/app/runtime/ssr/renderString.mdx +62 -0
- package/docs/en/apis/app/runtime/ssr/requestHandler.mdx +47 -0
- package/docs/en/components/debug-app.mdx +3 -3
- package/docs/en/configure/app/dev/live-reload.mdx +27 -0
- package/docs/en/configure/app/dev/setup-middlewares.mdx +69 -0
- package/docs/en/configure/app/dev/watch-files.mdx +59 -0
- package/docs/en/configure/app/dev/write-to-disk.mdx +38 -0
- package/docs/en/configure/app/output/ssg.mdx +4 -0
- package/docs/en/configure/app/source/enable-async-entry.mdx +4 -4
- package/docs/en/configure/app/source/enable-custom-entry.mdx +41 -0
- package/docs/en/guides/advanced-features/ssr/cache.mdx +7 -2
- package/docs/en/guides/basic-features/data/data-fetch.mdx +1 -1
- package/docs/en/guides/basic-features/routes.mdx +1 -1
- package/docs/en/guides/concept/entries.mdx +50 -36
- package/docs/en/guides/get-started/quick-start.mdx +24 -8
- package/docs/en/guides/topic-detail/framework-plugin/hook-list.mdx +30 -177
- package/docs/zh/apis/app/hooks/src/entry.mdx +42 -0
- package/docs/zh/apis/app/hooks/src/entry.server.mdx +52 -0
- package/docs/zh/apis/app/hooks/src/index_.mdx +4 -0
- package/docs/zh/apis/app/runtime/core/bootstrap.mdx +4 -0
- package/docs/zh/apis/app/runtime/core/create-app.mdx +5 -1
- package/docs/zh/apis/app/runtime/core/create-root.mdx +22 -0
- package/docs/zh/apis/app/runtime/core/render.mdx +43 -0
- package/docs/zh/apis/app/runtime/ssr/renderStreaming.mdx +69 -0
- package/docs/zh/apis/app/runtime/ssr/renderString.mdx +62 -0
- package/docs/zh/apis/app/runtime/ssr/requestHandler.mdx +47 -0
- package/docs/zh/components/debug-app.mdx +3 -2
- package/docs/zh/configure/app/dev/client.mdx +1 -1
- package/docs/zh/configure/app/dev/live-reload.mdx +27 -0
- package/docs/zh/configure/app/dev/setup-middlewares.mdx +69 -0
- package/docs/zh/configure/app/dev/watch-files.mdx +59 -0
- package/docs/zh/configure/app/dev/write-to-disk.mdx +38 -0
- package/docs/zh/configure/app/output/ssg.mdx +4 -0
- package/docs/zh/configure/app/source/enable-async-entry.mdx +4 -4
- package/docs/zh/configure/app/source/enable-custom-entry.mdx +41 -0
- package/docs/zh/guides/advanced-features/ssr/cache.mdx +6 -2
- package/docs/zh/guides/basic-features/data/data-fetch.mdx +1 -1
- package/docs/zh/guides/basic-features/routes.mdx +1 -1
- package/docs/zh/guides/concept/entries.mdx +54 -41
- package/docs/zh/guides/get-started/quick-start.mdx +26 -10
- package/docs/zh/guides/topic-detail/framework-plugin/hook-list.mdx +29 -174
- package/package.json +7 -7
- package/docs/en/apis/app/hooks/src/pages.mdx +0 -186
- package/docs/zh/apis/app/hooks/src/pages.mdx +0 -187
- package/docs/zh/apis/monorepo/commands/deploy.mdx +0 -38
@@ -247,7 +247,7 @@ In a multi-entry (MPA) scenario, the value of `routeId` needs to include the nam
|
|
247
247
|
|
248
248
|
If you want to get the data returned by the `loader` in `entry1/routes/layout.tsx`, the value of `routeId` is `entry1_layout`.
|
249
249
|
|
250
|
-
###
|
250
|
+
### Loading UI (Experimental)
|
251
251
|
|
252
252
|
:::info
|
253
253
|
This feature is currently experimental and the API may change in the future.
|
@@ -290,7 +290,7 @@ When accessing the route, you will get the following UI layout:
|
|
290
290
|
</RootLayout>
|
291
291
|
```
|
292
292
|
|
293
|
-
### (
|
293
|
+
### Loading (Experimental)
|
294
294
|
|
295
295
|
In each directory under `routes/`, developers can create a `loading.tsx` file that exports a `<Loading>` component by default.
|
296
296
|
|
@@ -82,12 +82,13 @@ By default, Modern.js scans the files under `src/` before starting the project,
|
|
82
82
|
|
83
83
|
:::
|
84
84
|
|
85
|
-
Not all top-level directories under `src/` become project entries. The directory where the entry is located must meet one of the following
|
85
|
+
Not all top-level directories under `src/` become project entries. The directory where the entry is located must meet one of the following five conditions:
|
86
86
|
|
87
87
|
1. Has a `routes/` directory.
|
88
88
|
2. Has an `App.[jt]sx?` file.
|
89
89
|
3. Has an `index.[jt]sx?` file.
|
90
90
|
4. Has a `pages/` directory (compatible with Modern.js 1.0).
|
91
|
+
5. Has an `entry.[jt]sx?` file.
|
91
92
|
|
92
93
|
When the `src/` directory meets the entry requirements, Modern.js considers the current project as a single entry application.
|
93
94
|
|
@@ -139,8 +140,46 @@ export default () => {
|
|
139
140
|
|
140
141
|
For more information, please refer to [Self-controlled Routing](/guides/basic-features/routes.html#self-controlled-routing).
|
141
142
|
|
143
|
+
#### Custom Entry
|
144
|
+
|
145
|
+
If there is an `entry.[jt]sx` file in the entry, developers need to call the `createRoot` and `render` functions in the `entry.[jt]sx` file to complete the project's entry logic.
|
146
|
+
|
147
|
+
:::info
|
148
|
+
Using this file requires enabling [source.enableCustomEntry](/configure/app/source/enable-custom-entry).
|
149
|
+
:::
|
150
|
+
|
151
|
+
```tsx
|
152
|
+
import { createRoot } from '@modern-js/runtime/react';
|
153
|
+
import { render } from '@modern-js/runtime/browser';
|
154
|
+
|
155
|
+
const ModernRoot = createRoot();
|
156
|
+
|
157
|
+
render(<ModernRoot />);
|
158
|
+
```
|
159
|
+
|
160
|
+
For example, if some other operations need to be performed before render is executed, it can be implemented in this way:
|
161
|
+
|
162
|
+
```tsx
|
163
|
+
import { createRoot } from '@modern-js/runtime/react';
|
164
|
+
import { render } from '@modern-js/runtime/browser';
|
165
|
+
|
166
|
+
const ModernRoot = createRoot();
|
167
|
+
|
168
|
+
async function beforeRender() {
|
169
|
+
// todo
|
170
|
+
}
|
171
|
+
|
172
|
+
beforeRender().then(() => {
|
173
|
+
render(<ModernRoot />);
|
174
|
+
});
|
175
|
+
```
|
176
|
+
|
142
177
|
#### Custom Bootstrap
|
143
178
|
|
179
|
+
:::warning
|
180
|
+
Soon to be deprecated, it is recommended to use a custom entry.
|
181
|
+
:::
|
182
|
+
|
144
183
|
If there is an `index.[jt]sx` file in the entry, and the file exports a function by default, Modern.js will pass the default `bootstrap` function as a parameter and use the exported function to replace the default `bootstrap`. This way, developers can customize how components are mounted to DOM nodes or add custom behavior before mounting. For example:
|
145
184
|
|
146
185
|
```tsx
|
@@ -152,44 +191,19 @@ export default (App: React.ComponentType, bootstrap: () => void) => {
|
|
152
191
|
};
|
153
192
|
```
|
154
193
|
|
155
|
-
At this point, the generated file content of Modern.js is as follows:
|
156
|
-
|
157
|
-
```js
|
158
|
-
import React from 'react';
|
159
|
-
import ReactDOM from 'react-dom/client';
|
160
|
-
import customBootstrap from '@_modern_js_src/index.tsx';
|
161
|
-
import App from '@_modern_js_src/App';
|
162
|
-
import { router, state } from '@modern-js/runtime/plugins';
|
163
|
-
|
164
|
-
const IS_BROWSER = typeof window !== 'undefined' && window.name !== 'nodejs';
|
165
|
-
const MOUNT_ID = 'root';
|
166
|
-
|
167
|
-
let AppWrapper = null;
|
168
|
-
|
169
|
-
function render() {
|
170
|
-
AppWrapper = createApp({
|
171
|
-
// plugin parameters for runtime...
|
172
|
-
})(App);
|
173
|
-
if (IS_BROWSER) {
|
174
|
-
customBootstrap(AppWrapper);
|
175
|
-
}
|
176
|
-
return AppWrapper;
|
177
|
-
}
|
178
|
-
|
179
|
-
AppWrapper = render();
|
180
|
-
|
181
|
-
export default AppWrapper;
|
182
|
-
```
|
183
|
-
|
184
194
|
### Build Mode Entry
|
185
195
|
|
186
|
-
Build mode refers to
|
196
|
+
Build mode refers to not using the Runtime capabilities provided by Modern.js, but rather having the developer define the entry of the page completely on their own.
|
197
|
+
|
198
|
+
When the entry directory contains `index.[jt]sx` (soon to be deprecated) and does not export a function via `export default`, or when there is an `entry.[jt]sx` file in the entry directory and the `@modern-js/runtime` dependency is not installed, the corresponding file will be identified as the entry module of webpack or Rspack.
|
187
199
|
|
188
|
-
|
200
|
+
:::info
|
201
|
+
Using the `entry.[jt]sx` file requires enabling [source.enableCustomEntry](/configure/app/source/enable-custom-entry).
|
202
|
+
:::
|
189
203
|
|
190
204
|
In this case, Modern.js will not generate the entry code automatically. Therefore, you need to manually mount the component to the DOM node, for example:
|
191
205
|
|
192
|
-
```js title=src/
|
206
|
+
```js title=src/entry.tsx
|
193
207
|
import React from 'react';
|
194
208
|
import ReactDOM from 'react-dom';
|
195
209
|
import App from './App';
|
@@ -197,9 +211,9 @@ import App from './App';
|
|
197
211
|
ReactDOM.render(<App />, document.getElementById('root'));
|
198
212
|
```
|
199
213
|
|
200
|
-
This approach is equivalent to enabling the [source.entries.disableMount](/configure/app/source/entries) option in Modern.js. When you use this approach, **you will not be able to use the runtime capabilities of the Modern.js framework**, such as the `runtime` configuration in the modern.config.js file will no longer take effect.
|
214
|
+
This approach is equivalent to enabling the [source.entries.disableMount](/configure/app/source/entries) option in Modern.js. When you use this approach, **you will not be able to use the runtime capabilities of the Modern.js framework**, such as the `runtime` configuration in the `modern.config.js` file will no longer take effect.
|
201
215
|
|
202
|
-
## Custom Entries
|
216
|
+
## Custom Entries Config
|
203
217
|
|
204
218
|
In some cases, you may need to customize the entry configuration instead of using the entry conventions provided by Modern.js.
|
205
219
|
|
@@ -232,4 +246,4 @@ export default defineConfig({
|
|
232
246
|
});
|
233
247
|
```
|
234
248
|
|
235
|
-
Note that when you enable `disableMount`, **you won't be able to use the runtime capabilities of the Modern.js framework**, such as the `runtime` configuration in the modern.config.ts file.
|
249
|
+
Note that when you enable `disableMount`, **you won't be able to use the runtime capabilities of the Modern.js framework**, such as the `runtime` configuration in the `modern.config.ts` file.
|
@@ -56,7 +56,9 @@ export default defineConfig({
|
|
56
56
|
server: {
|
57
57
|
ssr: true,
|
58
58
|
},
|
59
|
-
plugins: [appTools(
|
59
|
+
plugins: [appTools({
|
60
|
+
bundler: 'webpack', // Set to 'experimental-rspack' to enable rspack ⚡️🦀
|
61
|
+
}),],
|
60
62
|
});
|
61
63
|
```
|
62
64
|
|
@@ -91,15 +93,27 @@ $ pnpm run build
|
|
91
93
|
|
92
94
|
> modern build
|
93
95
|
|
94
|
-
|
95
|
-
|
96
|
+
Modern.js Framework v2.55.0
|
97
|
+
|
98
|
+
info Starting production build...
|
99
|
+
info Type checker is enabled. It may take some time.
|
100
|
+
ready Client compiled in 6.19 s
|
96
101
|
info Production file sizes:
|
97
102
|
|
98
|
-
File
|
99
|
-
dist/
|
100
|
-
dist/
|
101
|
-
dist/static/js/main.
|
102
|
-
dist/
|
103
|
+
File Size Gzipped
|
104
|
+
dist/routes-manifest.json 0.74 kB 0.28 kB
|
105
|
+
dist/static/css/async/page.d7915515.css 1.4 kB 0.69 kB
|
106
|
+
dist/static/js/main.5ae469e7.js 3.0 kB 1.3 kB
|
107
|
+
dist/html/main/index.html 6.0 kB 2.6 kB
|
108
|
+
dist/static/js/async/page.ddc8a4c1.js 19.2 kB 6.7 kB
|
109
|
+
dist/static/js/34.171fffdb.js 21.3 kB 7.1 kB
|
110
|
+
dist/static/js/lib-router.8995a55e.js 55.3 kB 18.1 kB
|
111
|
+
dist/static/js/lib-lodash.53ec3384.js 71.4 kB 24.8 kB
|
112
|
+
dist/static/js/lib-react.b5856db9.js 140.0 kB 45.2 kB
|
113
|
+
dist/static/js/lib-polyfill.86c452b3.js 213.3 kB 69.9 kB
|
114
|
+
|
115
|
+
Total size: 531.8 kB
|
116
|
+
Gzipped size: 176.7 kB
|
103
117
|
```
|
104
118
|
|
105
119
|
By default, the build artifacts are generated in `dist/`, with the following directory structure:
|
@@ -127,6 +141,8 @@ $ pnpm run serve
|
|
127
141
|
|
128
142
|
> modern serve
|
129
143
|
|
144
|
+
Modern.js Framework v2.55.0
|
145
|
+
|
130
146
|
info Starting production server...
|
131
147
|
|
132
148
|
> Local: http://localhost:8080/
|
@@ -420,13 +420,13 @@ export const myPlugin = (): CliPlugin<AppTools> => ({
|
|
420
420
|
},
|
421
421
|
});
|
422
422
|
```
|
423
|
+
{/*
|
424
|
+
### `checkEntryPoint`
|
423
425
|
|
424
|
-
|
425
|
-
|
426
|
-
- Function: Used for modifying or adding `import` statements in the generated entry files.
|
426
|
+
- Function: Used for increasing entry types.
|
427
427
|
- Execution stage: Executed before generating the entry files, triggered during the [`prepare`](#prepare) stage.
|
428
428
|
- Hook model: `AsyncWaterfall`
|
429
|
-
- Type: `AsyncWaterfall<{
|
429
|
+
- Type: `AsyncWaterfall<{ path: string; entry: false | string; }>`
|
430
430
|
- Example:
|
431
431
|
|
432
432
|
```ts
|
@@ -435,57 +435,20 @@ import type { CliPlugin, AppTools } from '@modern-js/app-tools';
|
|
435
435
|
export const myPlugin = (): CliPlugin<AppTools> => ({
|
436
436
|
setup(api) {
|
437
437
|
return {
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
value: 'react',
|
442
|
-
specifiers: [
|
443
|
-
{
|
444
|
-
imported: 'unmountComponentAtNode',
|
445
|
-
},
|
446
|
-
],
|
447
|
-
});
|
448
|
-
|
449
|
-
return { entrypoint, imports };
|
450
|
-
},
|
438
|
+
checkEntryPoint({ path, entry }) {
|
439
|
+
return { path, entry: entry || isNewEntry(path) };
|
440
|
+
}
|
451
441
|
};
|
452
442
|
},
|
453
443
|
});
|
454
444
|
```
|
455
445
|
|
456
|
-
### `
|
446
|
+
### `modifyEntrypoints`
|
457
447
|
|
458
|
-
- Function:
|
448
|
+
- Function: Used for modifying the entry information, for the newly added entries of the plugin, the corresponding entrypoint information can be modified through this hook.
|
459
449
|
- Execution stage: Before the entry file is generated, the [`prepare`](#prepare) phase triggers
|
460
450
|
- Hook model: `AsyncWaterfall`
|
461
|
-
- Type: `AsyncWaterfall<{
|
462
|
-
- Example:
|
463
|
-
|
464
|
-
```ts
|
465
|
-
import type { CliPlugin, AppTools } from '@modern-js/app-tools';
|
466
|
-
|
467
|
-
export const myPlugin = (): CliPlugin<AppTools> => ({
|
468
|
-
setup(api) {
|
469
|
-
return {
|
470
|
-
modifyEntryExport({ entrypoint, exportStatement }) {
|
471
|
-
return {
|
472
|
-
entrypoint,
|
473
|
-
exportStatement: [`export const foo = 'test'`, exportStatement].join(
|
474
|
-
'\n',
|
475
|
-
),
|
476
|
-
};
|
477
|
-
},
|
478
|
-
};
|
479
|
-
},
|
480
|
-
});
|
481
|
-
```
|
482
|
-
|
483
|
-
### `modifyEntryRuntimePlugins`
|
484
|
-
|
485
|
-
- Function: Used for adding or modifying [Runtime plugins](#Runtime) in the generated entry files.
|
486
|
-
- Execution stage: Executed before generating the entry files, triggered during the [`prepare`](#prepare) stage.
|
487
|
-
- Hook model: `AsyncWaterfall`
|
488
|
-
- Type: `AsyncWaterfall<{ entrypoint: Entrypoint; plugins: RuntimePlugin[]; }>`
|
451
|
+
- Type: `AsyncWaterfall<{ entrypoints: Entrypoint[]; }>`
|
489
452
|
- Example:
|
490
453
|
|
491
454
|
```ts
|
@@ -494,33 +457,23 @@ import type { CliPlugin, AppTools } from '@modern-js/app-tools';
|
|
494
457
|
export const myPlugin = (): CliPlugin<AppTools> => ({
|
495
458
|
setup(api) {
|
496
459
|
return {
|
497
|
-
|
498
|
-
const
|
499
|
-
|
500
|
-
|
501
|
-
};
|
502
|
-
|
503
|
-
return {
|
504
|
-
plugins: [
|
505
|
-
...plugins,
|
506
|
-
{
|
507
|
-
name,
|
508
|
-
options: JSON.stringify(options),
|
509
|
-
},
|
510
|
-
],
|
511
|
-
};
|
460
|
+
async modifyEntrypoints({ entrypoints }) {
|
461
|
+
const newEntryPoints = entrypoints.map(entrypoint => {
|
462
|
+
...
|
463
|
+
});
|
464
|
+
return { entrypoints: newEntryPoints };
|
512
465
|
},
|
513
466
|
};
|
514
467
|
},
|
515
468
|
});
|
516
469
|
```
|
517
470
|
|
518
|
-
### `
|
471
|
+
### `generateEntryCode`
|
519
472
|
|
520
|
-
- Function: Used for modifying the
|
521
|
-
- Execution stage:
|
473
|
+
- Function: Used for modifying the generated entry file
|
474
|
+
- Execution stage: After generating the entry file and before creating the builder.
|
522
475
|
- Hook model: `AsyncWaterfall`
|
523
|
-
- Type: `
|
476
|
+
- Type: `AsyncWorkflow<{ entrypoints: Entrypoint[] }, void>`
|
524
477
|
- Example:
|
525
478
|
|
526
479
|
```ts
|
@@ -529,18 +482,18 @@ import type { CliPlugin, AppTools } from '@modern-js/app-tools';
|
|
529
482
|
export const myPlugin = (): CliPlugin<AppTools> => ({
|
530
483
|
setup(api) {
|
531
484
|
return {
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
485
|
+
async generateEntryCode({ entrypoints }) {
|
486
|
+
await Promise.all(
|
487
|
+
entrypoints.map(async entrypoint => {
|
488
|
+
...
|
489
|
+
})
|
490
|
+
);
|
538
491
|
},
|
539
492
|
};
|
540
493
|
},
|
541
494
|
});
|
542
495
|
```
|
543
|
-
|
496
|
+
*/}
|
544
497
|
### `modifyFileSystemRoutes`
|
545
498
|
|
546
499
|
- Function: Used for modifying the content of the generated front-end page routing files, which must be serializable.
|
@@ -608,32 +561,6 @@ export const myPlugin = (): CliPlugin<AppTools> => ({
|
|
608
561
|
});
|
609
562
|
```
|
610
563
|
|
611
|
-
### `modifyAsyncEntry`
|
612
|
-
|
613
|
-
- Function: Used for modifying the asynchronous module that wraps the entry file, see [source.enableAsyncEntry](/configure/app/source/enable-async-entry).
|
614
|
-
- Execution stage: Executed before generating the entry files, triggered during the [`prepare`](#prepare) stage.
|
615
|
-
- Hook model: `AsyncWaterfall`
|
616
|
-
- Type: `AsyncWaterfall<{ entrypoint: Entrypoint; code: string; }>`
|
617
|
-
- Example:
|
618
|
-
|
619
|
-
```ts
|
620
|
-
import type { CliPlugin, AppTools } from '@modern-js/app-tools';
|
621
|
-
|
622
|
-
export const myPlugin = (): CliPlugin<AppTools> => ({
|
623
|
-
setup(api) {
|
624
|
-
return {
|
625
|
-
modifyAsyncEntry({ entrypoint, code }) {
|
626
|
-
const customCode = `console.log('hello');`;
|
627
|
-
return {
|
628
|
-
entrypoint,
|
629
|
-
code: `${customCode}${code}`,
|
630
|
-
};
|
631
|
-
},
|
632
|
-
};
|
633
|
-
},
|
634
|
-
});
|
635
|
-
```
|
636
|
-
|
637
564
|
### `htmlPartials`
|
638
565
|
|
639
566
|
- Function: Used for customizing the generated HTML page template.
|
@@ -780,7 +707,7 @@ export const myPlugin = (): Plugin => ({
|
|
780
707
|
- Function: Modifies the components that need to be rendered.
|
781
708
|
- Execution stage: Rendering (SSR/CSR).
|
782
709
|
- Hook model: `Pipeline`
|
783
|
-
- Type: `Pipeline<{ App: React.ComponentType<any>; },
|
710
|
+
- Type: `Pipeline<{ App: React.ComponentType<any>;config: Record<string, any>; },React.ComponentType<any>>`
|
784
711
|
- Example:
|
785
712
|
|
786
713
|
:::note
|
@@ -790,13 +717,12 @@ When using the hoc hook, you need to copy the static properties of the original
|
|
790
717
|
```ts
|
791
718
|
import { createContext } from 'react';
|
792
719
|
import type { Plugin } from '@modern-js/runtime';
|
793
|
-
import hoistNonReactStatics from 'hoist-non-react-statics';
|
794
720
|
|
795
721
|
export const myPlugin = (): Plugin => ({
|
796
722
|
setup(api) {
|
797
723
|
const FooContext = createContext('');
|
798
724
|
return {
|
799
|
-
hoc({ App }, next) {
|
725
|
+
hoc({ App, config }, next) {
|
800
726
|
const AppWrapper = (props: any) => {
|
801
727
|
return (
|
802
728
|
<FooContext.Provider store={'test'}>
|
@@ -805,84 +731,11 @@ export const myPlugin = (): Plugin => ({
|
|
805
731
|
);
|
806
732
|
};
|
807
733
|
return next({
|
808
|
-
App:
|
734
|
+
App: AppWrapper,
|
735
|
+
config
|
809
736
|
});
|
810
737
|
},
|
811
738
|
};
|
812
739
|
},
|
813
740
|
});
|
814
741
|
```
|
815
|
-
|
816
|
-
{/* ### `provide`
|
817
|
-
|
818
|
-
- Function: Modifies the Elements that need to be rendered.
|
819
|
-
- Execution stage: Rendering (SSR/CSR).
|
820
|
-
- Hook model: `Pipeline`
|
821
|
-
- Type: `Pipeline<{ element: JSX.Element; props: AppProps; context: RuntimeContext }, JSX.Element>`
|
822
|
-
- Example:
|
823
|
-
|
824
|
-
```ts
|
825
|
-
import { createContext } from 'react';
|
826
|
-
import type { Plugin } from '@modern-js/runtime';
|
827
|
-
|
828
|
-
export const myPlugin = (): Plugin => ({
|
829
|
-
setup(api) {
|
830
|
-
const FooContext = createContext('');
|
831
|
-
|
832
|
-
return {
|
833
|
-
provide: ({ element }) => <div>{element}</div>,
|
834
|
-
};
|
835
|
-
},
|
836
|
-
});
|
837
|
-
```
|
838
|
-
|
839
|
-
### `client`
|
840
|
-
|
841
|
-
- Function: Customizes the client-side rendering process.
|
842
|
-
- Execution stage: Client-side rendering in the browser.
|
843
|
-
- Hook model: `AsyncPipeline`
|
844
|
-
- Type: `AsyncPipeline<{ App: React.ComponentType<any>; context?: RuntimeContext; rootElement: HTMLElement; }, void>`
|
845
|
-
- Example:
|
846
|
-
|
847
|
-
```ts
|
848
|
-
import ReactDOM from 'react-dom';
|
849
|
-
import type { Plugin } from '@modern-js/runtime';
|
850
|
-
|
851
|
-
export const myPlugin = (): Plugin => ({
|
852
|
-
setup(api) {
|
853
|
-
return {
|
854
|
-
client: async ({ App, rootElement }) => {
|
855
|
-
ReactDOM.render(
|
856
|
-
React.createElement(App, { context: { foo: 'test' } }),
|
857
|
-
rootElement,
|
858
|
-
);
|
859
|
-
},
|
860
|
-
};
|
861
|
-
},
|
862
|
-
});
|
863
|
-
```
|
864
|
-
|
865
|
-
### `server`
|
866
|
-
|
867
|
-
- Function: Customize the server-side rendering process.
|
868
|
-
- Execution Phase: SSR
|
869
|
-
- Hook model: `AsyncPipeline`
|
870
|
-
- Type: `AsyncPipeline<{ App: React.ComponentType<any>; context?: RuntimeContext; }, string>`
|
871
|
-
- Example:
|
872
|
-
|
873
|
-
```ts
|
874
|
-
import ReactDomServer from 'react-dom/server';
|
875
|
-
import type { Plugin } from '@modern-js/runtime';
|
876
|
-
|
877
|
-
export const myPlugin = (): Plugin => ({
|
878
|
-
setup(api) {
|
879
|
-
return {
|
880
|
-
server({ App, context }) {
|
881
|
-
return ReactDomServer.renderToString(
|
882
|
-
React.createElement(App, { context: { foo: 'test' } }),
|
883
|
-
);
|
884
|
-
},
|
885
|
-
};
|
886
|
-
},
|
887
|
-
});
|
888
|
-
``` */}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
---
|
2
|
+
title: entry.[tj]s
|
3
|
+
sidebar_position: 4
|
4
|
+
---
|
5
|
+
# entry.[tj]s
|
6
|
+
|
7
|
+
通常情况下[`routes/`](/apis/app/hooks/src/routes.html) 和 [`App.[tj]sx`](/apis/app/hooks/src/app) 钩子文件已经能满足我们的需求,当我们需要在组件渲染之前添加自定义行为或者完全接管 webpack 打包入口时,可以在 `src` 或者入口目录下放置 `entry.[tj]s`。 下面有分两种情况进行讨论:
|
8
|
+
|
9
|
+
:::info
|
10
|
+
使用该文件需要开启 [source.enableCustomEntry](/configure/app/source/enable-custom-entry)。
|
11
|
+
:::
|
12
|
+
|
13
|
+
## 在组件渲染前添加自定义行为
|
14
|
+
|
15
|
+
在 `src/entry.[tj]s` 中这样实现:
|
16
|
+
|
17
|
+
```js title=src/entry.tsx
|
18
|
+
import { createRoot } from '@modern-js/runtime/react';
|
19
|
+
import { render } from '@modern-js/runtime/browser';
|
20
|
+
|
21
|
+
const ModernRoot = createRoot();
|
22
|
+
|
23
|
+
async function beforeRender() {
|
24
|
+
// todo
|
25
|
+
}
|
26
|
+
|
27
|
+
beforeRender().then(() => {
|
28
|
+
render(<ModernRoot />);
|
29
|
+
});
|
30
|
+
```
|
31
|
+
|
32
|
+
## 完全接管 webpack 入口
|
33
|
+
|
34
|
+
当项目未安装 `@modern-js/runtime` 依赖时, `src/entry.[tj]sx?` 即为真正的 webpack 打包入口文件, 可以直接像使用 create-react-app 等脚手架一样组织代码:
|
35
|
+
|
36
|
+
```js title=src/entry.jsx
|
37
|
+
import React from 'react';
|
38
|
+
import ReactDOM from 'react-dom/client';
|
39
|
+
import App from './App';
|
40
|
+
|
41
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);
|
42
|
+
```
|
@@ -0,0 +1,52 @@
|
|
1
|
+
---
|
2
|
+
title: entry.server.[tj]sx
|
3
|
+
sidebar_position: 5
|
4
|
+
---
|
5
|
+
|
6
|
+
# entry.server.[tj]sx
|
7
|
+
|
8
|
+
当项目开启 `server.ssr` 时,Modern.js 生成一个默认的 Server-Side 入口。示例代码如下:
|
9
|
+
|
10
|
+
```tsx title="entry.server.tsx"
|
11
|
+
import {
|
12
|
+
renderString,
|
13
|
+
createRequestHandler,
|
14
|
+
} from '@modern-js/runtime/ssr/server';
|
15
|
+
|
16
|
+
const handleRequest = async (request, ServerRoot, options) => {
|
17
|
+
const body = await renderString(request, <ServerRoot />, options);
|
18
|
+
|
19
|
+
return new Response(body, {
|
20
|
+
headers: {
|
21
|
+
'content-type': 'text/html; charset=utf-8',
|
22
|
+
},
|
23
|
+
});
|
24
|
+
};
|
25
|
+
|
26
|
+
export default createRequestHandler(handleRequest);
|
27
|
+
```
|
28
|
+
|
29
|
+
## 添加自定义行为
|
30
|
+
|
31
|
+
如果用户需自定义 Server-Side Rendering 入口,可以在 `src/entry.server.ts`、`src/{entryName}/entry.server.ts` 中自定义 server 入口
|
32
|
+
|
33
|
+
```tsx title="src/entry.server.tsx"
|
34
|
+
import { renderString, createRequestHandler } from '@edenx/runtime/ssr/server';
|
35
|
+
import type { HandleRequest } from '@edenx/runtime/ssr/server';
|
36
|
+
|
37
|
+
const handleRequest: HandleRequest = async (request, ServerRoot, options) => {
|
38
|
+
// do something before rendering
|
39
|
+
const body = await renderString(request, <ServerRoot />, options);
|
40
|
+
|
41
|
+
const newBody = body + '<div>Byte-Dance</div>';
|
42
|
+
|
43
|
+
return new Response(newBody, {
|
44
|
+
headers: {
|
45
|
+
'content-type': 'text/html; charset=UTF-8',
|
46
|
+
'x-custom-header': 'abc',
|
47
|
+
},
|
48
|
+
});
|
49
|
+
};
|
50
|
+
|
51
|
+
export default createRequestHandler(handleRequest);
|
52
|
+
```
|
@@ -4,6 +4,10 @@ sidebar_position: 4
|
|
4
4
|
---
|
5
5
|
# index.[tj]s
|
6
6
|
|
7
|
+
:::warning
|
8
|
+
即将废弃,推荐使用 [`entry.[tj]s`](/apis/app/hooks/src/entry)。
|
9
|
+
:::
|
10
|
+
|
7
11
|
应用使用自定义 `bootstrap` 时的入口标识。
|
8
12
|
|
9
13
|
通常情况下 [`App.[tj]sx`](/apis/app/hooks/src/app) 钩子文件已经能满足我们的需求,当我们需要在 `bootstrap` 之前添加自定义行为或者完全接管 webpack 打包入口时,可以在 `src` 或者入口目录下放置 `index.[tj]s`。 下面有分两种情况进行讨论:
|
@@ -0,0 +1,22 @@
|
|
1
|
+
---
|
2
|
+
title: createRoot
|
3
|
+
---
|
4
|
+
# createRoot
|
5
|
+
|
6
|
+
用于创建 Modern.js 提供的根组件,该根组件会自动注册 Runtime 插件,并完成 Runtime 插件初始化。
|
7
|
+
|
8
|
+
## 使用姿势
|
9
|
+
|
10
|
+
```ts
|
11
|
+
import { createRoot } from '@modern-js/runtime/react';
|
12
|
+
```
|
13
|
+
|
14
|
+
## 函数签名
|
15
|
+
|
16
|
+
```ts
|
17
|
+
export function createRoot(UserApp?: React.ComponentType | null): React.ComponentType<any>;
|
18
|
+
```
|
19
|
+
|
20
|
+
### 参数
|
21
|
+
|
22
|
+
- `UserApp` 可选参数,默认为 `App.tsx` 导出的组件
|