1,微前端的理解
个人理解,我们写过很多项目,可能下一个项目会用到上一个项目的东西,而上一个项目和现在项目用到的框架不一样,比如上一个项目用的vue框架,现在的项目用的react开发。如果现在的项目想集成上个项目的内容,重新开发就很浪费资源。而微前端能解决这个问题。
2,umijs/plugin-qiankun 搭建项目
官方文档地址
3,准备工作
- 我的主应用采用的umi进行搭建,采用内置插件的layout
- 搭建了3个子应用,2个umi搭建的子应用,一个vue搭建的子应用 umi官方地址
4,项目框架图片
主应用-- umi
子应用1 --umi
子应用2 -- vue
5,项目配置
一: 主应用配置
package.json 配置插件版本
umi ^3.5.23
umijs/plugin-qiankun ^2.37.2
注意:主应用和子应用都要下载插件才能进行通信
npm i @umijs/plugin-qiankun -D 或者 yarn add @umijs/plugin-qiankun -D
- 在.umirc.ts文件夹中进行配置
import { defineConfig } from 'umi';
export default defineConfig({
title: 'qiankun-demo',
// favicon: '../src/public/qiankun.png', // 修改浏览器上的icon,相对路径不成功
favicon: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202012%2F04%2F20201204182229_e1a0a.thumb.1000_0.jpeg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1653034439&t=1a24e65fd2a3d82a7390ca82cfad6041', // 修改浏览器上的icon
nodeModulesTransform: {
type: 'none',
},
// 内置 antd,目前内置版本是 ^4.0.0
antd: {
// dark: true,
compact: true,
},
layout: {
name: '乾坤微应用demo', //产品名称
locale: false, //是否开启国际化,开启后路由配置的菜单名会被当做菜单名国际化的key
// logo: '../src/public/qiankun.png',//相对路径不成功
logo:'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202012%2F04%2F20201204182229_e1a0a.thumb.1000_0.jpeg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1653034439&t=1a24e65fd2a3d82a7390ca82cfad6041'
},
routes: [
{ path: '/', component: '@/pages/index' },
// { path: '/login', component: '@/pages/Login/index'},
{
path: '/dashboard',
name: '显示方式',
icon: 'dashboard',
routes: [
{
path: '/dashboard/analysis',
icon: 'AreaChartOutlined',
name: '微应用直接显示',
component: '@/pages/Dashboard/Analysis',
// 微应用直接显示
microApp: 'app2'
},
{
path: '/dashboard/monitor',
icon: 'DesktopOutlined',
name: '主应用中嵌套MicroApp',
// 在主应用中嵌套MicroApp
component: '@/pages/Dashboard/Monitor',
// microApp: 'app1'
},
],
},
{
path: '/app1',
name: 'App1-umi子应用',
icon: 'RadarChartOutlined',
microApp: 'app1',
access: 'canReadFoo', // 权限定义返回值的某个 key
// 设置加载动画
// microAppProps: {
// autoSetLoading: true,
// // className: 'myContainer',
// // wrapperClassName: 'myWrapper',
// },
props: {
onClick: (event:number) => console.log(event),
name: 'App1-umi子应用props',
age: 1,
},
},
{
path: '/app2',
name: 'APP2-umi子应用',
icon: 'AreaChartOutlined',
microApp: 'app2',
// microAppProps: {
// autoSetLoading: true,
// // className: 'myContainer',
// // wrapperClassName: 'myWrapper',
// },
props: {
onClick: (event:any) => console.log(event),
name: 'name: App2-umi子应用props',
age: 1,
},
},
{
path: '/app-vue',
name: 'vue子应用',
// 只在vue项目里面出现加载动画?
// microAppProps: {
// autoSetLoading: true,
// className: 'myContainer',
// wrapperClassName: 'myWrapper',
// },
icon: 'DotChartOutlined',
microApp: 'qiankun-vue',
props: {
onClick: (event:any) => console.log(event),
name: 'name: vue子应用props',
age: 1,
},
},
{
path: '/vue-ayp',
name: 'anyapeng',
icon: 'smile',
microApp: 'vue-ayp',
props: {
onClick: (event:any) => console.log(event),
name: 'vue-ayp子应用props',
age: 1,
},
},
],
// Umi 内置了以下别名:
// @,项目 src 目录
// @@,临时目录,通常是 src/.umi 目录
// umi,当前所运行的 umi 仓库目录
// react-router 和 react-router-dom,底层路由库,锁定版本,打包时所有依赖了他们的地方使用同一个版本
// react 和 react-dom,默认使用 16.x 版本,但如果项目里有依赖,会优先使用项目中依赖的版本
fastRefresh: {},//快速刷新(Fast Refresh),开发时可以保持组件状态,同时编辑提供即时反馈。
qiankun: {
master: {
// 注册子应用信息
apps: [
{
name: 'app1', // 唯一 id
entry: '//localhost:8001', // html entry
},
{
name: 'app2', // 唯一 id
entry: '//localhost:8002', // html entry
},
{
name: 'qiankun-vue', // 唯一 id
entry: '//localhost:8888', // html entry
},
{
name: 'vue-ayp', // 唯一 id
entry: '//localhost:10000/', // html entry
},
// {
// name: '/app-react', // 唯一 id
// entry: '//localhost:8899', // html entry
// },
],
},
},
});
- app.ts进行配置(主应用进行配置 可以将参数传递给子应用,进行通信)
// 运行时配置文件,可以在这里扩展运行时的能力,比如修改路由、修改 render 方法等。
import {useState} from 'react'
export function useQiankunStateForSlave() {
const [Number, setNumber] = useState({});
return {
Number,
setNumber,
};
}
二,子应用配置
- .umi搭建的子应用
1.1. umi搭建的子应用配置,插件下载;注意:主应用和子应用都要下载插件才能进行通信
npm i @umijs/plugin-qiankun -D 或者 yarn add @umijs/plugin-qiankun -D
我的这个版本的umi搭建的项目没有app.ts,所以需要在项目的根目录建一个app.ts文件,暴露出来qiankun这个对象;
export const qiankun = {
// 应用加载之前
async bootstrap(props:object) {
console.log('app1-umi子应用bootstrap1111',props);
},
// 应用 render 之前触发
async mount(props:object) {
console.log('app1-umi子应用mount1111',props);
},
// 应用卸载之后触发
async unmount(props:object) {
console.log('app1-umi子应用卸载11111',props);
},
};
1.2. 确定端口,根目录没有 .env 文件的,建立一个.env文件设置一下端口,主应用根据端口匹配到页面,例如:
PORT=8001
1.3. 配置 .umirc.ts
import { defineConfig } from 'umi';
export default defineConfig({
nodeModulesTransform: {
type: 'none',
},
routes: [
{ path: '/', component: '@/pages/index' },
{
path: '/app1/app2',
name: 'vue',
icon: 'DotChartOutlined',
microApp: 'app2'
},
],
fastRefresh: {},
// 在这里注册乾坤注册(config.js)直接在config.js这里面写没有作用
// qiankun: { slave: {} }, 这个必须要写,不然子应用链接不上主应用
qiankun: {
slave: {},
master: {
// 注册子应用信息
apps: [
{
name: 'app2', // 唯一 id
entry: '//localhost:8002', // html entry
},
],
},
},
});
- vue搭建子应用 2.1 下载插件
npm i @umijs/plugin-qiankun -D 或者 yarn add @umijs/plugin-qiankun -D
2.2 配置 .env文件
PORT = 8888
2.2 配置config.vue.js
const { name } = require('./package');
const path = require('path')
module.exports = {
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
},
},
configureWebpack: {
// 设置别名
resolve: {
alias: {
"@": path.resolve(__dirname, "src"),
},
},
output: {
// 微应用的包名,这里与主应用中注册的微应用名称一致
library: `${name}-[name]`,
// 将你的 library 暴露为所有的模块定义下都可运行的方式
libraryTarget: 'umd',
// 按需加载相关,设置为 webpackJsonp_MicroAppPlugin 即可
jsonpFunction: `webpackJsonp_vue`,
},
},
};
2.4 配置 main.js
import Vue from 'vue'
import VueRouter from 'vue-router';
import routes from './router.js';
console.log(routes,'routes')
// import store from './store';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue'
// import * as PublicPath from './public-path'
Vue.use(ElementUI);
Vue.use(VueRouter)
Vue.config.productionTip = false
let router = null;
let instance = null;
// new Vue({
// render: h => h(App),
// }).$mount('#app')
function render(props = {}) {
const { container } = props;
router = new VueRouter({
// 微应用配置路由 基础路径
base: window.__POWERED_BY_QIANKUN__ ? '/app-vue/' : '/',
mode: 'history',
routes,
});
console.log(router,'router222')
instance = new Vue({
router,
// store,
render: (h) => h(App),
}).$mount(container ? container.querySelector('#app') : '#app');
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
export async function bootstrap() {
console.log('vue子应用bootstrap');
}
export async function mount(props) {
console.log('vue子应用mount', props);
render(props);
}
export async function unmount(props) {
console.log('vue子应用卸载', props);
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
router = null;
}
三,父子组件通信
- 使用MicroApp 组件通信 1.1 父应用
mport { MicroApp } from 'umi';
import { useState } from 'react';
import { Button } from 'antd';
export default function IndexPage() {
const [ age ,setAge] = useState(1)
const onAdd = ()=>{
setAge(age+1)
}
return (
<div>
<Button onClick ={()=>{onAdd()}}>父应用增加年龄</Button>
<div>{age}</div>
{/* MicroApp 像props一样参 */}
<MicroApp name="vue-ayp" onChange={onAdd} age={age} />
</div>
);
}
1.2 子应用app1
import { useModel } from 'umi';
function MyPage() {
// useModel('@@qiankunStateFromMaster') 子应用可以在其内部全局拿到父应用传递过来的参数
const masterProps = useModel('@@qiankunStateFromMaster');
console.log(masterProps, 'masterProps====')
const { numberF, onChange } = masterProps
const onAdd = () => {
onChange()
}
return (
<div>
{numberF ?
<div>
<Button onClick={() => { onAdd() }}>App1-umi本地应用点击加一</Button>
<div>{numberF}</div>
</div>
:
'App1-umi本地应用无点击事件'
}
</div>
)
}
2,未完待续。。。。