Modern.js
  环境准备
 Node.js
 在开始使用前,你需要安装 Node.js,并保证 Node.js 版本不低于 16.2.0,我们推荐使用 Node.js 18 的 LTS 版本。
 你可以通过以下命令检查当前使用的 Node.js 版本:
  如果你当前的环境中尚未安装 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 来管理依赖:
  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> 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 闪烁问题。