single-spa結合vue項目初探
本次案例以vue-element-admin爲例,驗證single-spa的可接入性。根據single-spa的官網介紹,推薦將項目的所有文件(包括圖片和css)等文件全部打包入一個js文件。但是這樣我們原來的分包等打包優化都會變得沒有意義,那麼爲什麼要全部打入一個包呢?
因爲single-spa的接入是以入口js文件接入的,而不是入口html文件,這樣一來就會導致一些資源加載路徑的錯誤,從而導致無法正常顯示,但也並不是完全不可以。下面將一步步一起嘗試。
安裝依賴
我們需要安裝幾個依賴來方便接入single-spa
npm install -save single-spa-vue
npm install -save systemjs-webpack-interop // 根據需要引入
配置文件
首先修改vue-element-admin的一些文件,首先是main.js,這裏只列舉新增的代碼塊,其餘保持不變,唯一需要變得是刪除Vue實例化的部分(即 new Vue(…))。
import "./set-public-path";
import singleSpaVue from "single-spa-vue";
const vueLifecycles = singleSpaVue({
Vue,
appOptions: {
render: h => h(App),
router,
store
}
});
export const bootstrap = vueLifecycles.bootstrap;
export const mount = vueLifecycles.mount;
export const unmount = vueLifecycles.unmount;
然後在main.js同級目錄下添加set-public-path.js文件,這個文件的作用是可以簡化文件的引用路徑,這樣在項目跑起來後就可以方便引入打包後的文件(只是在運行時簡化),如果是先打包後引入的話就不需要這個文件。
import { setPublicPath } from "systemjs-webpack-interop";
setPublicPath("vueAdmin", 2);
修改vue.config.js
這裏修改打包方式,這部分是我嘗試過之後可用的打包方式,暫且以這個爲例。
// 只保留如下 chainWebpack 配置,其餘的刪除
chainWebpack: config => { // 保留原項目處理svg的loader
config.devServer.set("inline", false);
config.devServer.set("hot", true);
config.module
.rule("svg")
.exclude.add(resolve("src/icons"))
.end();
config.module
.rule("icons")
.test(/\.svg$/)
.include.add(resolve("src/icons"))
.end()
.use("svg-sprite-loader")
.loader("svg-sprite-loader")
.options({
symbolId: "icon-[name]"
})
.end();
// config.externals(['vue', 'vue-router']) 如果是在外部統一引入則開啓這行
},
filenameHashing: false // 禁用hash文件名
然後執行命令打包,我這裏是打包到dist目錄下,這裏顯示++的都是打包後手動新增的文件
└─static
├─fonts
├─img
├─js
└─static ++
├─fonts ++
├─img ++
└─js ++
添加single-spa項目
新建一個文件夾執行npm init
然後修改pakage.json內容如下
{
"name": "single-spa",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"serve": "serve -s -l 5000"
},
"devDependencies": {
"serve": "^11.3.2"
},
"author": "",
"license": "ISC"
}
新建index.html
文件中vueAdmin的路徑爲vue項目打包後的dist目錄下起的服務
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Coexisting Vue Microfrontends</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="importmap-type" content="systemjs-importmap" />
<script type="systemjs-importmap">
{
"imports": {
"single-spa": "https://cdnjs.cloudflare.com/ajax/libs/single-spa/4.3.7/system/single-spa.min.js",
"vueAdmin": "http://10.118.37.41:8080/static/js/app.js"
}
}
</script>
<link
rel="preload"
href="https://cdnjs.cloudflare.com/ajax/libs/single-spa/4.3.7/system/single-spa.min.js"
as="script"
crossorigin="anonymous"
/>
<script src="https://unpkg.com/[email protected]/dist/import-map-overrides.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/system.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/amd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/named-exports.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/named-register.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/use-default.min.js"></script>
</head>
<body>
<script>
(function () {
System.import("vueAdmin").then((res) => {
console.log(res);
});
Promise.all([System.import("single-spa")]).then(function (modules) {
var singleSpa = modules[0];
singleSpa.registerApplication(
"vueAdmin",
() => System.import("vueAdmin"),
(location) => true
);
singleSpa.start();
});
})();
</script>
<!-- See https://github.com/joeldenning/import-map-overrides#user-interface -->
<import-map-overrides-full
show-when-local-storage="overrides-ui"
></import-map-overrides-full>
</body>
</html>
然後執行npm run serve就可以在瀏覽器中看到效果,並且是按需加載
結論:以js入口的方式並不是不可以分包加載,只不過需要我們修改打包出來的文件的文件夾層級