Skip to content

模块联邦技术

1. 概述

模块联邦技术是webpack5新增的功能,可以 实现多个应用之间的模块共享,提高代码复用率,减少代码冗余。

js
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin')

不太像微前端,微前端是将多个应用拆分成多个子应用,每个子应用都是独立的应用,可以独立部署,独立开发,独立运行。

模块联邦是将多个应用拆分成多个模块,每个模块都是独立的,可以独立开发,独立运行,但是这些模块可以共享代码。

emp2.0是基于模块联邦技术实现的,emp2.0是一个基于webpack5的微前端解决方案。 emp2

2. 使用

bash
host
  bootstrap.js
  index.html
  index.js
  webpack.config.js
  package.json
remote
  bootstrap.js
  index.html
  index.js
  webpack.config.js
  package.json
  list.js # 共享模块

核心代码,主要是使用webpack5 的 ModuleFederationPlugin 插件

提供方

js
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin')

new ModuleFederationPlugin({
  name: 'remote', //name必填
  filename: 'remoteEntry.js', //filename必填 生成的文件名
  exposes: {
    './addList': './list.js', //暴露的模块
  },
}),

使用方

js
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin')

new ModuleFederationPlugin({
  name: 'host', //name必填
  filename: 'hostEntry.js', //filename必填 生成的文件名
  //对应关系remote对应的remote项目ModuleFederationPlugin的name 后面url对应的port以及对应ModuleFederationPlugin的filename
  remotes: {
    remote: 'remote@http://localhost:9001/remoteEntry.js', //引入模块
  },
}),

打包的时候会通过cdn的方式加载远程的模块,然后在本地使用。

remote 模块暴露方

bootstrap.js

js
import { addList } from './list'

addList()
const app = document.getElementById('app')

app.innerHTML = `remote`

index.html

html
<body>
  <div id="app"></div>
</body>

index.js

js
import('./bootstrap')

list.js 暴露出去的模块

js
// 这个模块会暴露给 host 项目 去使用

const wrap = document.createElement('div')

const list = [
  { name: '张三', age: 18 },
  { name: '李四', age: 19 },
  { name: '王五', age: 20 },
  { name: '赵六', age: 21 },
  { name: '孙七', age: 22 },
]

list.forEach((item) => {
  const p = document.createElement('p')
  p.innerHTML = `姓名:${item.name} 年龄:${item.age}`
  wrap.appendChild(p)
})

export const addList = () => {
  document.body.appendChild(wrap)
}

webpack.config.js

js
const { Configuration } = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin')
/**
 * @type {Configuration} //配置智能提示
 */
const config = {
  mode: 'none',
  entry: './index.js',
  output: {
    filename: 'bundle.js',
  },
  devServer: {
    port: 9001, //remote 9001
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './index.html',
    }),
    new ModuleFederationPlugin({
      name: 'remote', //name必填
      filename: 'remoteEntry.js', //filename必填 生成的文件名  http://localhost:9001/remoteEntry.js 是可以直接访问到暴露的模块的
      exposes: {
        './addList': './list.js', //暴露的模块
      },
    }),
  ],
}

module.exports = config

package.json

json
{
  "name": "remote",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "webpack-dev-server",
    "build": "webpack"
  },
  "devDependencies": {
    "webpack": "^5.92.0",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^5.0.4",
    "html-webpack-plugin": "^5.6.0"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

host 模块使用方

bootstrap.js

js
import('remote/addList').then(({ addList }) => {
  const app = document.getElementById('app')

  app.innerHTML = `host`
  addList()
})

index.html

html
<div id="app"></div>

index.js

js
import('./bootstrap')

webpack.config.js

js
const { Configuration } = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin')
/**
 * @type {Configuration} //配置智能提示
 */
const config = {
  mode: 'none',
  entry: './index.js',
  output: {
    filename: 'bundle.js',
  },
  devServer: {
    port: 9002, // host 9002
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './index.html',
    }),
    new ModuleFederationPlugin({
      name: 'host', //name必填
      filename: 'hostEntry.js', //filename必填 生成的文件名
      //对应关系remote对应的remote项目ModuleFederationPlugin的name 后面url对应的port以及对应ModuleFederationPlugin的filename
      remotes: {
        remote: 'remote@http://localhost:9001/remoteEntry.js', //引入模块
      },
    }),
  ],
}

module.exports = config

package.json

json
{
  "name": "host",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "webpack-dev-server",
    "build": "webpack"
  },
  "devDependencies": {
    "webpack": "^5.92.0",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^5.0.4",
    "html-webpack-plugin": "^5.6.0"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}