一、背景
刚好有一个历史比较悠久的项目,也比较奇葩,门户是由三个前端项目组成的,所以在跳转页面的时候就相对比较慢。我思来想去,觉得微前端可以试试,便开始了我的qiankun之旅,虽然最终没有落地,但是其中的坎坷,我觉得是有必要记录一下的。 前端项目:2个vue2 + 1个vue3, 都是hash路由。
二、基本操作
1、主应用配置
按照乾坤的文档配置,首先配置主应用
const apps = [
{
name: 'v1',
entry: process.env.VUE_APP_ENTRY_V1,
container: '#subApp',
activeRule: '/v1',
},
{
name: 'v2',
entry: process.env.VUE_APP_ENTRY_V2,
container: '#subApp',
activeRule: '/v2',
},
{
name: 'v3',
entry: process.env.VUE_APP_EENTRY_V3,
container: '#subApp',
activeRule: '/v3',
},
]
registerMicroApps(apps);
runAfterFirstMounted(() => {
console.log("[MainApp] first app mounted");
});
start(
{
// urlRerouteOnly: true,
// singular: false,
excludeAssetFilter: (assetUrl: string): boolean => {}
}
);
PS: enrty字段可以根据自身的环境来,
- 如果是开发环境,可以直接写上本地启动的服务,【如://localhost:8080】
- 如果是测试或者线上环境:要区分是同服务部署还是不同服务器部署,我这里是在同一个服务器中的【如:/xx_xx/】
- 参考地址: qiankun.umijs.org/zh/cookbook…
2、微应用
微应用由于都是hash路由,所以在路由方面简单了很多,具体histroy路由怎么配置,可以参照文档:qiankun.umijs.org/zh/cookbook…
1)main.js
import './public-path';
Vue.use(VueLazyload, {
loading: window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__ ? `${window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__}/static/loading.png`: `/static/loading.png`
});
function render(props = {}) {
const { container } = props;
instance = new Vue({
router,
store,
render: (h) => h(App),
}).$mount(container ? container.querySelector('#app_mine') : '#app_mine');
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
const pvPromise = new LazyLoader('https://xxxx.xxxx.com/xx.php?id=1234&;web_id=2345').load()
const zStatPromise = new LazyLoader('https://xx.xxx.com/xxx?ie=utf-8').load()
render();
}
/**
* bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
* 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
*/
export async function bootstrap() {
console.log('我的页面bootstraped');
}
/**
* 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
*/
export async function mount(props) {
console.log('我的页面 app mount');
render(props);
}
/**
* 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
*/
export async function unmount(props) {
console.log('我的页面 from main framework', props);
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
_router = null;
}
/**
* 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效
*/
export async function update(props) {
}
2)添加public-path.js
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
3) webpack配置
output: {
library: `${packageName}-[name]`,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${packageName}`,
}
三、问题堆
qiankun的目的是帮助大家能更简单、无痛的构建一个生产可用微前端架构系统,但是对于刚开始接入的人来说,不走一些弯路是不可能的。
1、子应用引入第三方资源,报跨域错误
1) 可以将第三方脚本拖入本地,有自己服务器server支持跨域
2) 如果引入资源后为全局的变量,可以考虑在主应用中引入资源,微应用异步获取资源
- 主应用
<script type="text/javascript" src="https://xxx.xxx.com/xxx.php?xxx=xxx&;xxx=xxx"></script> <script src="https://xx.xx.com/xxx?ie=utf-8"></script> <script type="text/javascript" src="https://xxx.xxx.xxx.xxx/xxxx.js"></script>
3)excludeAssetFilter: 官方给出的一个方法,但是我这边尝试了,没有生效
- 微应用
// 独立运行时, 因为这个也不算是一个静态资源文件,所以没有办法直接放到本地,而是通过JSONP去获取的数据
if (!window.__POWERED_BY_QIANKUN__) {
const pvPromise = new LazyLoader('https://xxxx.xxxx.com/xx.php?id=1234&;web_id=2345').load()
const zStatPromise = new LazyLoader('https://xx.xxx.com/xxx?ie=utf-8').load()
render();
}
2、Uncaught Error: application 'mine-index' died in status LOADING_SOURCE_CODE: [qiankun]: Target container with #app_mine not existed while mine-index_1 loading!
看官方文档,我排查了很久,才发现是container写错了,主应用中要留一块subApp的container给子应用,这属于常识错误。
4、主应用中配置activeRule 为'/mine-index'进入死循环
配置出错了,重新对着文档配置了一遍,就没有死循环了,我微应用和主应用配置都配置了webpack选项,估计是当初看文档的时候老严昏花了吧。
5、出现了两行dom
低级错误,微应用中渲染了两次,即new了两次实例
6、app-errors.js?17fe:11 Uncaught Error: application 'mine-index' died in status NOT_MOUNTED: [qiankun]: Target container with #subApp not existed while mine-index mounting!
这个是在vue3项目中出现的,原因是我同时创建了多个实例,第二次访问项目的时候,又创建了一次
7、静态资源404的问题
- 1) 用网上的方法奖publicPath 设置成
localhost:${port}: 不行, 原始项目报错 vconsole.min.js?2f0e:10 Error: Loading chunk 0 failed. - 2) 后来自己琢磨,再看看文档
// 在懒加载资源上添加如上路径,就不报错了
Vue.use(VueLazyload, {
loading: window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__ ? `${window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__}/static/loading.png`: `/static/loading.png`
});
四、感悟
不是所有项目都要落地微前端的,除非你的应用已经变成了一个巨石应用,维护非常难,那么集成微前端才是最好的选择。虽然我的集成微前端这个方案最终没有落地,但是也不妨碍我轻触qiankun一次。