前端時間打算建立更新下自己的github page杰刽,所以先在gitee上進(jìn)行可實(shí)驗,
開始選用qiankun
后來使用single-spa
露戒。
主應(yīng)用構(gòu)建
- 使用single-spa或者qiankun搭建主應(yīng)用都比較簡單缺谴,只需要配置士修,只要需要配置子應(yīng)用即可。
export const apps: AppConfig[] = [
{
name: 'blogs', // app name 需要唯一
source: {
scripts: ['/blogs/bundle.js'], //目前只實(shí)現(xiàn)js的加載澈灼,其打包的方式應(yīng)該為umd竞川,具體參考子應(yīng)用的配置
},
activeWhen: '/#/blogs', //配置路由,或者自定義返回bool的函數(shù)
container: '#main', //加載子應(yīng)用的位置
},
];
如上配置叁熔,參照官網(wǎng)配置即可委乌。
- 然后手動實(shí)現(xiàn)一個簡單的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進(jìn)行執(zhí)行,獲取到export出來的js
});
return exports[name];
};
可能是我使用的qiankun
的姿勢不對荣回,上面getApp
這一步qiankun已經(jīng)做了遭贸,但是我的加載有問題,所以就放棄了改用了single-spa
心软。
window.onload = () => {
init();// 自定義全局變量
start();
apps.forEach((app) => {
registerApplication(getAppConfig(app));//注冊子應(yīng)用
});
// 這里是我自定義的菜單渲染壕吹,即通過配置實(shí)現(xiàn)
MenuRender(menu, document.getElementById('app-header'));
};
這樣主應(yīng)用就算是搭建起來了。
子應(yīng)用的構(gòu)建
import { createApp } from 'vue';
import App from './App.vue';
import './index.scss';
let app;
/**
* bootstrap 只會在微應(yīng)用初始化的時候調(diào)用一次删铃,下次微應(yīng)用重新進(jìn)入時會直接調(diào)用 mount 鉤子耳贬,不會再重復(fù)觸發(fā) bootstrap。
* 通常我們可以在這里做一些全局變量的初始化泳姐,比如不會在 unmount 階段被銷毀的應(yīng)用級別的緩存等效拭。
*/
export async function bootstrap() {}
/**
* 應(yīng)用每次進(jìn)入都會調(diào)用 mount 方法,通常我們在這里觸發(fā)應(yīng)用的渲染方法
*/
export async function mount(props) {
app = createApp(App);
app.mount(props.container);
}
/**
* 應(yīng)用每次 切出/卸載 會調(diào)用的方法胖秒,通常在這里我們會卸載微應(yīng)用的應(yīng)用實(shí)例
*/
export async function unmount(props) {
app.unmount(props.container);
}
/**
* 可選生命周期鉤子缎患,僅使用 loadMicroApp 方式加載微應(yīng)用時生效
*/
export async function update(props) {}
//在本地開發(fā)時的配置
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開發(fā)的阎肝,按照上面我想著createApp
然后在mount和unmount的時候直接調(diào)用即可挤渔,結(jié)果發(fā)現(xiàn)unmount之后mount失敗,后來定位是vue庫的問題风题,然后happy的去提了個issue判导,并提了fix,結(jié)果原來我不是第一個先發(fā)現(xiàn)的沛硅,然后尤大大在另一個issue里面提到眼刃,并不推薦這樣做,建議重新createApp
代碼很簡單摇肌,構(gòu)建也很簡單
- 主應(yīng)用的webpack配置,其他的不用說擂红,只說特殊點(diǎn)
devServer: {
contentBase: './dist',
hot: true,
proxy: {
'/blogs': {
target: 'http://localhost:1234/',
pathRewrite: { '^/blogs': '' },
changeOrigin: true,
},
},
},
其實(shí)主應(yīng)用構(gòu)建不需要什么處理,本地開發(fā)的話围小,加個代理昵骤,使其能獲取到子應(yīng)用的文件
- 子應(yīng)用配置可能需要幾個點(diǎn)
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
publicPath: '/blogs/', //這里否則資源加載不上
},
},
],
},
因為打包出來的js最終是在主應(yīng)用下運(yùn)行的,所以其子應(yīng)用url需要一層轉(zhuǎn)化肯适。
devtool: 'inline-source-map',
如上变秦,所以其map需要聯(lián)入代碼如果使用map文件會導(dǎo)致map找不到。
output: {
filename: 'bundle.js',
library: packageName,
libraryTarget: 'umd',
},
使用umd方式框舔,方便外部獲取export蹦玫。
最后一個路由問題
vue-router在single-spa的使用
由于是使用gitpage的所以只能使用hash,最后只好自己手動實(shí)現(xiàn)一個簡單的router來滿足使用刘绣。
簡單來說就是在app.vue中創(chuàng)建一個history并provide下去钳垮。
在實(shí)現(xiàn)的Router組件以及Menu組件中獲取到hostory,然后進(jìn)行push和解析操作额港。具體請直接參考代碼饺窿。