Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
# Deployment

Typically, deploying a Module Federation application requires adjusting the remote module address on the consumer side to its online address.
In general, when deploying a Module Federation application, there are two key points to consider:

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:
1. Ensure that the remote module addresses in the consumer's configuration file are correct, and that the consumer can correctly access the producer's `manifest` file.
2. Ensure that all resources in the producer's `manifest` file can be accessed correctly.

We recommend using Modern.js's [Node Server](/guides/basic-features/deploy.html#using-modernjs-built-in-nodejs-server) to deploy Module Federation applications for an out-of-the-box experience.

## Consumer

For the consumer of Module Federation, its connection with the producer is the remote module address in the configuration file.

For example, if the producer is deployed under the domain `https://my-remote-module`, the developer needs to modify the consumer's configuration file:

```ts title="module-federation.config.ts"
import { createModuleFederationConfig } from '@module-federation/modern-js';

export default createModuleFederationConfig({
name: 'host',
remotes: {
remote: 'remote@http://my-remote-module/mf-manifest.json',
remote: 'remote@https://my-remote-module/static/mf-manifest.json',
},
shared: {
react: { singleton: true },
Expand All @@ -19,10 +28,77 @@ export default createModuleFederationConfig({
});
```

At this point, the consumer will load the `manifest` configuration file of the `remote` module in the production environment.
At this point, the consumer will load the `manifest` configuration file of the remote module production environment.

:::note
In the above code, the address of the remote module is `/static/mf-manifest.json`, which is just an example using the default output path of Modern.js. In actual projects, developers need to configure according to the actual access path.
:::

## Producer

For the producer of Module Federation, developers need to correctly configure the [`output.assetPrefix`](/configure/app/output/asset-prefix) configuration, which affects:

1. The `publicPath` defined in `mf-manifest.json`, which determines the access path of other resources of the remote module.
2. The access path of the `mf-manifest.json` file when hosted directly by the Modern.js server.

In the production environment, developers need to configure `output.assetPrefix` as the access path of the production environment. For example, if we deploy the producer under the domain `https://my-remote-module`, we need to configure `output.assetPrefix` as `https://my-remote-module`.

```ts title="modern.config.ts"
import { defineConfig } from '@modern-js/app-tools';

export default defineConfig({
output: {
assetPrefix: 'https://my-remote-module',
},
});
```

At this point, the `publicPath` defined in the producer's build output `mf-manifest.json` is `https://my-remote-module`, for example:

```json
{
"id": "remote",
"name": "remote",
"metaData": {
"name": "remote",
"publicPath": "https://my-remote-module/"
},
"shared": [ /* xxx */ ],
"remotes": [],
"exposes": [ /* xxx */ ]
}
```

When the consumer accesses the remote module, it will automatically prepend the `publicPath` to the resource path of the remote module.

This configuration will also affect the access path of the producer's `mf-manifest.json`. For example, if this value is set to `MyDomain/module-a`, the hosting path of `mf-manifest.json` becomes `MyDomain/module-a/static/mf-manifest.json`.

At this point, the consumer needs to configure the following address when configuring the remote module:

```ts title="module-federation.config.ts"
import { createModuleFederationConfig } from '@module-federation/modern-js';

export default createModuleFederationConfig({
name: 'host',
remotes: {
remote: 'remote@MyDomain/module-a/static/mf-manifest.json',
},
});
```

## Local Deployment Verification

## Deployment via Platform
Modern.js provides the `modern deploy` command, which can easily generate products that can run in a Node.js environment.

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.
```bash
modern deploy
```

After executing the command, you can see the following output in the console:

```bash
Static directory: .output/static
You can preview this build by node .output/index
```

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.
At this point, the developer only needs to run `node .output/index` to preview the effect locally. Whether it is a CSR or an SSR application, all Module Federation files can be accessed correctly.
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,6 @@ If we want to simulate the production environment in local, but not configure `o
import { appTools, defineConfig } from '@modern-js/app-tools';
import { moduleFederationPlugin } from '@module-federation/modern-js';

const isLocal = process.env.IS_LOCAL === 'true';

// https://modernjs.dev/en/configure/app/usage
export default defineConfig({
server: {
Expand All @@ -204,7 +202,7 @@ export default defineConfig({
// Now this configuration is only used in the local when you run modern serve command.
// If you want to deploy the application to the platform, use your own domain name.
// Module federation will automatically write it to mf-manifest.json, which influences consumer to fetch remoteEntry.js.
assetPrefix: isLocal ? 'http://127.0.0.1:3051' : '/',
assetPrefix: 'http://127.0.0.1:3051',
},
plugins: [
appTools({
Expand All @@ -215,7 +213,7 @@ export default defineConfig({
});
```

Now, in the producer, run `IS_LOCAL=true modern build && modern serve`, and in the consumer, run `modern build && modern serve` to simulate the production environment locally and access the remote modules.
Now, in the producer, run `modern build && modern serve`, and in the consumer, run `modern build && modern serve` to simulate the production environment locally and access the remote modules.

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).

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
# 部署

通常情况下,部署 Module Federation 应用,需要在消费者上将远程模块地址,调整为其线上地址。
通常情况下,部署 Module Federation 应用,需要注意两点:

例如已经将生产者部署到 `https://my-remote-module` 这个域名下,可以这样修改消费者的 `module-federation.config.ts` 文件:
1. 保证消费者配置文件中的远程模块地址无误,消费者能够正确访问到生产者的 `manifest` 文件。
2. 保证生产者 `manifest` 文件中各个资源能被正确访问到。

我们推荐使用 Modern.js 的 [Node 服务](/guides/basic-features/deploy.html#modernjs-内置-nodejs-服务器)来部署 Module Federation 应用,以获得开箱即用的体验。

## 消费者

对于 Module Federation 的消费者来说,它与生产者的联系就是在配置文件中的远程模块地址。

例如生产者部署在 `https://my-remote-module` 这个域名下,开发者需要修改消费者的配置文件:

```ts title="module-federation.config.ts"
import { createModuleFederationConfig } from '@module-federation/modern-js';

export default createModuleFederationConfig({
name: 'host',
remotes: {
remote: 'remote@http://my-remote-module/mf-manifest.json',
remote: 'remote@https://my-remote-module/static/mf-manifest.json',
},
shared: {
react: { singleton: true },
Expand All @@ -19,10 +28,77 @@ export default createModuleFederationConfig({
});
```

此时,消费者将加载生产环境的 `remote` 模块的 `manifest` 配置文件。
此时,消费者将加载远程模块生产环境的 `manifest` 配置文件。

:::note
上述代码中,远程模块的地址是 `/static/mf-manifest.json`,这只是以 Modern.js 默认的产物路径举例。在实际项目中,开发者需要根据实际的访问路径进行配置。
:::

## 生产者

对于 Module Federation 的生产者,开发者需要正确的配置 [`output.assetPrefix`](/configure/app/output/asset-prefix) 配置,它会影响到:

1. `mf-manifest.json` 中定义的 `publicPath`,它决定了远程模块其他资源的访问路径。
2. 通过 Modern.js 服务直接托管产物时,`mf-manifest.json` 文件的访问路径。

在生产环境,开发者需要将 `output.assetPrefix` 配置为生产环境的访问路径。例如我们将生产者部署在 `https://my-remote-module` 这个域名下,需要将 `output.assetPrefix` 配置为 `https://my-remote-module`。

```ts title="modern.config.ts"
import { defineConfig } from '@modern-js/app-tools';

export default defineConfig({
output: {
assetPrefix: 'https://my-remote-module',
},
});
```

此时,生产者构建产物 `mf-manifest.json` 中定义的 `publicPath` 为 `https://my-remote-module`,例如:

```json
{
"id": "remote",
"name": "remote",
"metaData": {
"name": "remote",
"publicPath": "https://my-remote-module/"
},
"shared": [ /* xxx */ ],
"remotes": [],
"exposes": [ /* xxx */ ]
}
```

消费者在访问远程模块时,会自动将 `publicPath` 拼接在远程模块的资源路径前。

该配置也会影响到生产者 `mf-manifest.json` 的访问路径。例如将这个值设置为 `MyDomain/module-a` 时,`mf-manifest.json` 的托管路径变为 `MyDomain/module-a/static/mf-manifest.json`。

此时,消费者在配置远程模块时,需要配置以下地址:

```ts title="module-federation.config.ts"
import { createModuleFederationConfig } from '@module-federation/modern-js';

export default createModuleFederationConfig({
name: 'host',
remotes: {
remote: 'remote@MyDomain/module-a/static/mf-manifest.json',
},
});
```

## 本地验证部署

## 通过平台部署
Modern.js 提供了 `modern deploy` 命令,可以方便生成可运行在 Node.js 环境的产物。

上述部署方式只是最简单的实践,在真实场景还有很多限制,例如版本管理、发布时序等。在字节跳动内部,我们在部署平台上搭建了 Module Federation 应用的部署流程,可以帮助开发者解决这些问题。
```bash
modern deploy
```

执行命令后,可以在控制台看到以下输出:

```bash
Static directory: .output/static
You can preview this build by node .output/index
```

我们会持续关注社区里类似功能的平台,在未来完善 Modern.js + Module Federation 在这些类平台上的部署文档
此时,开发者只需要运行 `node .output/index` 即可在本地预览部署后的效果。无论是 CSR 应用或是 SSR 应用,所有的 Module Federation 产物都能够被正确的访问
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,6 @@ export default Index;
import { appTools, defineConfig } from '@modern-js/app-tools';
import { moduleFederationPlugin } from '@module-federation/modern-js';

const isLocal = process.env.IS_LOCAL === 'true';

// https://modernjs.dev/en/configure/app/usage
export default defineConfig({
server: {
Expand All @@ -203,7 +201,7 @@ export default defineConfig({
// Now this configuration is only used in the local when you run modern serve command.
// If you want to deploy the application to the platform, use your own domain name.
// Module federation will automatically write it to mf-manifest.json, which influences consumer to fetch remoteEntry.js.
assetPrefix: isLocal ? 'http://127.0.0.1:3051' : '/',
assetPrefix: 'http://127.0.0.1:3051',
},
plugins: [
appTools({
Expand All @@ -214,7 +212,7 @@ export default defineConfig({
});
```

现在,在生产者中运行 `IS_LOCAL=true modern build && modern serve`,在消费者中运行 `modern build && modern serve`,即可在本地模拟生产环境,访问到远程模块。
现在,在生产者中运行 `modern build && modern serve`,在消费者中运行 `modern build && modern serve`,即可在本地模拟生产环境,访问到远程模块。

上述用例可以参考:[Modern.js & Module Federation 基础用法示例](https://github.com/web-infra-dev/modern-js-examples/tree/main/examples/module-federation/base)。

Expand Down