Webpack5模块联邦微前端方案实践
1.参考资料
2.Webpack5模块联邦
使用的webpack版本:5.76.2,webpack-cli版本:5.0.1,webapck-dev-server:4.13.1,使用的react版本:18.2.0。
webpack5:配置
new ModuleFederationPlugin(moduleSetting)
- 1.Module Federation(模块联邦):可以使JavaScript应用可以动态运行另一个JavaScript应用中的代码,同时可以共享依赖。
3.demo探索
1.先新建3个工程,主应用工程,嵌入的子应用工程app1和app2。
2.主应用配置
先搭建一个react项目,这里我不使用react的官方脚手架搭建
(1)先创建一个名叫主应用的文件夹。
(2)初始化 NPM 项目
npm init
这将创建一个 package.json
文件。
(3)安装 React 和 ReactDOM:
npm install react react-dom
(4)安装 Webpack、Babel 和相关依赖:
npm install --save-dev webpack webpack-cli webpack-dev-server babel-loader @babel/core @babel/preset-env @babel/preset-react html-webpack-plugin
(5)在项目根目录下创建一个 webpack.config.js
文件,配置如下:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
module.exports = {
entry: './src/index.js',
output: {
path: __dirname + '/dist',
filename: 'bundle.js',
},
devServer: {
static: {
directory: './dist',
},
port: 3000,
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
},
},
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
plugins: [
new ModuleFederationPlugin({
name: 'mainApp',
remotes: {
microApp1: 'microApp1@http://localhost:3002/remoteEntry.js',
// microApp2: 'microApp2@http://localhost:3003/remoteEntry.js',
},
}),
new HtmlWebpackPlugin({
template: './public/index.html',
}),
],
};
(6)在项目根目录下创建一个 .babelrc
文件,配置如下:
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
(7)创建项目的源代码结构:
在项目根目录下创建以下文件和文件夹:
mkdir public src
touch public/index.html src/index.js src/App.js
(8)编辑 public/index.html
文件,添加以下内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>主应用</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
(9)编辑 src/index.js
文件,添加以下内容:
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
const rootElement = document.getElementById('root');
createRoot(rootElement).render(<App />);
(10)编辑 src/App.js
文件,添加以下内容:
import React, { useState, lazy, Suspense } from 'react';
import './App.css';
const RemoteApp1 = lazy(() => import('microApp1/app'));
// const RemoteApp2 = lazy(() => import('App2/RemoteApp2'));
function App() {
const [activeApp, setActiveApp] = useState(null);
const handleClick = (app) => {
setActiveApp(app);
};
return (
<div>
<nav>
<ul>
<li><span onClick={() => handleClick('App1')}>子应用1</span></li>
<li><span>子应用2</span></li>
</ul>
</nav>
<div className="app-container">
<Suspense fallback={<div>Loading...</div>}>
{activeApp === 'App1' && <RemoteApp1 />}
{/* {activeApp === 'App2' && <RemoteApp2 />} */}
</Suspense>
</div>
</div>
);
}
export default App;
(11)新建一个 src/App.css
文件,添加以下内容:
nav {
display: flex;
justify-content: center;
}
ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
}
li {
margin: 0 10px;
height: 24px;
background: #ff5c35;
border-radius: 5px;
}
span {
color: #333;
text-decoration: none;
font-size: 18px;
padding: 10px;
border-bottom: 2px solid transparent;
transition: all 0.3s ease;
cursor: pointer;
}
span:hover {
border-bottom: 2px solid #333;
}
(12)更新 package.json
文件,添加以下脚本:
"scripts": {
"start": "webpack serve --mode development --open",
"build": "webpack --mode production"
}
(13)启动开发服务器:
npm start
启动起来在浏览器上看见子应用1和子应用2的按钮那么项目就搭建成功了。
3.子应用配置
(1)跟主应用一样,也是不使用react的官方脚手架搭一个简单的react项目
搭建方式跟上面的主应用相同,不过需要改几个文件的内容。
按上面的步骤又搭建起一个工程后。
将public/index.html中的内容替换掉:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>子应用1</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
将src/App.js中的内容替换掉:
import React from 'react';
function App() {
return <h1>Hello, 子应用1!</h1>;
}
export default App;
将src/webpack.config.js中的内容替换掉:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
module.exports = {
entry: './src/index.js',
output: {
path: __dirname + '/dist',
filename: 'bundle.js',
},
devServer: {
static: {
directory: './dist',
},
port: 3002,
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
},
},
},
],
},
plugins: [
new ModuleFederationPlugin({
name: 'microApp1',
filename: 'remoteEntry.js',
exposes: {
'./app': './src/App'
},
// shared: {
// react: { singleton: true },
// 'react-dom': { singleton: true }
// },
}),
new HtmlWebpackPlugin({
template: './public/index.html',
}),
],
};
将两个工程都运行起来,你点击应用1按钮就会发现,子应用已经集成到主应用里面了。
转载自:https://juejin.cn/post/7258119819383734331