webpack5新增的ModuleFederationPlugin
- 一种解决微前端的解决方案,
- 共用组件升级时,避免所有依赖项目都要进行升级的痛点
remote远程组件
该项目代表的是被远程引用的共用组件库
安装项目依赖
// webpack相关
yarn add webpack webpack-cli webpack-dev-server html-webpack-plugin -D
// 框架类相关
yarn add react react-dom babel-loader @babel/core @babel/preset-react -D
设置webpack.config.js
const path = require("path");
const webpack = require("webpack");
const htmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
publicPath: "http://localhost:3000/",
},
devtool: false,
devServer: {
port: 3000,
},
module: {
rules: [
{
test: /\.jsx?$/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-react"],
},
},
exclude: /node_modules/,
},
],
},
plugins: [
new htmlWebpackPlugin({
template: "./public/index.html",
}),
// 定义被引用时的名称,引入路径 ${name}/${exposes} -> remote/NewList
new ModuleFederationPlugin({
name: "remote",
filename: "remoteEntry.js",
// 提供组件时:exposes
exposes: {
"./NewList": "./src/NewList",
},
// 性能优化
shared: {
react: { singleton: true },
"react-dom": { singleton: true },
},
}),
],
};
组件中目录代码
├── package.json
├── public
│ └── index.html
├── src
│ ├── App.js
│ ├── NewList.js
│ ├── bootstrap.js
│ └── index.js
├── webpack.config.js
package.json
"scripts": {
"start": "webpack serve",
"build": "webpack"
},
index.js
import "./bootstrap";
App.js
import React from "react";
import NewList from "./NewList";
export default (props) => {
return (
<div>
<h1>App</h1>
<hr />
<h3>list</h3>
<NewList
list={[
{ id: 1, name: "js" },
{ id: 2, name: "webpack" },
]}
/>
</div>
);
};
bootstrap.js
import React from "react";
import { createRoot } from 'react-dom/client';
import App from "./App";
const root = createRoot(document.getElementById("app"));
root.render(<App />);
NewList.js
import React from "react";
export default (props) => {
return (
<ol>{props.list && props.list.map((l) => <li key={l.id}>{l.name}</li>)}</ol>
);
};
生成了remoteEntry.js
启动项目是会发现生成了remoteEntry.js文件,该文件就是供其它项目引入插件时使用。
该文件会提供组件的入口链接。
host项目
安装项目依赖
// webpack相关
yarn add webpack webpack-cli webpack-dev-server html-webpack-plugin -D
// 框架类相关
yarn add react react-dom babel-loader @babel/core @babel/preset-react -D
设置webpack.config.js
const path = require("path");
const webpack = require("webpack");
const htmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
publicPath: "http://localhost:8000/",
},
devServer: {
port: 8000,
},
module: {
rules: [
{
test: /\.jsx?$/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-react"],
},
},
exclude: /node_modules/,
},
],
},
plugins: [
new htmlWebpackPlugin({
template: "./public/index.html",
}),
new ModuleFederationPlugin({
name: "host",
//使用的时:为remotes
remotes: {
remote: "remote@http://localhost:3000/remoteEntry.js",
}
}),
],
};
本地项目中目录结构
.
├── package.json
├── public
│ └── index.html
├── src
│ ├── App.js
│ ├── bootstrap.js
│ └── index.js
└── webpack.config.js
index.js
import "./bootstrap";
bootstrap.js
import React from "react";
import { createRoot } from 'react-dom/client';
import App from "./App";
const root = createRoot(document.getElementById("app"));
root.render(<App />);
App.js
import React from "react";
// import 远程组件
const RemoteNewList = React.lazy(() => import("remote/NewList"));
export default (props) => {
return (
<div>
<h1>Remote List</h1>
<React.Suspense fallback="loading">
<RemoteNewList list={[
{ id: 1, name: "remote js" },
{ id: 2, name: "remote webpack" },
]} />
</React.Suspense>
</div>
);
};