1、什么是微前端
微前端是一种前端架构模式 ,核心思想是------把后端微服务的理念搬到前端:将一个庞大的"巨石单体应用"拆成多个独立开发、独立构建、独立部署、运行时聚合 的小型前端应用(子应用/微应用),再由一个**主应用(基座/Shel)**负责统一加载和组合。
特点就是:微前端并不微,可以使用多个技术栈,独立开发部署
2、创建项目

1、main-app
使用vue3 作为基座,
pnpm create vue@latest

一步步往下走
2、app1
react 作为子应用
npx create-react-app app1
一步步往下走
3、app2
vue3+vuecil作为子应用
vue create app2
使用上面的命令一步步往下走
好了 一个主应用+两个子应用 创建完成
接下来配置main-app 主应用


主应用先装个qiankun框架
pnpm add qiankun
先建个index.js
javascript
export default {
microApp: [
{
name: 'app1',
entry: '//127.0.0.1:8002',
activeRule: '/app-react',
container: '#container',
props: { parent: 'base' },
},
{
name: 'app2',
entry: '//127.0.0.1:8003',
activeRule: '/app-vue',
container: '#container',
props: {},
},
],
}

#container 是需要显示的容器id
/app-vue 是地址栏的路由路径
接下来编写app.vue
javascript
<script setup>
import { RouterLink, RouterView } from 'vue-router'
import { registerMicroApps, start, addGlobalUncaughtErrorHandler } from "qiankun";
import config from "./index";
const { microApp } = config;
// 初始化乾坤
const initQiankun = () => {
if (microApp.length) {
registerMicroApps(microApp, {
beforeLoad(app) {
console.log("app=>", app);
},
beforeMount: [() => console.log('before mount')],
afterMount: () => console.log('****afterMount*****'),
beforeUnmount: () => console.log('****beforeUnmount *****'),
afterUnmount: () => console.log('-------afterUnmount *********---')
});
}
};
if (!window.qiankunStarted) {
window.qiankunStarted = true;
initQiankun();
start({
sandbox: {
experimentalStyleIsolation: true, // 样式隔离
},
});
}
// 全局的未捕获异常处理器
addGlobalUncaughtErrorHandler(event => {
console.log('异常=>', event)
})
</script>
<template>
<div>
<nav>
<RouterLink to="/">首页</RouterLink> |
<RouterLink to="/about">关于</RouterLink>
</nav>
<RouterView />
<div id="container"></div>
</div>
</template>
<style scoped>
nav {
padding: 20px;
}
nav a {
color: #42b883;
text-decoration: none;
}
nav a.router-link-active {
font-weight: bold;
}
</style>
registerMicroApps 这个方法重要,需要注册一下你的子应用
然后配置app1
app1是react 项目

需要有个注意点
qiankun 必须通过 UMD + 全局变量,才能"拿到"你的子应用并调用它的生命周期。
app1 的package.json 配置

修改下端口是8002 启动
使用react-app-rewired 进行webpack5改写
之后新建下config-overrides.js这个文件
javascript
const { name } = require('./package.json')
module.exports = {
webpack: (config) => {
config.output.library = `${name}-[name]`
config.output.libraryTarget = 'umd'
config.output.globalObject = 'window'
// ✅ webpack 5 专用
config.output.chunkLoadingGlobal = `webpackJsonp_${name}`
return config
},
devServer: (configFunction) => {
return (proxy, allowedHost) => {
const devConfig = configFunction(proxy, allowedHost)
devConfig.headers = {
'Access-Control-Allow-Origin': '*',
}
devConfig.historyApiFallback = true
return devConfig
}
},
}

让qiankun框架可以进行跨域拉取app1这个应用的资源,不配置浏览器会拦截掉
然后新建一下public-path.js这样一个文件
javascript
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
写这一段让主应用可以访问到子应用的资源文件比如图片,视频什么的
不写的话
http://localhost:3001/static/js/main.xxx.jpg 这个会拿不到
然后修改index.js
javascript
import './public-path.js'
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
let root = null
async function render(props) {
const {container} = props
root = root || ReactDOM.createRoot(
container ? container.querySelector('#root'):document.getElementById('root')
)
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
}
// const root = ReactDOM.createRoot(document.getElementById('root'));
if(!window.__POWERED_BY_QIANKUN__){
render({})
}
export async function bootstrap() {
console.log('[app2] bootstrap')
}
export async function mount(props) {
console.log('[app2] mount', props)
render(props)
}
export async function unmount() {
console.log('[app2] unmount')
if (root) {
root.unmount()
root = null
}
}
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

这个导入一下重要,需要让上面的写法生效

这三个是qiankun的生命周期,后续需要和主应用通信什么的的可以用到
好了
接下来配置app2 子应用

app2是一个vue3项目
首先对vue.config.js 配置下
javascript
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
port: 8003,
headers: {
'Access-Control-Allow-Origin': '*',
},
},
configureWebpack: {
output: {
library: 'app2',
libraryTarget: 'umd',
chunkLoadingGlobal: 'webpackJsonp-app2',
},
},
})
端口改8003 使用umd输出
然后就是main.js 配置
javascript
import { createApp } from 'vue'
import App from './App.vue'
let app = null
function render(props = {}) {
const { container } = props
app = createApp(App)
app.mount(container ? container.querySelector('#app') : '#app')
}
if (!window.__POWERED_BY_QIANKUN__) {
render({})
}
export async function bootstrap() {
console.log('[app2] bootstrap')
}
export async function mount(props) {
console.log('[app2] mount', props)
render(props)
}
export async function unmount() {
console.log('[app2] unmount')
if (app) {
app.unmount()
app = null
}
}
最后就是进入 main-app
pnpm dev
启动应用
进入app1和app2 启动应用
效果如下
