@modern-js/main-doc 2.60.1-alpha.0 → 2.60.2
Sign up to get free protection for your applications and to get access to all the features.
- package/docs/en/apis/app/commands.mdx +4 -35
- package/docs/en/components/deploy-command.mdx +14 -0
- package/docs/en/components/output-polyfill-extend.mdx +1 -0
- package/docs/en/components/serve-command.mdx +22 -0
- package/docs/en/configure/app/runtime/router.mdx +11 -3
- package/docs/en/configure/app/runtime/state.mdx +0 -2
- package/docs/en/guides/concept/_meta.json +1 -1
- package/docs/en/guides/concept/server.mdx +35 -0
- package/docs/en/guides/topic-detail/_meta.json +6 -6
- package/docs/en/guides/topic-detail/model/quick-start.mdx +5 -0
- package/docs/en/guides/topic-detail/module-federation/_meta.json +1 -0
- package/docs/en/guides/topic-detail/module-federation/application.mdx +112 -0
- package/docs/en/guides/topic-detail/module-federation/deploy.mdx +28 -0
- package/docs/en/guides/topic-detail/module-federation/introduce.mdx +35 -0
- package/docs/en/guides/topic-detail/module-federation/ssr.mdx +31 -0
- package/docs/en/guides/topic-detail/module-federation/usage.mdx +180 -0
- package/docs/zh/apis/app/commands.mdx +4 -37
- package/docs/zh/components/deploy-command.mdx +14 -0
- package/docs/zh/components/output-polyfill-extend.mdx +1 -0
- package/docs/zh/components/serve-command.mdx +22 -0
- package/docs/zh/configure/app/runtime/router.mdx +10 -4
- package/docs/zh/configure/app/runtime/state.mdx +0 -2
- package/docs/zh/guides/concept/_meta.json +1 -1
- package/docs/zh/guides/concept/server.mdx +35 -0
- package/docs/zh/guides/topic-detail/_meta.json +6 -6
- package/docs/zh/guides/topic-detail/model/quick-start.mdx +5 -0
- package/docs/zh/guides/topic-detail/module-federation/_meta.json +1 -0
- package/docs/zh/guides/topic-detail/module-federation/application.mdx +112 -0
- package/docs/zh/guides/topic-detail/module-federation/deploy.mdx +28 -0
- package/docs/zh/guides/topic-detail/module-federation/introduce.mdx +35 -0
- package/docs/zh/guides/topic-detail/module-federation/ssr.mdx +31 -0
- package/docs/zh/guides/topic-detail/module-federation/usage.mdx +181 -0
- package/i18n.json +4 -0
- package/package.json +4 -3
@@ -153,28 +153,9 @@ The `--config` parameter needs to use a JSON string.
|
|
153
153
|
pnpm does not support the use of JSON strings as parameter values currently. Use `npm new` to turn on.【[Relate Issue](https://github.com/pnpm/pnpm/issues/3876)】
|
154
154
|
:::
|
155
155
|
|
156
|
-
|
156
|
+
import ServeCommand from "@site-docs-en/components/serve-command";
|
157
157
|
|
158
|
-
|
159
|
-
|
160
|
-
```bash
|
161
|
-
Usage: modern serve [options]
|
162
|
-
|
163
|
-
Options:
|
164
|
-
-c --config <config> specify the configuration file, which can be a relative or absolute path
|
165
|
-
-h, --help show command help
|
166
|
-
--api-only only run API service
|
167
|
-
```
|
168
|
-
|
169
|
-
By default, the project will run in `localhost:8080`, you can modify the server port number with `server.port`:
|
170
|
-
|
171
|
-
```js
|
172
|
-
export default defineConfig({
|
173
|
-
server: {
|
174
|
-
port: 8081,
|
175
|
-
},
|
176
|
-
});
|
177
|
-
```
|
158
|
+
<ServeCommand />
|
178
159
|
|
179
160
|
## modern upgrade
|
180
161
|
|
@@ -250,18 +231,6 @@ Inspect config succeed, open following files to view the content:
|
|
250
231
|
- Webpack Config (node): /root/my-project/dist/webpack.config.node.mjs
|
251
232
|
```
|
252
233
|
|
253
|
-
|
254
|
-
|
255
|
-
Run ESLint to check the syntax of the code.
|
256
|
-
|
257
|
-
```bash
|
258
|
-
Usage: modern lint [options] [...files]
|
259
|
-
|
260
|
-
Options:
|
261
|
-
--no-fix disable auto fix source file
|
262
|
-
-h, --help display help for command
|
263
|
-
```
|
264
|
-
|
265
|
-
Normally, only the part of the code modified by this commit needs to be checked by `lint-staged` during the `git commit` phase.
|
234
|
+
import DeployCommand from "@site-docs-en/components/deploy-command";
|
266
235
|
|
267
|
-
|
236
|
+
<DeployCommand />
|
@@ -0,0 +1,14 @@
|
|
1
|
+
## modern deploy
|
2
|
+
|
3
|
+
The `modern deploy` command is used to generate artifacts required for the deployment platform.
|
4
|
+
|
5
|
+
```bash
|
6
|
+
Usage: modern deploy [options]
|
7
|
+
|
8
|
+
Options:
|
9
|
+
-c --config <config> Specify configuration file path, either relative or absolute
|
10
|
+
-s --skip-build Skip the build stage
|
11
|
+
-h, --help Display command help
|
12
|
+
```
|
13
|
+
|
14
|
+
For more details, refer to [Deploy Application](/guides/basic-features/deploy).
|
@@ -0,0 +1 @@
|
|
1
|
+
Modern.js also provides a runtime Polyfill solution based on browser [UA](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/User-Agent) information. For detailed usage instructions, please refer to [Polyfill At Runtime](https://modernjs.dev/en/guides/advanced-features/compatibility.html#polyfill-at-runtime).
|
@@ -0,0 +1,22 @@
|
|
1
|
+
## modern serve
|
2
|
+
|
3
|
+
The `modern serve` command is used to start a Modern.js project in the production environment. It can also be used to preview the artifacts built for the production environment locally. Please note that you need to execute the [`build`](/apis/app/commands#modern-build) command beforehand to generate the corresponding artifacts.
|
4
|
+
|
5
|
+
```bash
|
6
|
+
Usage: modern serve [options]
|
7
|
+
|
8
|
+
Options:
|
9
|
+
-c --config <config> specify the configuration file, which can be a relative or absolute path
|
10
|
+
-h, --help show command help
|
11
|
+
--api-only only run API service
|
12
|
+
```
|
13
|
+
|
14
|
+
By default, the project will run in `localhost:8080`, you can modify the server port number with `server.port`:
|
15
|
+
|
16
|
+
```js
|
17
|
+
export default defineConfig({
|
18
|
+
server: {
|
19
|
+
port: 8081,
|
20
|
+
},
|
21
|
+
});
|
22
|
+
```
|
@@ -8,12 +8,16 @@ import RouterLegacyTip from "@site-docs-en/components/router-legacy-tip"
|
|
8
8
|
|
9
9
|
<RouterLegacyTip />
|
10
10
|
|
11
|
-
# runtime.router
|
12
|
-
|
13
11
|
- **Type:** `boolean | Object`
|
14
12
|
- **Default:** `false`
|
15
13
|
|
16
|
-
|
14
|
+
This value is set to `true` when the project is created, supporting the use of [conventional routing](/guides/concept/entries.html#约定式路由) provided by Modern.js for routing management.
|
15
|
+
|
16
|
+
If you wish to use [controlled routing](/guides/concept/entries.html#自控式路由), please remove this value or set it to `false`.
|
17
|
+
|
18
|
+
:::note
|
19
|
+
All sub-configurations of `router` will only take effect when using conventional routing.
|
20
|
+
:::
|
17
21
|
|
18
22
|
## basename
|
19
23
|
|
@@ -22,6 +26,10 @@ When enabled, the router option provides routing management for Modern.js conven
|
|
22
26
|
|
23
27
|
The basename option specifies the subpath where the app is deployed, for situations where it cannot be deployed to the root domain.
|
24
28
|
|
29
|
+
:::tip
|
30
|
+
推荐使用 [`server.baseUrl`](/configure/app/server/base-url) 进行配置。
|
31
|
+
:::
|
32
|
+
|
25
33
|
## supportHtml5History
|
26
34
|
|
27
35
|
- **Type:** `boolean`
|
@@ -1 +1 @@
|
|
1
|
-
["entries", "builder"]
|
1
|
+
["entries", "builder", "server"]
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Web Server
|
2
|
+
|
3
|
+
Modern.js provides an integrated Web server for applications that can run in any container environment with Node.js. Whether executing the `dev` command in a local development environment, running the `build && serve` commands in a production environment, or using the official deployment solution, it all runs through this Web server to host the application.
|
4
|
+
|
5
|
+
## Underlying Dependencies
|
6
|
+
|
7
|
+
Modern.js builds its Web server based on the [Hono framework](https://hono.dev/). Hono is a small, simple, and ultra-fast web standard-based framework that can run on any JavaScript runtime.
|
8
|
+
|
9
|
+
## Development & Production
|
10
|
+
|
11
|
+
The Web server flow in both Modern.js development and production environments is entirely isomorphic, so you don't need to worry about differences between them.
|
12
|
+
|
13
|
+
As mentioned in the [Build Tools](/guides/concept/builder) section, Modern.js' underlying build capability is provided by Rsbuild, and some server-side capabilities in the development environment are coupled with the build tools, such as HMR. Modern.js needs to reuse these capabilities of the Rsbuild Dev Server.
|
14
|
+
|
15
|
+
In the development environment, Modern.js directly uses the middlewares provided by Rsbuild, which includes capabilities needed during the development stage such as HMR and Proxy. Additionally, Modern.js provides capabilities such as Mock, routing, and rendering on top of this:
|
16
|
+
|
17
|
+

|
18
|
+
|
19
|
+
Therefore, in Modern.js, the development environment merely adds middleware to the production environment. All capabilities of the production environment are also applicable in the development environment, ensuring no fragmentation between the two.
|
20
|
+
|
21
|
+
:::tip
|
22
|
+
Static asset files can be directly hosted by Modern.js' server, but it is highly recommended to upload these files to a CDN in a production environment.
|
23
|
+
:::
|
24
|
+
|
25
|
+
## Running in CI Environments
|
26
|
+
|
27
|
+
Modern.js supports running built artifacts in any Node.js environment. Typically, the CI environment has already installed all application dependencies.
|
28
|
+
|
29
|
+
You can run the [`modern build`](/apis/app/commands#modern-build) command to build the application and the [`modern serve`](/apis/app/commands#modern-serve) command to run the Web server, starting the Modern.js application.
|
30
|
+
|
31
|
+
## Running in Production Environments
|
32
|
+
|
33
|
+
When deploying to production, the artifact size should be as small as possible. The aforementioned method for running in CI environments keeps all artifacts from the original project. Therefore, it is not recommended to run the application using the above commands in a production environment.
|
34
|
+
|
35
|
+
Modern.js offers a standalone deployment solution. When running the [`modern deploy`](/apis/app/commands#modern-deploy) command, the artifacts will include an entry file for running the Web server.
|
@@ -1,20 +1,20 @@
|
|
1
1
|
[
|
2
2
|
{
|
3
3
|
"type": "dir",
|
4
|
-
"name": "
|
5
|
-
"label": "
|
4
|
+
"name": "module-federation",
|
5
|
+
"label": "module-federation",
|
6
6
|
"collapsed": true
|
7
7
|
},
|
8
8
|
{
|
9
9
|
"type": "dir",
|
10
|
-
"name": "
|
11
|
-
"label": "
|
10
|
+
"name": "micro-frontend",
|
11
|
+
"label": "micro-frontend",
|
12
12
|
"collapsed": true
|
13
13
|
},
|
14
14
|
{
|
15
15
|
"type": "dir",
|
16
|
-
"name": "
|
17
|
-
"label": "
|
16
|
+
"name": "model",
|
17
|
+
"label": "reduck",
|
18
18
|
"collapsed": true
|
19
19
|
}
|
20
20
|
]
|
@@ -2,6 +2,11 @@
|
|
2
2
|
sidebar_position: 1
|
3
3
|
title: Quick Start
|
4
4
|
---
|
5
|
+
|
6
|
+
:::caution
|
7
|
+
New projects are no longer recommended to use Reduck. You can use state management tools from the community, such as [Jotai](https://jotai.org/), [zustand](https://zustand.docs.pmnd.rs/getting-started/introduction), [valtio](https://valtio.dev/docs/introduction/getting-started), etc.
|
8
|
+
:::
|
9
|
+
|
5
10
|
# Quick Start
|
6
11
|
|
7
12
|
import ReduckMigration from "@site-docs-en/components/reduck-migration"
|
@@ -0,0 +1 @@
|
|
1
|
+
["introduce", "usage", "application", "ssr", "deploy"]
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# Application-Level Modules
|
2
|
+
|
3
|
+
Modern.js provides runtime APIs to quickly export application-level Module Federation modules from your application.
|
4
|
+
|
5
|
+
We use the application created in [Using Module Federation](/guides/topic-detail/module-federation/usage) as an example to further explain how to import application-level modules.
|
6
|
+
|
7
|
+
## Install Dependencies
|
8
|
+
|
9
|
+
Building on the existing application, we need to install the `@module-federation/bridge-react` dependency to use Bridge for loading application-level modules.
|
10
|
+
|
11
|
+
import { PackageManagerTabs } from '@theme';
|
12
|
+
|
13
|
+
<PackageManagerTabs command="add @module-federation/bridge-react" />
|
14
|
+
|
15
|
+
## Exporting Modules from Producer
|
16
|
+
|
17
|
+
Unlike directly exporting component-level modules, we need to create a separate entry for application-level modules to be exported via `Module Federation`.
|
18
|
+
|
19
|
+
We create the `src/export-App.tsx` file:
|
20
|
+
|
21
|
+
:::note
|
22
|
+
The filename can be arbitrary; Modern.js does not enforce a specific naming convention.
|
23
|
+
:::
|
24
|
+
|
25
|
+
```ts title="src/export-App.tsx"
|
26
|
+
import '@modern-js/runtime/registry/main'; // This line must be included, it will import micro frontend runtime dependencies by default
|
27
|
+
import { render } from '@modern-js/runtime/browser';
|
28
|
+
import { createRoot } from '@modern-js/runtime/react';
|
29
|
+
import { createBridgeComponent } from '@module-federation/bridge-react';
|
30
|
+
|
31
|
+
const ModernRoot = createRoot();
|
32
|
+
export const provider = createBridgeComponent({
|
33
|
+
rootComponent: ModernRoot,
|
34
|
+
render: (Component, dom) => render(Component, dom),
|
35
|
+
});
|
36
|
+
|
37
|
+
export default provider;
|
38
|
+
```
|
39
|
+
|
40
|
+
This file will pass the root component of the `main` entry application to the Bridge API and render it to the specified node via Bridge's render function.
|
41
|
+
|
42
|
+
Next, we configure `module-federation.config.ts` to modify the export to `src/export-App.tsx`:
|
43
|
+
|
44
|
+
```ts title="module-federation.config.ts"
|
45
|
+
import { createModuleFederationConfig } from '@module-federation/modern-js';
|
46
|
+
|
47
|
+
export default createModuleFederationConfig({
|
48
|
+
name: 'remote',
|
49
|
+
filename: 'remoteEntry.js',
|
50
|
+
exposes: {
|
51
|
+
'./app': './src/export-App.tsx',
|
52
|
+
},
|
53
|
+
shared: {
|
54
|
+
react: { singleton: true },
|
55
|
+
'react-dom': { singleton: true },
|
56
|
+
},
|
57
|
+
});
|
58
|
+
```
|
59
|
+
|
60
|
+
:::info
|
61
|
+
[`createBridgeComponent`](https://module-federation.io/zh/practice/bridge/react-bridge.html#createbridgecomponent) is used to export application-level modules. Modern.js related APIs can be found at [createRoot](/apis/app/runtime/core/create-root) and [render](/apis/app/runtime/core/render).
|
62
|
+
:::
|
63
|
+
|
64
|
+
## Using Modules in Consumer
|
65
|
+
|
66
|
+
We then modify the consumer configuration by removing the previously created `src/routes/remote/page.tsx` route file.
|
67
|
+
|
68
|
+
We want all routes that access `/remote` to enter the aforementioned application-level module, so we add `src/routes/remote/$.tsx` instead.
|
69
|
+
|
70
|
+
:::note
|
71
|
+
If you are not familiar with the capabilities of `$.tsx`, please read [Wildcard Routes](/guides/basic-features/routes.html#通配路由).
|
72
|
+
:::
|
73
|
+
|
74
|
+
```tsx title="src/routes/remote/$.tsx"
|
75
|
+
import { createRemoteComponent } from '@module-federation/bridge-react';
|
76
|
+
import { loadRemote } from '@module-federation/modern-js/runtime';
|
77
|
+
|
78
|
+
const ErrorBoundary = (info?: { error: { message: string } }) => {
|
79
|
+
return (
|
80
|
+
<div>
|
81
|
+
<h2>This is ErrorBoundary Component, Something went wrong:</h2>
|
82
|
+
<pre style={{ color: 'red' }}>{info?.error.message}</pre>
|
83
|
+
</div>
|
84
|
+
);
|
85
|
+
};
|
86
|
+
const Loading = <div>loading...</div>;
|
87
|
+
const RemoteApp = createRemoteComponent({
|
88
|
+
loader: () => loadRemote('remote/app'),
|
89
|
+
fallback: ErrorBoundary,
|
90
|
+
loading: Loading,
|
91
|
+
});
|
92
|
+
|
93
|
+
export default RemoteApp;
|
94
|
+
```
|
95
|
+
|
96
|
+
:::info
|
97
|
+
[`createRemoteComponent`](https://module-federation.io/zh/practice/bridge/react-bridge.html#createremotecomponent) is used to load application-level modules.
|
98
|
+
:::
|
99
|
+
|
100
|
+
## Start the Application
|
101
|
+
|
102
|
+
Now, both the producer and consumer applications are set up. We can run `modern dev` locally to start both applications.
|
103
|
+
|
104
|
+
After startup, when the consumer application accesses the `/remote` route, it will enter the producer application. Accessing `http://localhost:8080/remote` will display a complete page of the producer's remote module in the browser.
|
105
|
+
|
106
|
+
You can create new route files in the producer application and add route navigation in the code. These functionalities will also work as expected.
|
107
|
+
|
108
|
+
You can refer to the example here: [Modern.js & Module Federation Application-Level Modules](https://github.com/web-infra-dev/modern-js-examples/tree/main/examples/module-federation/app-export).
|
109
|
+
|
110
|
+
## Related Documentation
|
111
|
+
|
112
|
+
- [Module Federation Bridge](https://module-federation.io/zh/practice/bridge/index.html)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Deployment
|
2
|
+
|
3
|
+
Typically, deploying a Module Federation application requires adjusting the remote module address on the consumer side to its online address.
|
4
|
+
|
5
|
+
For example, if the producer is deployed to the domain `https://my-remote-module`, you can modify the consumer's `module-federation.config.ts` file as follows:
|
6
|
+
|
7
|
+
```ts title="module-federation.config.ts"
|
8
|
+
import { createModuleFederationConfig } from '@module-federation/modern-js';
|
9
|
+
|
10
|
+
export default createModuleFederationConfig({
|
11
|
+
name: 'host',
|
12
|
+
remotes: {
|
13
|
+
remote: 'remote@http://my-remote-module/mf-manifest.json',
|
14
|
+
},
|
15
|
+
shared: {
|
16
|
+
react: { singleton: true },
|
17
|
+
'react-dom': { singleton: true },
|
18
|
+
},
|
19
|
+
});
|
20
|
+
```
|
21
|
+
|
22
|
+
At this point, the consumer will load the `manifest` configuration file of the `remote` module in the production environment.
|
23
|
+
|
24
|
+
## Deployment via Platform
|
25
|
+
|
26
|
+
The above deployment method is merely the simplest practice. In real-world scenarios, there are many constraints, such as version management, release sequencing, and more. Within ByteDance, we have set up a deployment process for Module Federation applications on our deployment platform, which helps developers address these issues.
|
27
|
+
|
28
|
+
We will continue to keep an eye on platforms with similar functionalities in the community and, in the future, enhance the documentation for deploying Modern.js + Module Federation on these types of platforms.
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Introduction
|
2
|
+
|
3
|
+
Module Federation is an architectural pattern for dividing JavaScript applications, allowing you to share code and resources among multiple JavaScript applications.
|
4
|
+
|
5
|
+
In this divided model, it can help improve application performance, enhance code maintainability, and more.
|
6
|
+
|
7
|
+
## Module Federation 2.0
|
8
|
+
|
9
|
+
Module Federation, a highlight feature introduced with Webpack 5, has been around for more than three years. This year, ByteDance, along with the author of Module Federation, [@Zack Jackson](https://github.com/ScriptedAlchemy), and community members jointly launched **Module Federation 2.0**.
|
10
|
+
|
11
|
+
Module Federation 2.0 is based on internal practices at ByteDance and the existing community ecosystem of Module Federation, addressing many issues in the previous version.
|
12
|
+
|
13
|
+
Within ByteDance, frameworks based on Modern.js have already deeply integrated with Module Federation 2.0. We are gradually integrating these features into Modern.js and hope to explore the future together with community developers.
|
14
|
+
|
15
|
+
:::info
|
16
|
+
Refer to [Module Federation 2.0 Announcement](https://module-federation.io/zh/blog/announcement.html) for more related content.
|
17
|
+
:::
|
18
|
+
|
19
|
+
## Modern.js MF Plugin
|
20
|
+
|
21
|
+
Based on internal practices at ByteDance, the Module Federation team officially provides the [Modern.js Plugin](https://www.npmjs.com/package/@module-federation/modern-js) to help developers use Module Federation more easily.
|
22
|
+
|
23
|
+
The plugin recognizes the current build engine (Webpack or Rspack), injects the corresponding Module Federation plugin into Modern.js applications, and automatically handles build configurations and adds runtime code.
|
24
|
+
|
25
|
+
Moreover, the plugin also supports the use of Module Federation in Modern.js SSR applications, providing a better performance experience.
|
26
|
+
|
27
|
+
For more details, refer to [Using Module Federation](/guides/topic-detail/module-federation/usage) and [Module Federation Server-Side Rendering](/guides/topic-detail/module-federation/ssr).
|
28
|
+
|
29
|
+
## Application-Level Modules
|
30
|
+
|
31
|
+
**Application-level modules** possess the application's framework rendering capabilities and routing capabilities, allowing them to operate like applications. Application-level modules are a crucial capability in **micro-frontend frameworks**, providing the ability to load and render across application frameworks (React, Vue) and supporting the loading of modules with routing.
|
32
|
+
|
33
|
+
Module Federation 2.0 offers the [Bridge](https://module-federation.io/zh/practice/bridge/index.html) capability to load application-level modules.
|
34
|
+
|
35
|
+
Modern.js, based on Bridge and its internal implementation, provides APIs to easily export application-level modules. For more details, refer to [Application-Level Modules](/guides/topic-detail/module-federation/application).
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Server-Side Rendering
|
2
|
+
|
3
|
+
`@module-federation/modern-js` offers powerful capabilities, enabling developers to easily combine Module Federation with server-side rendering (SSR) in Modern.js applications.
|
4
|
+
|
5
|
+
## Enable SSR
|
6
|
+
|
7
|
+
Using the application created in [Using Module Federation](/guides/topic-detail/module-federation/usage) as an example, you only need to add the `server.ssr` configuration to both the producer and the consumer:
|
8
|
+
|
9
|
+
```ts title="modern.config.ts"
|
10
|
+
import { appTools, defineConfig } from '@modern-js/app-tools';
|
11
|
+
|
12
|
+
export default defineConfig({
|
13
|
+
server: {
|
14
|
+
ssr: {
|
15
|
+
mode: 'stream',
|
16
|
+
},
|
17
|
+
},
|
18
|
+
});
|
19
|
+
```
|
20
|
+
|
21
|
+
For better performance, we only support using this capability combination in Streaming SSR scenarios.
|
22
|
+
|
23
|
+
:::warning
|
24
|
+
Currently, `@module-federation/bridge-react` is not compatible with the Node environment. You must remove it from the dependencies to use Module Federation and server-side rendering correctly. This means Bridge cannot work with server-side rendering.
|
25
|
+
:::
|
26
|
+
|
27
|
+
## Data Fetching
|
28
|
+
|
29
|
+
:::note
|
30
|
+
Stay tuned
|
31
|
+
:::
|
@@ -0,0 +1,180 @@
|
|
1
|
+
# Getting Started
|
2
|
+
|
3
|
+
To use Module Federation in Modern.js, we recommend using the official plugin `@module-federation/modern-js`.
|
4
|
+
|
5
|
+
This section will introduce how to set up both producer and consumer applications using the official plugin. First, create two applications by following the [Modern.js Quick Start](/guides/get-started/quick-start).
|
6
|
+
|
7
|
+
## Install the Plugin
|
8
|
+
|
9
|
+
After creating the applications, install the plugin for both projects:
|
10
|
+
|
11
|
+
import { PackageManagerTabs } from '@theme';
|
12
|
+
|
13
|
+
<PackageManagerTabs command="add @module-federation/modern-js" />
|
14
|
+
|
15
|
+
## Register the Plugin
|
16
|
+
|
17
|
+
After installing the plugin, you need to register it in the `modern.config.js` file:
|
18
|
+
|
19
|
+
```ts
|
20
|
+
import { appTools, defineConfig } from '@modern-js/app-tools';
|
21
|
+
import { moduleFederationPlugin } from '@module-federation/modern-js';
|
22
|
+
|
23
|
+
export default defineConfig({
|
24
|
+
runtime: {
|
25
|
+
router: true,
|
26
|
+
},
|
27
|
+
plugins: [
|
28
|
+
appTools({
|
29
|
+
bundler: 'rspack',
|
30
|
+
}),
|
31
|
+
moduleFederationPlugin(),
|
32
|
+
],
|
33
|
+
});
|
34
|
+
```
|
35
|
+
|
36
|
+
## Export Modules from Producer
|
37
|
+
|
38
|
+
Next, modify the producer's code to export the Module Federation module.
|
39
|
+
|
40
|
+
Create the `src/components/Button.tsx` file and export a Button component:
|
41
|
+
|
42
|
+
```tsx title="src/components/Button.tsx"
|
43
|
+
import React from 'react';
|
44
|
+
|
45
|
+
export const Button = () => {
|
46
|
+
return <button type="button">Remote Button</button>;
|
47
|
+
};
|
48
|
+
```
|
49
|
+
|
50
|
+
Then, add the `module-federation.config.ts` file at the project root to configure the Module Federation module's name, shared dependencies, and exports:
|
51
|
+
|
52
|
+
```ts title="module-federation.config.ts"
|
53
|
+
import { createModuleFederationConfig } from '@module-federation/modern-js';
|
54
|
+
|
55
|
+
export default createModuleFederationConfig({
|
56
|
+
name: 'remote',
|
57
|
+
filename: 'remoteEntry.js',
|
58
|
+
exposes: {
|
59
|
+
'./Button': './src/components/Button.tsx',
|
60
|
+
},
|
61
|
+
shared: {
|
62
|
+
react: { singleton: true },
|
63
|
+
'react-dom': { singleton: true },
|
64
|
+
},
|
65
|
+
});
|
66
|
+
```
|
67
|
+
|
68
|
+
Additionally, modify `modern.config.ts` to provide a development environment port for the producer, allowing the consumer to access the producer's resources through this port:
|
69
|
+
|
70
|
+
```ts title="modern.config.ts"
|
71
|
+
import { appTools, defineConfig } from '@modern-js/app-tools';
|
72
|
+
import { moduleFederationPlugin } from '@module-federation/modern-js';
|
73
|
+
|
74
|
+
export default defineConfig({
|
75
|
+
dev: {
|
76
|
+
port: 3051,
|
77
|
+
},
|
78
|
+
runtime: {
|
79
|
+
router: true,
|
80
|
+
},
|
81
|
+
plugins: [
|
82
|
+
appTools({
|
83
|
+
bundler: 'rspack',
|
84
|
+
}),
|
85
|
+
moduleFederationPlugin(),
|
86
|
+
],
|
87
|
+
});
|
88
|
+
```
|
89
|
+
|
90
|
+
## Use Modules in Consumer
|
91
|
+
|
92
|
+
Now, modify the consumer's code to use the module exported by the producer.
|
93
|
+
|
94
|
+
Add the `module-federation.config.ts` file at the project root to configure the Module Federation module's name, shared dependencies, and the remote module to use:
|
95
|
+
|
96
|
+
```ts title="module-federation.config.ts"
|
97
|
+
import { createModuleFederationConfig } from '@module-federation/modern-js';
|
98
|
+
|
99
|
+
export default createModuleFederationConfig({
|
100
|
+
name: 'host',
|
101
|
+
remotes: {
|
102
|
+
remote: 'remote@http://localhost:3051/mf-manifest.json',
|
103
|
+
},
|
104
|
+
shared: {
|
105
|
+
react: { singleton: true },
|
106
|
+
'react-dom': { singleton: true },
|
107
|
+
},
|
108
|
+
});
|
109
|
+
```
|
110
|
+
|
111
|
+
`mf-manifest.json` is the file produced by the producer after packaging, containing all the information about the modules exported by the producer.
|
112
|
+
|
113
|
+
Create a new route file `src/routes/remote/page.tsx` and import the producer module:
|
114
|
+
|
115
|
+
```tsx title="src/routes/remote/page.tsx"
|
116
|
+
import React, { useState, Suspense } from 'react';
|
117
|
+
import { Button } from 'remote/Button';
|
118
|
+
|
119
|
+
const Index = (): JSX.Element => {
|
120
|
+
return (
|
121
|
+
<div>
|
122
|
+
<Suspense fallback={<div>Loading...</div>}>
|
123
|
+
<Button />
|
124
|
+
</Suspense>
|
125
|
+
</div>
|
126
|
+
);
|
127
|
+
};
|
128
|
+
|
129
|
+
export default Index;
|
130
|
+
```
|
131
|
+
|
132
|
+
At this point, importing `remote/Button` will result in a type error because the local environment doesn't have the type for the remote module. Module Federation 2.0 provides [type hints](https://module-federation.io/zh/guide/basic/type-prompt.html), which will automatically generate type definitions for remote modules during the producer's build and download them during the consumer's build.
|
133
|
+
|
134
|
+
To ensure the types take effect, add a new `path` in `tsconfig.json`:
|
135
|
+
|
136
|
+
```json title="tsconfig.json"
|
137
|
+
{
|
138
|
+
"compilerOptions": {
|
139
|
+
"paths": {
|
140
|
+
"*": ["./@mf-types/*"]
|
141
|
+
}
|
142
|
+
}
|
143
|
+
}
|
144
|
+
```
|
145
|
+
|
146
|
+
:::tip
|
147
|
+
In the consumer, we reference the remote module using `remote/Button`. Here's a brief explanation of what this path specifically represents. You can abstract it as `[remoteAlias]/[remoteExpose]`.
|
148
|
+
|
149
|
+
The first part, `remoteAlias`, is the alias of the producer in the consumer. It is the `key` configured in the `remotes` field of the consumer's `module-federation.config.ts`:
|
150
|
+
|
151
|
+
```ts
|
152
|
+
{
|
153
|
+
remotes: {
|
154
|
+
[remoteAlias]: '[remoteModuleName]@[URL_ADDRESS]',
|
155
|
+
}
|
156
|
+
}
|
157
|
+
```
|
158
|
+
|
159
|
+
Here, we also abstract the remote address as `[remoteModuleName]@[URL_ADDRESS]`. The part before `@` must correspond to the module name of the producer.
|
160
|
+
|
161
|
+
The second part, `remoteExpose`, is the `key` configured in the `exposes` field of the producer's `module-federation.config.ts`.
|
162
|
+
:::
|
163
|
+
|
164
|
+
## Start the Applications
|
165
|
+
|
166
|
+
Now, both the producer and consumer applications are set up. You can run `modern dev` locally to start both applications.
|
167
|
+
|
168
|
+
Once started, the imports of the producer's modules in the consumer will no longer throw errors, and the types will be downloaded to the consumer application.
|
169
|
+
|
170
|
+
:::note
|
171
|
+
After modifying the producer's code, the consumer will automatically fetch the producer's types.
|
172
|
+
:::
|
173
|
+
|
174
|
+
Access `http://localhost:8080/remote`, and you will see that the page includes the `Button` component from the producer's remote module.
|
175
|
+
|
176
|
+
You can refer to this example: [Modern.js & Module Federation Basic Example](https://github.com/web-infra-dev/modern-js-examples/tree/main/examples/module-federation/base).
|
177
|
+
|
178
|
+
## Related Documentation
|
179
|
+
|
180
|
+
- [Module Federation Official Documentation](https://module-federation.io/zh/guide/framework/modernjs.html)
|
@@ -153,28 +153,9 @@ pnpm 暂不支持使用 JSON 字符串作为参数值,可使用 `npm new` 开
|
|
153
153
|
|
154
154
|
:::
|
155
155
|
|
156
|
-
|
156
|
+
import ServeCommand from "@site-docs/components/serve-command";
|
157
157
|
|
158
|
-
|
159
|
-
|
160
|
-
```bash
|
161
|
-
Usage: modern serve [options]
|
162
|
-
|
163
|
-
Options:
|
164
|
-
-c --config <config> 指定配置文件路径,可以为相对路径或绝对路径
|
165
|
-
-h, --help 显示命令帮助
|
166
|
-
--api-only 仅启动 API 接口服务
|
167
|
-
```
|
168
|
-
|
169
|
-
默认情况下,应用将会在 `localhost:8080` 启动,可以通过 `server.port` 修改 Server 端口号:
|
170
|
-
|
171
|
-
```js
|
172
|
-
export default defineConfig({
|
173
|
-
server: {
|
174
|
-
port: 8081,
|
175
|
-
},
|
176
|
-
});
|
177
|
-
```
|
158
|
+
<ServeCommand />
|
178
159
|
|
179
160
|
## modern upgrade
|
180
161
|
|
@@ -250,20 +231,6 @@ Inspect config succeed, open following files to view the content:
|
|
250
231
|
- Webpack Config (node): /root/my-project/dist/webpack.config.node.mjs
|
251
232
|
```
|
252
233
|
|
253
|
-
|
254
|
-
|
255
|
-
运行 `ESLint` 进行代码语法检查。
|
256
|
-
|
257
|
-
```bash
|
258
|
-
Usage: modern lint [options] [...files]
|
259
|
-
|
260
|
-
lint and fix source files
|
261
|
-
|
262
|
-
Options:
|
263
|
-
--no-fix disable auto fix source file
|
264
|
-
-h, --help display help for command
|
265
|
-
```
|
266
|
-
|
267
|
-
通常情况下,我们只需要在 `git commit` 阶段通过 `lint-staged` 检查本次提交修改的部分代码。
|
234
|
+
import DeployCommand from "@site-docs/components/deploy-command";
|
268
235
|
|
269
|
-
|
236
|
+
<DeployCommand />
|
@@ -0,0 +1,14 @@
|
|
1
|
+
## modern deploy
|
2
|
+
|
3
|
+
`modern deploy` 命令,用于生成部署平台需要的产物。
|
4
|
+
|
5
|
+
```bash
|
6
|
+
Usage: modern deploy [options]
|
7
|
+
|
8
|
+
Options:
|
9
|
+
-c --config <config> 指定配置文件路径,可以为相对路径或绝对路径
|
10
|
+
-s --skip-build 跳过构建阶段
|
11
|
+
-h, --help 显示命令帮助
|
12
|
+
```
|
13
|
+
|
14
|
+
详细内容可以参考 [部署应用](/guides/basic-features/deploy)。
|
@@ -0,0 +1 @@
|
|
1
|
+
Modern.js 还支持了基于浏览器 [UA](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/User-Agent) 信息的运行时按需 Polyfill 方案,具体使用姿势可查看 [运行时按需 Polyfill](/guides/advanced-features/compatibility.html#运行时按需-polyfill)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
## modern serve
|
2
|
+
|
3
|
+
`modern serve` 命令用于在生产环境下启动 Modern.js 工程, 也可以用于在本地预览生产环境构建的产物。注意你需要提前执行 [`build`](/apis/app/commands#modern-build) 命令构建出对应产物。
|
4
|
+
|
5
|
+
```bash
|
6
|
+
Usage: modern serve [options]
|
7
|
+
|
8
|
+
Options:
|
9
|
+
-c --config <config> 指定配置文件路径,可以为相对路径或绝对路径
|
10
|
+
-h, --help 显示命令帮助
|
11
|
+
--api-only 仅启动 API 接口服务
|
12
|
+
```
|
13
|
+
|
14
|
+
默认情况下,应用将会在 `localhost:8080` 启动,可以通过 `server.port` 修改 Server 端口号:
|
15
|
+
|
16
|
+
```js
|
17
|
+
export default defineConfig({
|
18
|
+
server: {
|
19
|
+
port: 8081,
|
20
|
+
},
|
21
|
+
});
|
22
|
+
```
|
@@ -8,14 +8,16 @@ import RouterLegacyTip from "@site-docs/components/router-legacy-tip"
|
|
8
8
|
|
9
9
|
<RouterLegacyTip />
|
10
10
|
|
11
|
-
# runtime.router
|
12
|
-
|
13
11
|
- **类型:** `boolean | Object`
|
14
12
|
- **默认值:** `false`
|
15
13
|
|
16
|
-
|
14
|
+
该值在项目创建时被设置为 `true`,支持使用 Modern.js 默认提供的[约定式路由](/guides/concept/entries.html#约定式路由)进行路由管理。
|
15
|
+
|
16
|
+
如果希望使用[自控式路由](/guides/concept/entries.html#自控式路由),请移除该值,或将该值设置为 `false`。
|
17
17
|
|
18
|
-
|
18
|
+
:::note
|
19
|
+
`router` 的所有子配置都只会在使用约定式路由时生效。
|
20
|
+
:::
|
19
21
|
|
20
22
|
## basename
|
21
23
|
|
@@ -24,6 +26,10 @@ import RouterLegacyTip from "@site-docs/components/router-legacy-tip"
|
|
24
26
|
|
25
27
|
设置客户端路由的 `basename`,通常用于应用需要部署在域名非根路径下的场景。
|
26
28
|
|
29
|
+
:::tip
|
30
|
+
推荐使用 [`server.baseUrl`](/configure/app/server/base-url) 进行配置。
|
31
|
+
:::
|
32
|
+
|
27
33
|
## supportHtml5History
|
28
34
|
|
29
35
|
- **类型:** `boolean`
|
@@ -1 +1 @@
|
|
1
|
-
["entries", "builder"]
|
1
|
+
["entries", "builder", "server"]
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Web 服务器
|
2
|
+
|
3
|
+
Modern.js 为应用提供了内置的 Web 服务器,可以被运行在任何拥有 Node.js 的容器环境中。无论是在本地开发环境中执行 `dev` 命令,或是执行 `build && serve` 命令运行生成环境产物,或是官方的部署方案,都是通过这个 Web 服务器来托管应用。
|
4
|
+
|
5
|
+
## 底层依赖
|
6
|
+
|
7
|
+
Modern.js 基于 [Hono 框架](https://hono.dev/) 搭建了自己的 Web 服务器。Hono 是一个小型、简单且超快速的基于 Web 标准的框架,它能在任何 JavaScript 运行时上运行。
|
8
|
+
|
9
|
+
## 开发 & 生产
|
10
|
+
|
11
|
+
Modern.js 开发环境和生产环境的 Web 服务器流程是完全同构的,你无需担心开发环境和生产环境的差异。
|
12
|
+
|
13
|
+
在 [构建工具](/guides/concept/builder) 一节我们提到,Modern.js 底层构建能力由 Rsbuild 提供,而部分开发环境的服务端能力是与构建工具耦合的,例如 HMR。Modern.js 需要复用 Rsbuild Dev Server 的能力。
|
14
|
+
|
15
|
+
在开发环境,Modern.js 直接使用了 Rsbuild 提供的中间件,包含 HMR、Proxy 等开发阶段需要的能力。同时,Modern.js 在这之上提供了 Mock、路由、渲染等能力:
|
16
|
+
|
17
|
+

|
18
|
+
|
19
|
+
因此,在 Modern.js 中开发环境只是在生产环境上增加了中间件。生产环境的所有能力,在开发环境中也同样适用,两者不会产生割裂。
|
20
|
+
|
21
|
+
:::tip
|
22
|
+
静态资源文件能够直接被 Modern.js 的服务器托管,但在生产环境中,强烈推荐将这些内容上传到 CDN。
|
23
|
+
:::
|
24
|
+
|
25
|
+
## 在 CI 环境中运行
|
26
|
+
|
27
|
+
Modern.js 支持在任何 Node.js 环境运行构建产物。在 CI 环境中,通常情况下已经安装了应用全部的依赖。
|
28
|
+
|
29
|
+
你可以执行 [`modern build`](/apis/app/commands#modern-build) 来构建应用,执行 [`modern serve`](/apis/app/commands#modern-serve) 命令来运行 Web 服务器,启动 Modern.js 应用。
|
30
|
+
|
31
|
+
## 在生产环境中运行
|
32
|
+
|
33
|
+
在部署到生产环境时,产物体积应该尽可能小,而上述在 CI 中运行的方案,会保留原项目的所有产物。因此在生产环境,不推荐通过上述命令运行应用。
|
34
|
+
|
35
|
+
Modern.js 提供了独立的部署方案,当运行 [`modern deploy`](/apis/app/commands#modern-deploy) 命令时,产物中会包含可运行 Web 服务器的入口文件。
|
@@ -1,20 +1,20 @@
|
|
1
1
|
[
|
2
2
|
{
|
3
3
|
"type": "dir",
|
4
|
-
"name": "
|
5
|
-
"label": "
|
4
|
+
"name": "module-federation",
|
5
|
+
"label": "module-federation",
|
6
6
|
"collapsed": true
|
7
7
|
},
|
8
8
|
{
|
9
9
|
"type": "dir",
|
10
|
-
"name": "
|
11
|
-
"label": "
|
10
|
+
"name": "micro-frontend",
|
11
|
+
"label": "micro-frontend",
|
12
12
|
"collapsed": true
|
13
13
|
},
|
14
14
|
{
|
15
15
|
"type": "dir",
|
16
|
-
"name": "
|
17
|
-
"label": "
|
16
|
+
"name": "model",
|
17
|
+
"label": "reduck",
|
18
18
|
"collapsed": true
|
19
19
|
}
|
20
20
|
]
|
@@ -2,6 +2,11 @@
|
|
2
2
|
sidebar_position: 1
|
3
3
|
title: 快速上手
|
4
4
|
---
|
5
|
+
|
6
|
+
:::caution
|
7
|
+
新项目不再推荐使用 Reduck,可以使用社区中的状态管理工具,例如 [Jotai](https://jotai.org/)、[zustand](https://zustand.docs.pmnd.rs/getting-started/introduction)、[valtio](https://valtio.dev/docs/introduction/getting-started) 等。
|
8
|
+
:::
|
9
|
+
|
5
10
|
# 快速上手
|
6
11
|
|
7
12
|
import ReduckMigration from "@site-docs/components/reduck-migration"
|
@@ -0,0 +1 @@
|
|
1
|
+
["introduce", "usage", "application", "ssr", "deploy"]
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# 应用级别模块
|
2
|
+
|
3
|
+
Modern.js 提供了运行时 API,支持快速从应用中导出应用级别的 Module Federation 模块。
|
4
|
+
|
5
|
+
我们以 [使用模块联邦](/guides/topic-detail/module-federation/usage) 创建的应用为例,进一步说明如何导入应用级别模块。
|
6
|
+
|
7
|
+
## 安装依赖
|
8
|
+
|
9
|
+
在原本应用的基础上,我们需要安装 `@module-federation/bridge-react` 依赖,用于使用 Bridge 加载应用级别模块。
|
10
|
+
|
11
|
+
import { PackageManagerTabs } from '@theme';
|
12
|
+
|
13
|
+
<PackageManagerTabs command="add @module-federation/bridge-react" />
|
14
|
+
|
15
|
+
## 生产者导出模块
|
16
|
+
|
17
|
+
和直接导出组件级别的模块不同,我们需要为应用级别模块创建一个独立的入口来作为 `Module Federation` 的导出。
|
18
|
+
|
19
|
+
我们创建 `src/export-App.tsx` 文件:
|
20
|
+
|
21
|
+
:::note
|
22
|
+
这里可以是任意的文件名,Modern.js 没有做强制约定。
|
23
|
+
:::
|
24
|
+
|
25
|
+
```ts title="src/export-App.tsx"
|
26
|
+
import '@modern-js/runtime/registry/main'; // 这一行必须引入,它会默认导入微前端运行时依赖
|
27
|
+
import { render } from '@modern-js/runtime/browser';
|
28
|
+
import { createRoot } from '@modern-js/runtime/react';
|
29
|
+
import { createBridgeComponent } from '@module-federation/bridge-react';
|
30
|
+
|
31
|
+
const ModernRoot = createRoot();
|
32
|
+
export const provider = createBridgeComponent({
|
33
|
+
rootComponent: ModernRoot,
|
34
|
+
render: (Component, dom) => render(Component, dom),
|
35
|
+
});
|
36
|
+
|
37
|
+
export default provider;
|
38
|
+
```
|
39
|
+
|
40
|
+
该文件会将 `main` 入口的应用根组件传递给 Bridge API,并通过 Bridge 将调用渲染函数将其渲染到指定的节点上。
|
41
|
+
|
42
|
+
接下来,我们配置 `module-federation.config.ts`,将导出修改为 `src/export-App.tsx`:
|
43
|
+
|
44
|
+
```ts title="module-federation.config.ts"
|
45
|
+
import { createModuleFederationConfig } from '@module-federation/modern-js';
|
46
|
+
|
47
|
+
export default createModuleFederationConfig({
|
48
|
+
name: 'remote',
|
49
|
+
filename: 'remoteEntry.js',
|
50
|
+
exposes: {
|
51
|
+
'./app': './src/export-App.tsx',
|
52
|
+
},
|
53
|
+
shared: {
|
54
|
+
react: { singleton: true },
|
55
|
+
'react-dom': { singleton: true },
|
56
|
+
},
|
57
|
+
});
|
58
|
+
```
|
59
|
+
|
60
|
+
:::info
|
61
|
+
[`createBridgeComponent`](https://module-federation.io/zh/practice/bridge/react-bridge.html#createbridgecomponent) 用于导出应用级别模块,Modern.js 相关 API 可以查看 [createRoot](/apis/app/runtime/core/create-root)、[render](/apis/app/runtime/core/render)。
|
62
|
+
:::
|
63
|
+
|
64
|
+
## 消费者使用模块
|
65
|
+
|
66
|
+
然后我们修改消费者配置,移除之前创建的的路由文件 `src/routes/remote/page.tsx`。
|
67
|
+
|
68
|
+
我们希望所有访问到 `/remote` 的路由都能被进入上述应用级别模块中,因此我们重新添加 `src/routes/remote/$.tsx`。
|
69
|
+
|
70
|
+
:::note
|
71
|
+
如果你还不了解 `$.tsx` 的能力,可以阅读 [通配路由](/guides/basic-features/routes.html#通配路由)。
|
72
|
+
:::
|
73
|
+
|
74
|
+
```tsx title="src/routes/remote/$.tsx"
|
75
|
+
import { createRemoteComponent } from '@module-federation/bridge-react';
|
76
|
+
import { loadRemote } from '@module-federation/modern-js/runtime';
|
77
|
+
|
78
|
+
const ErrorBoundary = (info?: { error: { message: string } }) => {
|
79
|
+
return (
|
80
|
+
<div>
|
81
|
+
<h2>This is ErrorBoundary Component, Something went wrong:</h2>
|
82
|
+
<pre style={{ color: 'red' }}>{info?.error.message}</pre>
|
83
|
+
</div>
|
84
|
+
);
|
85
|
+
};
|
86
|
+
const Loading = <div>loading...</div>;
|
87
|
+
const RemoteApp = createRemoteComponent({
|
88
|
+
loader: () => loadRemote('remote/app'),
|
89
|
+
fallback: ErrorBoundary,
|
90
|
+
loading: Loading,
|
91
|
+
});
|
92
|
+
|
93
|
+
export default RemoteApp;
|
94
|
+
```
|
95
|
+
|
96
|
+
:::info
|
97
|
+
[`createRemoteComponent`](https://module-federation.io/zh/practice/bridge/react-bridge.html#createremotecomponent) 用于加载应用级别模块。
|
98
|
+
:::
|
99
|
+
|
100
|
+
## 启动应用
|
101
|
+
|
102
|
+
现在,生产者应用和消费者应用都已经搭建完毕,我们可以在本地运行 `modern dev` 启动两个应用。
|
103
|
+
|
104
|
+
启动后,消费者应用访问 `/remote` 路由时,会进入生产者应用中。访问 `http://localhost:8080/remote`,可以看到页面中已经包含了生产者的远程模块的完整页面。
|
105
|
+
|
106
|
+
你可以在生产者应用中,创建新的路由文件,并在代码中添加路由导航,可以发现这些功能也能够正常运行。
|
107
|
+
|
108
|
+
上述用例可以参考:[Modern.js & Module Federation 应用级别模块](https://github.com/web-infra-dev/modern-js-examples/tree/main/examples/module-federation/app-export)。
|
109
|
+
|
110
|
+
## 相关文档
|
111
|
+
|
112
|
+
- [Module Federation Bridge](https://module-federation.io/zh/practice/bridge/index.html)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# 部署
|
2
|
+
|
3
|
+
通常情况下,部署 Module Federation 应用,需要在消费者上将远程模块地址,调整为其线上地址。
|
4
|
+
|
5
|
+
例如已经将生产者部署到 `https://my-remote-module` 这个域名下,可以这样修改消费者的 `module-federation.config.ts` 文件:
|
6
|
+
|
7
|
+
```ts title="module-federation.config.ts"
|
8
|
+
import { createModuleFederationConfig } from '@module-federation/modern-js';
|
9
|
+
|
10
|
+
export default createModuleFederationConfig({
|
11
|
+
name: 'host',
|
12
|
+
remotes: {
|
13
|
+
remote: 'remote@http://my-remote-module/mf-manifest.json',
|
14
|
+
},
|
15
|
+
shared: {
|
16
|
+
react: { singleton: true },
|
17
|
+
'react-dom': { singleton: true },
|
18
|
+
},
|
19
|
+
});
|
20
|
+
```
|
21
|
+
|
22
|
+
此时,消费者将加载生产环境的 `remote` 模块的 `manifest` 配置文件。
|
23
|
+
|
24
|
+
## 通过平台部署
|
25
|
+
|
26
|
+
上述部署方式只是最简单的实践,在真实场景还有很多限制,例如版本管理、发布时序等。在字节跳动内部,我们在部署平台上搭建了 Module Federation 应用的部署流程,可以帮助开发者解决这些问题。
|
27
|
+
|
28
|
+
我们会持续关注社区里类似功能的平台,在未来完善 Modern.js + Module Federation 在这些类平台上的部署文档。
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# 简介
|
2
|
+
|
3
|
+
模块联邦(Module Federation)是一种 JavaScript 应用分治的架构模式,它允许你在多个 JavaScript 应用之间共享代码和资源。
|
4
|
+
|
5
|
+
在这种分治的模式下,可以帮助你提升应用程序的性能,增强代码可维护性等。
|
6
|
+
|
7
|
+
## Module Federation 2.0
|
8
|
+
|
9
|
+
Module Federation 作为 Webpack 5 推出的重磅功能,自发布以来已经三年有余。在今年,字节跳动与 Module Federation 的作者 [@Zack Jackson](https://github.com/ScriptedAlchemy) 以及社区成员共同推出了 **Module Federation 2.0**。
|
10
|
+
|
11
|
+
Module Federation 2.0 基于字节跳动内部实践以及 Module Federation 原有社区生态,解决了原先版本中的诸多问题。
|
12
|
+
|
13
|
+
在字节跳动内部,基于 Modern.js 的框架已经与 Module Federation 2.0 进行了深度集成。我们正在逐步将这些功能集成到 Modern.js 中,希望与社区开发者共同探索未来。
|
14
|
+
|
15
|
+
:::info
|
16
|
+
参考 [Module Federation 2.0 发布](https://module-federation.io/zh/blog/announcement.html) 获取更多相关内容。
|
17
|
+
:::
|
18
|
+
|
19
|
+
## Modern.js MF 插件
|
20
|
+
|
21
|
+
基于字节跳动内部实践,Module Federation 团队官方提供了 [Modern.js 插件](https://www.npmjs.com/package/@module-federation/modern-js),帮助开发者更方便的使用 Module Federation。
|
22
|
+
|
23
|
+
插件会识别当前构建引擎(Webpack 或 Rspack),在 Modern.js 应用中注入 Module Federation 对应插件,并自动处理构建配置、添加运行时代码等。
|
24
|
+
|
25
|
+
同时,插件还支持在 Modern.js SSR 应用中使用 Module Federation,提供更好的性能体验。
|
26
|
+
|
27
|
+
详细内容可以参考 [使用 Module Federation](/guides/topic-detail/module-federation/usage)、[Module Federation 服务端渲染](/guides/topic-detail/module-federation/ssr)。
|
28
|
+
|
29
|
+
## 应用维度模块
|
30
|
+
|
31
|
+
**应用级别模块**是具备应用的框架渲染能力及路由能力,能像应用一样运行的模块。应用级别模块是在**微前端框架**中非常重要的能力,提供跨应用框架(React、Vue)加载和渲染的能力,支持加载带路由的模块。
|
32
|
+
|
33
|
+
Module Federation 2.0 提供了 [Bridge](https://module-federation.io/zh/practice/bridge/index.html) 的能力,用于加载应用级别模块。
|
34
|
+
|
35
|
+
Modern.js 基于 Brdige 和自身内部实现提供了 API,可以非常简单的导出应用级别模块。详细内容可以参考 [应用级别模块](/guides/topic-detail/module-federation/application)。
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# 服务端渲染
|
2
|
+
|
3
|
+
`@module-federation/modern-js` 提供了非常强大的能力,开发者可以非常方便的在 Modern.js 应用中,组合使用 Module Federation 和服务端渲染(SSR)的能力。
|
4
|
+
|
5
|
+
## 开启 SSR
|
6
|
+
|
7
|
+
我们以 [使用模块联邦](/guides/topic-detail/module-federation/usage) 创建的应用为例,只需要在生产者和消费者上,都添加 `server.ssr` 配置即可:
|
8
|
+
|
9
|
+
```ts title="modern.config.ts"
|
10
|
+
import { appTools, defineConfig } from '@modern-js/app-tools';
|
11
|
+
|
12
|
+
export default defineConfig({
|
13
|
+
server: {
|
14
|
+
ssr: {
|
15
|
+
mode: 'stream',
|
16
|
+
},
|
17
|
+
},
|
18
|
+
}
|
19
|
+
```
|
20
|
+
|
21
|
+
为更好的性能体验,我们仅支持 Streaming SSR 情况使用这种能力组合。
|
22
|
+
|
23
|
+
:::warning
|
24
|
+
目前 `@module-federation/bridge-react` 未兼容 Node 环境,你必须从依赖中移除它,才能正常使用 Module Federation 和服务端渲染。这意味着 Bridge 无法和服务端渲染配合使用。
|
25
|
+
:::
|
26
|
+
|
27
|
+
## 数据获取
|
28
|
+
|
29
|
+
:::note
|
30
|
+
敬请期待
|
31
|
+
:::
|
@@ -0,0 +1,181 @@
|
|
1
|
+
# 开始使用
|
2
|
+
|
3
|
+
在 Modern.js 中使用 Module Federation 我们推荐使用官方插件 `@module-federation/modern-js`。
|
4
|
+
|
5
|
+
本章节将会介绍如何通过官方插件搭含生产者应用与消费者应用,我们首先根据 [Modern.js 快速上手](/guides/get-started/quick-start) 创建两个应用。
|
6
|
+
|
7
|
+
## 安装插件
|
8
|
+
|
9
|
+
完成应用创建后,我们分别为两个项目安装插件:
|
10
|
+
|
11
|
+
import { PackageManagerTabs } from '@theme';
|
12
|
+
|
13
|
+
<PackageManagerTabs command="add @module-federation/modern-js" />
|
14
|
+
|
15
|
+
## 注册插件
|
16
|
+
|
17
|
+
安装插件后,你需要在 `modern.config.js` 中注册插件:
|
18
|
+
|
19
|
+
```ts
|
20
|
+
import { appTools, defineConfig } from '@modern-js/app-tools';
|
21
|
+
import { moduleFederationPlugin } from '@module-federation/modern-js';
|
22
|
+
|
23
|
+
export default defineConfig({
|
24
|
+
runtime: {
|
25
|
+
router: true,
|
26
|
+
},
|
27
|
+
plugins: [
|
28
|
+
appTools({
|
29
|
+
bundler: 'rspack',
|
30
|
+
}),
|
31
|
+
moduleFederationPlugin(),
|
32
|
+
],
|
33
|
+
});
|
34
|
+
|
35
|
+
```
|
36
|
+
|
37
|
+
## 生产者导出模块
|
38
|
+
|
39
|
+
接下来,我们先修改生产者的代码,导出 Module Federation 模块。
|
40
|
+
|
41
|
+
我们创建 `src/components/Button.tsx` 文件,导出一个 Button 组件:
|
42
|
+
|
43
|
+
```tsx title="src/components/Button.tsx"
|
44
|
+
import React from 'react';
|
45
|
+
|
46
|
+
export const Button = () => {
|
47
|
+
return <button type="button">Remote Button</button>;
|
48
|
+
};
|
49
|
+
```
|
50
|
+
|
51
|
+
随后,在项目根目录添加 `module-federation.config.ts`,配置 Module Federation 模块的名称、共享依赖和导出内容:
|
52
|
+
|
53
|
+
```ts title="module-federation.config.ts"
|
54
|
+
import { createModuleFederationConfig } from '@module-federation/modern-js';
|
55
|
+
|
56
|
+
export default createModuleFederationConfig({
|
57
|
+
name: 'remote',
|
58
|
+
filename: 'remoteEntry.js',
|
59
|
+
exposes: {
|
60
|
+
'./Button': './src/components/Button.tsx',
|
61
|
+
},
|
62
|
+
shared: {
|
63
|
+
react: { singleton: true },
|
64
|
+
'react-dom': { singleton: true },
|
65
|
+
},
|
66
|
+
});
|
67
|
+
```
|
68
|
+
|
69
|
+
另外,我们还需要修改 `modern.config.ts`,为生产者提供一个开发环境的端口,让消费者可以通过此端口访问生产者的资源:
|
70
|
+
|
71
|
+
```ts title="modern.config.ts"
|
72
|
+
import { appTools, defineConfig } from '@modern-js/app-tools';
|
73
|
+
import { moduleFederationPlugin } from '@module-federation/modern-js';
|
74
|
+
|
75
|
+
export default defineConfig({
|
76
|
+
dev: {
|
77
|
+
port: 3051,
|
78
|
+
},
|
79
|
+
runtime: {
|
80
|
+
router: true,
|
81
|
+
},
|
82
|
+
plugins: [
|
83
|
+
appTools({
|
84
|
+
bundler: 'rspack',
|
85
|
+
}),
|
86
|
+
moduleFederationPlugin(),
|
87
|
+
],
|
88
|
+
});
|
89
|
+
```
|
90
|
+
|
91
|
+
## 消费者使用模块
|
92
|
+
|
93
|
+
现在,我们修改消费者的代码,使用生产者导出的模块。
|
94
|
+
|
95
|
+
在项目根目录添加 `module-federation.config.ts`,配置 Module Federation 模块的名称、共享依赖和使用的远程模块:
|
96
|
+
|
97
|
+
```ts title="module-federation.config.ts"
|
98
|
+
import { createModuleFederationConfig } from '@module-federation/modern-js';
|
99
|
+
|
100
|
+
export default createModuleFederationConfig({
|
101
|
+
name: 'host',
|
102
|
+
remotes: {
|
103
|
+
remote: 'remote@http://localhost:3051/mf-manifest.json',
|
104
|
+
},
|
105
|
+
shared: {
|
106
|
+
react: { singleton: true },
|
107
|
+
'react-dom': { singleton: true },
|
108
|
+
},
|
109
|
+
});
|
110
|
+
```
|
111
|
+
|
112
|
+
`mf-manifest.json` 是生产者在打包后产出的文件,包含了生产者导出的所有模块信息。
|
113
|
+
|
114
|
+
我们创建新的路由文件 `src/routes/remote/page.tsx`,引入生产者模块:
|
115
|
+
|
116
|
+
```tsx title="src/routes/remote/page.tsx"
|
117
|
+
import React, { useState, Suspense } from 'react';
|
118
|
+
import { Button } from 'remote/Button';
|
119
|
+
|
120
|
+
const Index = (): JSX.Element => {
|
121
|
+
return (
|
122
|
+
<div>
|
123
|
+
<Suspense fallback={<div>Loading...</div>}>
|
124
|
+
<Button />
|
125
|
+
</Suspense>
|
126
|
+
</div>
|
127
|
+
);
|
128
|
+
};
|
129
|
+
|
130
|
+
export default Index;
|
131
|
+
```
|
132
|
+
|
133
|
+
此时 `remote/Button` 引入会出现类型错误,这是因为本地没有远程模块的类型。Module Federation 2.0 提供了 [类型提示](https://module-federation.io/zh/guide/basic/type-prompt.html) 的能力,会在生产者构建时自动生成远程模块的类型定义,在消费者构建时自动下载。
|
134
|
+
|
135
|
+
为此我们需要在 `tsconfig.json` 中添加新的 `path`,保证类型生效:
|
136
|
+
|
137
|
+
```json title="tsconfig.json"
|
138
|
+
{
|
139
|
+
"compilerOptions": {
|
140
|
+
"paths": {
|
141
|
+
"*": ["./@mf-types/*"]
|
142
|
+
}
|
143
|
+
}
|
144
|
+
}
|
145
|
+
```
|
146
|
+
|
147
|
+
:::tip
|
148
|
+
在消费者中,我们通过 `remote/Button` 来引用远程模块。这里简单介绍下这个路径具体代表了什么,可以先将它抽象成 `[remoteAlias]/[remoteExpose]`。
|
149
|
+
|
150
|
+
第一段 `remoteAlias` 是生产者在消费者中的别名,它是消费者 `module-federation.config.ts` 中配置的 `remotes` 字段的 `key`:
|
151
|
+
|
152
|
+
```ts
|
153
|
+
{
|
154
|
+
remotes: {
|
155
|
+
[remoteAlias]: '[remoteModuleName]@[URL_ADDRESS]',
|
156
|
+
}
|
157
|
+
}
|
158
|
+
```
|
159
|
+
|
160
|
+
这里我们也将远程地址抽象为 `[remoteModuleName]@[URL_ADDRESS]`,`@` 前的部分必须对应生产者的模块名。
|
161
|
+
|
162
|
+
第二段 `remoteExpose` 是生产者在 `module-federation.config.ts` 中配置的 `exposes` 字段的 `key`。
|
163
|
+
:::
|
164
|
+
|
165
|
+
## 启动应用
|
166
|
+
|
167
|
+
现在,生产者应用和消费者应用都已经搭建完毕,我们可以在本地运行 `modern dev` 启动两个应用。
|
168
|
+
|
169
|
+
启动后,消费者中对生产者模块的引入,不会再出现抛错,类型已经下载到消费者应用中。
|
170
|
+
|
171
|
+
:::note
|
172
|
+
修改生产者代码后,消费者会自动拉取生产者的类型。
|
173
|
+
:::
|
174
|
+
|
175
|
+
访问 `http://localhost:8080/remote`,可以看到页面中已经包含了生产者的远程模块 `Button` 组件。
|
176
|
+
|
177
|
+
上述用例可以参考:[Modern.js & Module Federation 基础用法示例](https://github.com/web-infra-dev/modern-js-examples/tree/main/examples/module-federation/base)。
|
178
|
+
|
179
|
+
## 相关文档
|
180
|
+
|
181
|
+
- [Module Federation 官方文档](https://module-federation.io/zh/guide/framework/modernjs.html)
|
package/i18n.json
CHANGED
package/package.json
CHANGED
@@ -15,13 +15,14 @@
|
|
15
15
|
"modern",
|
16
16
|
"modern.js"
|
17
17
|
],
|
18
|
-
"version": "2.60.
|
18
|
+
"version": "2.60.2",
|
19
19
|
"publishConfig": {
|
20
20
|
"registry": "https://registry.npmjs.org/",
|
21
|
-
"access": "public"
|
21
|
+
"access": "public",
|
22
|
+
"provenance": true
|
22
23
|
},
|
23
24
|
"dependencies": {
|
24
|
-
"@modern-js/sandpack-react": "2.60.
|
25
|
+
"@modern-js/sandpack-react": "2.60.2"
|
25
26
|
},
|
26
27
|
"devDependencies": {
|
27
28
|
"@rspress/shared": "1.31.0",
|