2022,向后看,向前走
前言
过去的2021年除了业务开发,几乎所有的时间都致力于对composition-api的探究,封装了大量的组件以及配套的use函数,也算是对业务做了一些贡献,更重要的是对自己的开发思想进行了实践、落地,对解耦、聚合有了更深的理解,敬无所为但不甘碌碌无为的自己
思考
原vue2项目引入composition-api的确对逻辑层的开发提升了不少效率,但是项目依然是非常庞大,若干个应用在一个工程中,若干个应用同时开发、迭代,带来了很多的问题:
- 项目庞大、打包发布时间较长
- 项目维护、代码版本、合并变得困难
- 技术升级、迭代困难(一旦升级可能导致整个项目改造)
- 微小的改动导致整个项目需要发布(如紧急发布,导致整个项目需要重新发布,发布出现问题有可能导致整个项目瘫痪)
- 多个迭代进行时,常常需要沟通哪些迭代是需要发布的(某些迭代可能因为突发情况上线时间变动)
- 业务层面讲,不同应用也需独立开发部署
so,综上组合式api、组件封装等都是无法解决上述问题,由此也就引出了我们今天的主题:qiankun,qiankun是kuitos大佬开发的,目前算是业界较为完善且运用广泛的微前端解决方案,在项目中落地前先来学习一番(默默跟着大佬走),现在还处于初步了解阶段,在此记录一下
基座
基座也就是主应用,在基座完成对微应用的注册
import { registerMicroApps, start } from 'qiankun'
// router
import router from '@/router'
// 微应用配置
const apps = [
{
name: "child",
entry: "//localhost:8882",
container: "#container",
activeRule: '/child',
props: {
data: {
test: 'test',
router
}
}
}
]
// 注册方法
const registerApp = () => {
registerMicroApps(apps)
// 启动
start()
}
// 在main.js中调用
registerApp()
配置router
const routes = [
{
path: '/',
name: 'Layout',
component: Layout,
children: [
{
path: "/",
name: "Home",
component: Home,
}
]
}, {
// 携带*,表示匹配携带/child的所有路由
path: '/child*',
name: 'child',
component: Layout
}
];
如此就完成了基座的简单配置(不要忘记在DOM中绑定id)
微服务
微服务不需要安装qiankun,技术栈可以为前端任意框架,以vue为例,配置webpack:
const { name } = require('./package');
module.exports = {
devServer: {
port: 8883,
hot: true,
// 允许跨域访问
headers: {
'Access-Control-Allow-Origin': '*',
},
},
configureWebpack: {
output: {
library: `${name}-[name]`,
// 把微应用打包成 umd 库格式
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${name}`,
},
},
};
在/src/下添加文件public-path.js文件
// 作为判断是否存在基座的依据
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
然后再main.js中编写:
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import "./public-path";
Vue.config.productionTip = false;
let instance = null;
// 根据基座的存在与否,现在
function render(props) {
const { container } = props ?? {}
instance = new Vue({
router,
render: (h) => h(App),
}).$mount(container ? container.querySelector("#app") : "#app");
}
// 微应用独立运行
if (!window.__POWERED_BY_QIANKUN__) render()
export async function bootstrap(props) {
const { router } = props?.data ?? {}
// 保存基座router
Vue.prototype.$parentRouter = router
}
export async function mount(props) {
// 非独立运行
render(props);
}
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
}
微应用跳转主应用
如果微应用需要跳转主应用,可以通过主应用下发的router进行跳转
this.$parentRouter.push('/')
微应用互相跳转
通过history.pushState
history.pushState({ id: 1 }, '', '/child1')
全局状态
qiankun提供了initGlobalState定义全局状态
基座:
// 初始化全局状态
const actions = initGlobalState({ test: 1 })
// 设置全局状态
actions.setGlobalState({ level: 2 })
// 监听全局状态的变化
actions.onGlobalStateChange((state, prev) => console.log(state, prev))
微应用:
export async function mount(props) {
// 监听数据
props.onGlobalStateChange((state, prev) => console.log(state, prev););
// 更新数据
setTimeout(() => {
props.setGlobalState({ level: 3 })
}, 6000)
render(props);
}
公共组件、方法等
全局状态、方法、组件等均可通过props传递给微应用
基座:
// 公共组件
import Coms from '@/common/components'
// 公共方法
import utils from '@/common/utils'
// 微应用配置
const apps = [
{
name: "child",
entry: "//localhost:8882",
container: "#container",
activeRule: '/child',
props: {
data: {
Coms,
utils
}
}
}
]
微服务:
export async function bootstrap(props) {
const { Coms, utils } = props?.data ?? {}
// 保存公共方法
Vue.prototype.$utils = utils
// 注册公共组件
Vue.use(Coms)
}
sandbox
沙箱默认是开启的,但若微应用class名若和基座重复也会具备基座部分样式,若想样式完全隔离,需将strictStyleIsolation设置微true(参考webComponents的shadow dom),全局样式(即引入main.js中的样式依然会生效)
微应用技术栈不同
微前端不关心微应用使用的是哪种前端技术,但若想要统一组件的话,webComponents是一种方案,当然最好的方式还是技术栈统一
结语
抽空看了一部分,做了简单的demo,待有时间继续