微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。解耦团队之间的龚和渡,解耦技术栈的龚和渡,节省团队间沟通成本,解决技术栈之间无法业务打通的能力
微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用(Frontend Monolith)后,随之而来的应用不可维护的问题。这类问题在企业级 Web 应用中尤其常见。
* 主框架不限制接入应用的技术栈,微应用具备完全自主权
* 微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新
基于 single-spa 封装,提供了更加开箱即用的 API。
技术栈无关,任意技术栈的应用均可 使用/接入,不论是 React/Vue/Angular/JQuery 还是其他等框架。
HTML Entry 接入方式,让你接入微应用像使用 iframe 一样简单。
样式隔离,确保微应用之间样式互相不干扰。
JS 沙箱,确保微应用之间 全局变量/事件 不冲突。
⚡️ 资源预加载,在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度。
umi 插件,提供了 @umijs/plugin-qiankun 供 umi 应用一键切换成微前端架构系统。
Lerna 是一个管理工具,用于管理包含多个软件包(package)的 JavaScript 项目
npm
将 Lerna
安装到全局环境中npm i lerna -g
git
代码仓库git init lerna-qiankun && cd lerna-qiankun
Lerna
仓库
lerna init
lerna-qiankun/
packages/
package.json
lerna.json
packages
文件目录创建项目 main-qiankun
, one-qiankun
, tow-qiankun
, three-qiankun
create-react-app main-qiankun --template typescript
微前端主应用进入项目 cd main-qiankun
释放配置文件打开 one-qiankun
webpack配置,执行命令: npm eject
, 释放后根目录会生成 config
文件夹和 script
文件夹
安装react路由 npm install react-router-dom
创建三个路由页面 /
, /one
, /*
, 代码如下:
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import './App.css';
import Home from './pages/home'
import One from './pages/one';
import ErrorPage from './pages/404';
function App() {
return (
<div className="App">
乾坤主应用
<BrowserRouter basename=''>
<Routes >
<Route path="/" element={<Home></Home>} ></Route>
<Route path="/one" element={<One></One>} ></Route>
<Route path="/*" element={<ErrorPage></ErrorPage>} ></Route>
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
执行命令 npm i qiankun -S
安装 qiankun
在主应用中找到 one.tsx
添加 qiankun
依赖及启动生命周期,代码如下:
import React, { useEffect, useMemo, useState } from 'react'
import { Outlet } from 'react-router-dom'
import { useSearchParams } from 'react-router-dom'
import { start } from 'qiankun'
const One = () => {
// 启动微前端调用子应用模块
useEffect(() => {
start()
}, [])
return (<>
<div className="app-box" >
ONE !!!
</div>
<div>
<div id="one">
<div>此处是子应用渲染区域</div>
</div>
</div>
</>
)
}
export default One;
npm build
那到 build
文件夹部署代码到nginx指向服务器create-react-app one-qiankun --template typescript
微前端主应用进入项目 cd one-qiankun
释放配置文件打开 one-qiankun
webpack配置,执行命令: npm eject
, 释放后根目录会生成 config
文件夹和 script
文件夹, 找到 script
文件夹下面的 start.js
修改端口号 3000
改成 4000
安装react路由 npm install react-router-dom
创建三个路由页面 /dcw/
, /dcw/one
, /dcw/one-one
, /*
, 前缀 /dcw
代码如下:
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import './App.css'
import Home from './views/home'
import One from './views/one'
import Two from './views/two'
import ErrorPage from './views/404'
function App() {
return (
<div className="App">
乾坤子应用
<BrowserRouter basename='/dcw'>
<Routes >
<Route path="/" element={<Home></Home>} ></Route>
<Route path="/one" element={<One></One>} ></Route>
<Route path="/one-one" element={<Two></Two>} ></Route>
<Route path="/*" element={<ErrorPage></ErrorPage>} ></Route>
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
one-qiankun
的入口逻辑 index.tsx
代码如下:
import React from 'react'
import ReactDOM from 'react-dom/client'
// import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import reportWebVitals from './reportWebVitals'
console.log(window, 'window----')
// 此处是子应用独立访问渲染路由到 root div 标签下
if (!(window as any).__POWERED_BY_QIANKUN__) {
let root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
reportWebVitals();
}
// 此处是微前端主应用调用执行生命周期
export async function bootstrap() {
console.log('bootstrap-----')
}
// 微前端挂载dome 生命周期
export async function mount(props: any) {
console.log('one start')
// ReactDOM.render( , props.container ? props.container.querySelector('#one') : document.getElementById('root'));
let root = ReactDOM.createRoot(
document.getElementById('one') as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
reportWebVitals();
}
export async function unmount(props: any) {
console.log('unmount-----')
// ReactDOM.unmountComponentAtNode(
// props.container ? props.container.querySelector('#one') : document.getElementById('root'),
// );
}
export async function update(props: any) {
console.log('update-----')
console.log('update props', props)
}
webpack.config.js
// 打包出口处添加
output: {
library: `${packageName}-[name]`,
libraryTarget: 'umd',
npm build
那到 build
文件夹部署代码到nginx指向服务器server {
listen 8080;
server_name localhost;
charset utf-8;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#charset koi8-r;
#access_log logs/host.access.log main;
location /v2/ {
proxy_set_header Host 'dcw.com';
proxy_pass http://dcw.com;
proxy_read_timeout 10m;
}
location /boss/ {
proxy_set_header Host 'dcw.com';
proxy_pass http://dcw.com;
proxy_read_timeout 10m;
}
location / {
root /work/dist/build;
try_files $uri /index.html;
}
},
server {
listen 8081;
server_name localhost;
// 允许跨域
add_header 'Access-Control-Allow-Origin' *;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' *;
add_header 'Access-Control-Allow-Headers' *;
location / {
root /u/work/dist/oneqiankun/build;
try_files $uri /index.html;
}
}
localhost:8080
即可在主应用看到 localhost:8081
子应用的界面,如下图: