single-spa結合vue項目初探

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入口的方式並不是不可以分包加載,只不過需要我們修改打包出來的文件的文件夾層級

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章