logologo
指南
实践
配置
插件
案例
博客
生态
Module Federation Examples
Practical Module Federation
Zephyr Cloud
Nx
简体中文
English
指南
实践
配置
插件
案例
博客
Module Federation Examples
Practical Module Federation
Zephyr Cloud
Nx
简体中文
English
logologo
概览

Bridge

Bridge 介绍

React Bridge

快速开始
导出应用
加载应用
加载模块
Vue Bridge

框架

框架概览

React

Basic CRA with Rsbuild
国际化 (i18n)

Modern.js

快速开始
动态加载生产者

Next.js

Basic Example
导入组件
路由和导入页面
使用 Express.js
预设

Angular

Angular CLI 设置
Micro-frontends with Angular
服务端渲染
使用 Service Workers
Authentication with Auth0
Authentication with Okta
拆分巨石应用
改造巨石应用
Edit this page on GitHub
Previous Page国际化 (i18n)
Next Page动态加载生产者

#Modern.js

TIP
  • 示例 Demo Modern.js SSR

#环境准备

#Node.js

在开始使用前,你需要安装 Node.js,并保证 Node.js 版本不低于 16.2.0,我们推荐使用 Node.js 18 的 LTS 版本。

你可以通过以下命令检查当前使用的 Node.js 版本:

node -v

如果你当前的环境中尚未安装 Node.js,或是安装的版本低于 16,可以通过 nvm 或 fnm 安装需要的版本。

下面是通过 nvm 安装 Node.js 18 LTS 版本的例子:

# 安装 Node.js 18 的长期支持版本
nvm install 18 --lts

# 将刚安装的 Node.js 18 设置为默认版本
nvm alias default 18

# 切换到刚安装的 Node.js 18
nvm use 18
nvm 和 fnm

nvm 和 fnm 都是 Node.js 版本管理工具。相对来说,nvm 较为成熟和稳定,而 fnm 是使用 Rust 实现的,比 nvm 提供了更好的性能。

此外,在安装 nvm 或 fnm 后,然后只要仓库根目录下有内容为 lts/hydrogen 的 .nvmrc 文件,进入这个仓库时就会自动安装或切换到正确的 Node.js 版本。

#pnpm

推荐使用 pnpm 来管理依赖:

npm install -g pnpm@8
NOTE

Modern.js 同样支持使用 yarn、npm 进行依赖管理。

#创建项目

Modern.js 提供了 @modern-js/create 工具来创建项目,不需要全局安装,直接使用 npx 按需运行即可。

#创建消费者

npx @modern-js/create@latest modern-consumer

#创建生产者

npx @modern-js/create@latest modern-provider

#安装插件

Module Federation 为 Modern.js 提供了 配套的插件 @module-federation/modern-js。

pnpm add @module-federation/modern-js

#设置模块联邦配置

#生产者

#1. 创建配置文件

在项目根目录创建 module-federation.config.ts 文件,并写入下列内容:

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

export default createModuleFederationConfig({
  name: 'provider',
  filename: 'remoteEntry.js',
  exposes: {
    './Image': './src/components/Image.tsx',
  },
  shared: {
    react: { singleton: true },
    'react-dom': { singleton: true },
  },
});

#2. 应用插件

在 modern.config.ts 应用 @module-federation/modern-js:

modern.config.ts
import { appTools, defineConfig } from '@modern-js/app-tools';
import { moduleFederationPlugin } from '@module-federation/modern-js';

// https://modernjs.dev/en/configure/app/usage
export default defineConfig({
  runtime: {
    router: true,
  },
  server: {
    ssr: {
      mode: 'stream',
    },
    port: 3006,
  },
  plugins: [appTools(), moduleFederationPlugin()],
});

#3. 创建导出组件

创建文件 src/components/Image.tsx ,内容如下:

Image.tsx
import React from 'react';
import styles from './Image.module.css';

export default (): JSX.Element => (
  <div
    id="remote-components"
    style={{
      backgroundColor: '#1ee9c1',
      color: 'lightgrey',
      padding: '1rem',
    }}
  >
    <h2>
      <strong>remote</strong>&nbsp;image
    </h2>
    <button
      id="remote-components-button"
      style={{ marginBottom: '1rem' }}
      onClick={() => alert('[remote-components] Client side Javascript works!')}
    >
      Click me to test i'm interactive!
    </button>
    <img
      id="remote-components-image"
      src="https://module-federation.io/module-federation-logo.svg"
      style={{ width: '100px' }}
      alt="serge"
    />
    <button className={styles['button']}>Button from remote</button>
  </div>
);

并创建对应的样式文件,内容如下:

Image.module.css
.button {
  background: red;
}

#消费者

#1. 创建配置文件

在项目根目录创建 module-federation.config.ts 文件,并写入下列内容:

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

export default createModuleFederationConfig({
  name: 'consumer',
  remotes: {
    remote: 'provider@http://localhost:3006/mf-manifest.json',
  },
  shared: {
    react: { singleton: true },
    'react-dom': { singleton: true },
  },
});

#2. 应用插件

在 modern.config.ts 应用 @module-federation/modern-js:

modern.config.ts
import { appTools, defineConfig } from '@modern-js/app-tools';
import { moduleFederationPlugin } from '@module-federation/modern-js';

// https://modernjs.dev/en/configure/app/usage
export default defineConfig({
  runtime: {
    router: true,
  },
  server: {
    ssr: {
      mode: 'stream',
    },
    port: 3007,
  },
  plugins: [appTools(), moduleFederationPlugin()],
});

#3. 引用类型

在 tsconfig.json 添加 paths 以获取生产者的类型:

{
  "compilerOptions": {
    "paths": {
      "*": ["./@mf-types/*"]
    }
  }
}

#4. 消费生产者

修改入口页面(src/routes/page.tsx),引用生产者提供的组件,内容如下:

page.tsx
import ProviderImage from 'remote/Image';
import './index.css';

const Index = () => (
  <div className="container-box">
    <ProviderImage />
  </div>
);

export default Index;

#CSS 闪烁问题

启动项目访问 http://localhost:3007/,发现SSR 正常工作,页面可以正常渲染,但是会有样式闪烁的问题。

这是因为生产者的样式文件无法注入到对应的 html 中。

此问题可以通过使用 @module-federation/modern-js 提供的 createremotessrcomponent 解决。

修改消费者引用生产者处的代码(src/routes/page.tsx):

page.tsx
import { getInstance } from '@module-federation/modern-js/runtime';
import { createLazyComponent } from '@module-federation/modern-js/react'
import './index.css';

const RemoteSSRComponent = createLazyComponent({
  instance: getInstance(),
  loader: () => import('remote/Image'),
  loading: 'loading...',
  export: 'default',
  fallback: ({ error }) => {
    if (error instanceof Error && error.message.includes('not exist')) {
      return <div>fallback - not existed id</div>;
    }
    return <div>fallback</div>;
  },
});

const Index = () => (
  <div className="container-box">
    <RemoteSSRComponent />
  </div>
);

export default Index;

修改后重新访问页面,可以观测返回的 html 中会自动注入生产者的样式文件,从而解决 CSS 闪烁问题。