前端时间打算建立更新下自己的github page,所以先在gitee上进行可实验,
开始选用qiankun
后来使用single-spa
。
主应用构建
- 使用single-spa或者qiankun搭建主应用都比较简单,只需要配置,只要需要配置子应用即可。
export const apps: AppConfig[] = [
{
name: 'blogs', // app name 需要唯一
source: {
scripts: ['/blogs/bundle.js'], //目前只实现js的加载,其打包的方式应该为umd,具体参考子应用的配置
},
activeWhen: '/#/blogs', //配置路由,或者自定义返回bool的函数
container: '#main', //加载子应用的位置
},
];
如上配置,参照官网配置即可。
- 然后手动实现一个简单的loader
export const getAppConfig = (app: AppConfig): RegisterApplicationConfig => {
return {
name: app.name,
app: () => getApp(app),
activeWhen: app.activeWhen,
customProps: {
...app.customProps,
container: app.container,
},
};
};
const getApp = async (app: AppConfig): Promise<any> => {
const {
source: { scripts, styles },
name,
} = app;
if (exports[name]) return exports[name];
const srcs = await Promise.all(
scripts.map((script) => fetch(script).then((res) => res.text()))
);
// todo:append styles
srcs.forEach((script) => {
eval.call(window, script); // 将配置的js进行执行,获取到export出来的js
});
return exports[name];
};
可能是我使用的qiankun
的姿势不对,上面getApp
这一步qiankun已经做了,但是我的加载有问题,所以就放弃了改用了single-spa
。
window.onload = () => {
init();// 自定义全局变量
start();
apps.forEach((app) => {
registerApplication(getAppConfig(app));//注册子应用
});
// 这里是我自定义的菜单渲染,即通过配置实现
MenuRender(menu, document.getElementById('app-header'));
};
这样主应用就算是搭建起来了。
子应用的构建
import { createApp } from 'vue';
import App from './App.vue';
import './index.scss';
let app;
/**
* bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
* 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
*/
export async function bootstrap() {}
/**
* 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
*/
export async function mount(props) {
app = createApp(App);
app.mount(props.container);
}
/**
* 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
*/
export async function unmount(props) {
app.unmount(props.container);
}
/**
* 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效
*/
export async function update(props) {}
//在本地开发时的配置
if (!window['__POWERED_BY_QIANKUN__']) {
const root = document.createElement('div');
root.setAttribute('id', 'main');
document.body.append(root);
const app = createApp(App);
app.mount('#main');
}
就是这么简单。
这里还有一个小插曲:使用vue3-alpha开发的,按照上面我想着createApp
然后在mount和unmount的时候直接调用即可,结果发现unmount之后mount失败,后来定位是vue库的问题,然后happy的去提了个issue,并提了fix,结果原来我不是第一个先发现的,然后尤大大在另一个issue里面提到,并不推荐这样做,建议重新createApp
代码很简单,构建也很简单
- 主应用的webpack配置,其他的不用说,只说特殊点
devServer: {
contentBase: './dist',
hot: true,
proxy: {
'/blogs': {
target: 'http://localhost:1234/',
pathRewrite: { '^/blogs': '' },
changeOrigin: true,
},
},
},
其实主应用构建不需要什么处理,本地开发的话,加个代理,使其能获取到子应用的文件
- 子应用配置可能需要几个点
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
publicPath: '/blogs/', //这里否则资源加载不上
},
},
],
},
因为打包出来的js最终是在主应用下运行的,所以其子应用url需要一层转化。
devtool: 'inline-source-map',
如上,所以其map需要联入代码如果使用map文件会导致map找不到。
output: {
filename: 'bundle.js',
library: packageName,
libraryTarget: 'umd',
},
使用umd方式,方便外部获取export。
最后一个路由问题
vue-router在single-spa的使用
由于是使用gitpage的所以只能使用hash,最后只好自己手动实现一个简单的router来满足使用。
简单来说就是在app.vue中创建一个history并provide下去。
在实现的Router组件以及Menu组件中获取到hostory,然后进行push和解析操作。具体请直接参考代码。
网友评论