发布时间:2023-06-12 09:30
很多小伙伴在工作中都碰到过和我一样的场景,手上的某个项目越来越大,眼看着每次build时间越来越长,吐了。在杭州某独角兽我碰到了这样的一个项目,他叫运营后台,听名字就知道,他的主要用户是运营人员。问题就是随着公司业务的越来越多,这个运营后台承担的已经不是某一块业务了,而是所有业务的运营操作的中后台都在这上面。你可以这样理解,这个系统的每个一级菜单都是一块独立的业务,相互之间没有任何瓜葛;按常规的理解,这应该是单独的每一个project比较合理,但是正因为他的用户又都是公司的同一群人,他们早已经习惯就在运营后台上去找自己的菜单进行业务操作,拒不接受在他的收藏夹里多出来好几个项目地址。那我们有没有一个办法让我们的项目更好维护,又能让用户不改变他们使用同一个项目的期望呢。这就是写这篇文章的初衷,就是微前端!!
除了可以解决上面的问题以外,你想想,只要我们把项目改造成了微前端,那每个业务都是独立的project,只不过最终用户都是在一个主项目里去使用,那我们每个project的技术栈也不用定死了,就不存在老项目的技术栈是vue,以至于后面的项目都必须要用vue了,你也可以用react,这就很香不是吗。微前端的原理就是项目被拆成了父子关系,通过基座去引用了子应用,子应用之间是互相隔离的
可能是你见过最完善的微前端解决方案——官方是这么介绍的,基于single-spa,这里我就不详细介绍了,感兴趣的去看看文档,地址丢给你
首先我先用vue2-admin-cli——我自己做的脚手架工具,创建两个vue-admin项目来演示,一个作为qiankun基座,另外一个就是我要引用的子应用。
全局安装脚手架 npm install -g vue2-admin-cli # or yarn global add vue2-admin-cli 创建项目 vue2-admin-cli init安装依赖 yarn 启动项目 yarn serve 复制代码
运行起来就是这样的
现在我们开始分别改造基座qiankun-base和子应用qiankun-vue,我想达到的效果是主应用qiankun-base只保留header sider footer的一个基本layout的布局,content部分全部加载子应用
yarn add qiankun # 或者 npm i qiankun -S 修改package.json启动命令修改启动端口 \"serve\": \"vue-cli-service serve --port 80 --open\" src/router/index.ts修改路由模式为history const createRouter = () => new VueRouter({ mode: \"history\", routes: routes as any, }); 修改vue.config.js 我这里之前用的路由模式是hash 上线配置了publicPath 导致改为history以后静态资源加载路径有问题所以修改 module.exports = { // publicPath: \"./\", devServer: { disableHostCheck: true, // 关闭host检查 }, }; 复制代码
在入口文件src/main.ts下注册微应用并启动:
import { registerMicroApps, start } from \"qiankun\"; registerMicroApps([ { name: \"qiankunVue\", entry: \"//localhost:8080\", 子应用的启动端口修改为8080,基座使用80,不要相同 container: \"#qiankunVue\", 加载子应用的容器 activeRule: \"/qiankunVue\", 路由匹配规则 }, ]); // 启动 qiankun start(); 复制代码
在你要放置子应用的位置增加一个容器用于加载子应用
src/components/layout/index.vue
复制代码 {{ route.meta.title }} {{ route.meta.title }}
将主应用之前的路由配置进行修改,不渲染自己的内容了,因为要改成去加载子应用的内容才是我们想要的,我的左侧菜单栏sider也是用路由配置这份文件生成的,所以我只需要注释这些路由要渲染的components就行,让他只充当一个生成sider菜单栏的作用,但是注意要保留容器所在的layout,因为我的子应用加载容器在这里面,加载子应用之前你必须保证容器被加载了
src/router/config.ts
const routes: Array= [ { path: \"/\", redirect: \"/home\", hidden: true, }, { path: \"/login\", name: \"login\", hidden: true, component: () => import(\"../views/Login.vue\"), }, //保证子应用加载时容器页面必须加载 { path: \"/qiankunVue/*\", name: \"qiankunVue\", hidden: true, component: Layout, }, { path: \"/qiankunVue/home\", name: \"home\", component: Layout, redirect: \"/qiankunVue/home/index\", meta: { title: \"首页\", icon: \"el-icon-s-home\", }, children: [ { path: \"index\", name: \"index\", hidden: true, // component: () => import(\"../views/Home.vue\"), meta: { title: \"首页\", breadcrumb: false, }, }, { path: \"bar/:width/:height\", name: \"bar\", props: true, hidden: true, // component: () => import(\"@/components/echarts/Bar.vue\"), meta: { title: \"柱状图\", activeMenu: \"/home/index\", }, }, { path: \"pie/:width/:height\", name: \"pie\", props: true, hidden: true, // component: () => import(\"@/components/echarts/Pie.vue\"), meta: { title: \"饼图\", activeMenu: \"/home/index\", }, }, { path: \"line/:width/:height\", name: \"line\", props: true, hidden: true, // component: () => import(\"@/components/echarts/Line.vue\"), meta: { title: \"折线图\", activeMenu: \"/home/index\", }, }, ], }, ..... { path: \"*\", redirect: \"/error/404\", hidden: true, }, ]; export default routes; 复制代码
改完之后刷新看一看,这样基座项目就改造好了,保留了基本页面的框架,中间的内容到时候都由子应用来填充就行了
修改package.json启动命令修改启动端口
\"serve\": \"vue-cli-service serve --port 8080 --open\"
入口文件 src/main.ts 修改
let vm: any = null; function render(props: any = {}) { const { container } = props; vm = new Vue({ router, store, render: (h) => h(App), }).$mount(container ? container.querySelector(\"#app\") : \"#app\"); } // 在被qiankun引用时 修改运行时的 `publicPath` if ((window as any).__POWERED_BY_QIANKUN__) { __webpack_public_path__ = (window as any).__INJECTED_PUBLIC_PATH_BY_QIANKUN__; } // 独立运行时 if (!(window as any).__POWERED_BY_QIANKUN__) { render(); } 导出三个生命周期函数 export async function bootstrap() { console.log(\"[vue] vue app bootstraped\"); } export async function mount(props: any) { console.log(\"[vue] props from main framework\", props); render(props); } export async function unmount() { vm.$destroy(); vm.$el.innerHTML = \"\"; vm = null; } export default vm; 复制代码
src/router/index.ts修改路由模式并增加base(和主应用设置的activeRule一致)
const createRouter = () => new VueRouter({ mode: \"history\", base: \"/qiankunVue\", routes: routes as any }); 复制代码
打包配置修改(`vue.config.js`)
module.exports = { devServer: { disableHostCheck: true, // 关闭host检查 headers: { \"Access-Control-Allow-Origin\": \"*\", // 防止加载时跨域 }, }, configureWebpack: { output: { library: \"qiankunVue\", libraryTarget: \"umd\", // 把微应用打包成 umd 库格式 }, }, }; 复制代码
基座和子应用都修改完以后刷新看看,控制台报错了
立马查看官方文档,发现是因为我的子应用加载容器在基座的某个路由页面即我的layout里面,文档里指出必须保证微应用加载时主应用这个路由页面也加载了,就很喜欢这种文档,于是立马改一改
注释之前qiankun-base注册子应用时的启动qiankun命令,改到路由页面layout里面启动
src/main.ts
// 启动 qiankun //start(); src/components/layout/index.vue import { start } from \"qiankun\"; mounted() { if (!(window as any).qiankunStarted) { (window as any).qiankunStarted = true; start(); } } 复制代码
重新刷新看看,成功了,多少有点舒服了
接下来要做的就是把子应用再改造一下,在qiankun中就只需要展示子应用content的内容,单独运行的时候为了方便调试我们就保留layout布局。看了这么久的官方文档,我当然知道用它就可以做出判断__POWERED_BY_QIANKUN__,思路很清晰,冲他
qiankun-vue
src/components/layout/index.vue
{{ route.meta.title }} {{ route.meta.title }} 复制代码 {{ route.meta.title }} {{ route.meta.title }}
至此完结撒花,改造结束❤️❤️,看看效果 基座正常展示子应用
子应用单独运行也正常展示,并且丝毫不影响开发体验
qiankun-base qiankun基座
qiankun-vue qiankun子应用
vue-admin ## vue 中后台系统解决方案
vue2-admin-cli vue2-admin-cli是vue-admin的cli脚手架工具,支持快速搭建企业级中后台项目模板
关于父子通信这个示例就不做概述,有兴趣的可以自己看看文档
以上就是微前端qiankun改造日渐庞大的项目教程的详细内容,更多关于微前端qiankun改造庞大项目的资料请关注脚本之家其它相关文章!