React&微前端&模块联盟概念讲解@react,webpack,微前端
微前端架构(micro frontends architecture)设计风格为应用程序的前端所做的,就像微服务为后端所做的那样,将整体结构分解成更小的组件,然后可以在单个页面上组装。
优点:
模块联盟允许一个JavaScript应用程序动态地从另一个应用程序加载代码,并在此过程中共享依赖关系。如果一个使用联盟模块的应用程序没有联盟代码所需的依赖,Webpack将从该联盟的构建源头下载缺少的依赖。
前提是确保你已经安装了最新的Node.js。对React.js和Webpack 5+有基本了解。
我将在本文中创建2个应用程序。第一个:容器应用,将被用作微前端的基础。第二:计数器应用,将在容器应用内被渲染。
让我们从设置环境开始,我使用create-mf-app来创建一个react应用。
在终端上运行以下npx命令,使用 "create-mf-app "安装和引导应用程序。
npx create-mf-app
完成第一步后,初始化后的目录是这样的
我不会深入讲解这个目录结构,因为它和create-react-app目录结构一样。
值得注意的是,这里的index.js文件是动态导入了一个App.js
import('./App')
接下来让我们快速开始初始化另一个叫做Counter的app,与创造Container app一样
npx create-mf-app
在这里,我在component目录下创建了一个Counter组件
src/components/Counter.jsx
import React, { useState } from "react";
export const Counter = () => {
const [count, setCount] = useState(0);
const onIncrement = () => setCount(count + 1);
const onDecrement = () => setCount(count - 1);
return (
<div>
<h1>Counter App</h1>
<p>Current count: <strong>{count}</strong></p>
<button onClick={onIncrement}>+</button>
<button onClick={onDecrement}>-</button>
</div>
);
}
让我们在Counter app里更新webpack.config.js文件,在plugins的数组里加入ModuleFederationPlugin插件。
webpack.config.js
const HtmlWebPackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const deps = require("./package.json").dependencies;
module.exports = {
output: {
publicPath: "http://localhost:8081/",
},
resolve: {
extensions: [".tsx", ".ts", ".jsx", ".js", ".json"],
},
devServer: {
port: 8081,
historyApiFallback: true,
},
module: {
rules: [
{
test: /\.m?js/,
type: "javascript/auto",
resolve: {
fullySpecified: false,
},
},
{
test: /\.(css|s[ac]ss)$/i,
use: ["style-loader", "css-loader", "postcss-loader"],
},
{
test: /\.(ts|tsx|js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
],
},
plugins: [ // This is important part
new ModuleFederationPlugin({
name: "counter",
filename: "remoteEntry.js",
remotes: {},
exposes: {
"./Counter": "./src/components/Counter",
},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
},
}),
new HtmlWebPackPlugin({
template: "./src/index.html",
}),
],
};
让我们来理解一下这个插件的配置项:
name:远程app的名称
filename:Counter app的入口点 (remoteEntry.js)。
remotes:在此处添加 remotes 项(与容器相关),必须定义从远程应用程序公开的所有入口点,远程入口结构为:{ “app-name”: “name@/remoteEntry.js” }
exposes:您要向容器应用程序公开的所有组件名称。
shared:容器所有要在容器和计数器应用程序之间共享的依赖项。
src/App.jsx
import React from "react";
import ReactDOM from "react-dom";
import { Counter } from 'counter/Counter';
import "./index.css";
const App = () => (
<div className="container">
<h1>Container App</h1>
<Counter /> // Micro frontend app
</div>
);
ReactDOM.render(<App />, document.getElementById("app"));