webpack 模块联邦

1、基础配置

前提概述

模块联邦可以将多个独立运行的项目产生依赖关系,以下创建两个项目,让A项目依赖B项目的一个组件。(前三步两个项目配置相同)

(1)、安装webpack环境
npm init -y
npm i webpack webpack-cli webpack-dev-server html-webpack-plugin -D
(2)、创建入口文件

在根目录下创建 /src/index.js

(3)、配置webpack

在根目录下创建webpack.config.js

// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  plugins: [
    new HtmlWebpackPlugin()
  ]
}

(4)、准备B项目资源

在package.json中配置启动脚本:

"scripts": {
  "dev": "webpack-dev-server --port 3001",
  ...
},

在src下创建一个文件导出资源 命名为createHeader.js

export default () => {
  const header = document.createElement('header')
  header.innerText = 'header'
  return header
}

修改webpack.config.js文件

const HtmlWebpackPlugin = require('html-webpack-plugin')
const { ModuleFederationPlugin } = require('webpack').container

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  plugins: [
    new HtmlWebpackPlugin(),
    new ModuleFederationPlugin({
      name: 'header', // 项目名称
      filename: 'header.js', // 请求该项目暴露的依赖入口
      remotes: {}, // 该项目需要远程依赖的配置
      exposes: {
        // 该项目暴露的依赖, 将刚刚写的createHeader.js暴露出去,外部访问路径为./createHeader
        './createHeader': './src/createHeader.js' 
      },
      shared: {} // 改项目分享的公共模块
    })
  ]
}

启动B项目

npm run dev
(5)、配置A项目

在package.json中配置启动脚本:

"scripts": {
  "dev": "webpack-dev-server --port 3000",
  ...
},

修改webpack.config.js文件

const HtmlWebpackPlugin = require('html-webpack-plugin')
const { ModuleFederationPlugin } = require('webpack').container

module.exports = {
  mode: 'development',
  entry: './src/index.js'
  plugins: [
    new HtmlWebpackPlugin(),
    new ModuleFederationPlugin({
      name: 'main',
      filename: 'main.js',
      remotes: {
        // 配置依赖的模块将其命名为本项目的header模块,header(B项目的名称)@http://localhost:3001(B项目的host)/header.js(B项目的依赖入口)
        'header': 'header@http://localhost:3001/header.js'
      },
      exposes: {},
      shared: {}
    })
  ]
}

在index.js中使用

;(async () => {
  // 引用远程依赖的模块,由于远程加载需要异步方式获取 header(本项目的命名的模块名称)/createHeader (B项目暴露的外部访问路径)
  const {default: createHeader} = await import('header/createHeader')

  document.body.appendChild(createHeader())
})()

启动A项目 访问http://localhost:3000 即可看到header被引入了

npm run dev

2、react配置

前提概述

以下创建两个react项目,让A项目依赖B项目的一个组件。(第一步两个项目配置相同)

(1)、使用react脚手架搭建两个react项目

以A项目为例

npx create-react-app A
cd A
// 拉取配置文件
npm run eject
(2)、准备B项目资源

在scr/components下创建一个组件button.jsx

const Button = ({ children }) => {
  return (
    <button className="test-btn1">{children}</button>
  )
}

export default Button

修改项目启动的端口 script/start.js 修改启动端口为3001

// const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3001;

修改config/webpack.config.js文件 加入模块联邦插件,并将定义好的button组件暴露出去

...
const { ModuleFederationPlugin } = require('webpack').container;
...
plugins: [
  ...
  output: {
  	...
  	publicPath: process.env.NODE_ENV === 'development' ? 'http://localhost:3001/' : 'http://production.com/', // 必须要配置publicPath,否则请求的路径不对,找不到资源
  	...
  }
  ...
  new ModuleFederationPlugin({
    name: 'component',
    filename: 'component.js',
    remotes: {},
    exposes: {
      './Button': './src/components/button.jsx'
    },
  }),
  ....
]

启动项目

npm start
(3)、配置A项目

修改config/webpack.config.js文件 加入模块联邦插件,配置好依赖

...
const { ModuleFederationPlugin } = require('webpack').container;
...
plugins: [
  ...
  new ModuleFederationPlugin({
    name: 'main',
    filename: 'main.js',
    remotes: {
      'component': 'component@http://localhost:3001/component.js'
    },
    exposes: {},
    shared: {}
  }),
  ....
]

在需要使用的地方直接调用,由于是远程加载所以需要用异步方式

import React, { Suspense } from 'react'
const Button = React.lazy(() => import('component/Button'))

function App() {
  return (
    <div className="App">
      app
      <Suspense fallback="loading">
        <Button>app button</Button>
      </Suspense>
    </div>
  );
}

export default App;

启动项目

npm run start

3、总结

模块联邦可以实现微前端,独立打包部署每一个应用,其原理是将公共文件单独打包成一个js,在引用的地方直接用js标签请求即可,但无法支持seo。

posted @ 2022-02-21 09:45  如戏一场  阅读(531)  评论(0编辑  收藏  举报