前端微服務化解決方案3 - 模組載入器

weixin_33830216發表於2018-10-26

微前端的模組載入器,主要功能為:

  • 專案配置檔案的載入
  • 專案對外介面檔案的載入(訊息匯流排會用到,後續會提)
  • 專案入口檔案的載入

以上也是每一個單模組,不可缺少的三部分

配置檔案

我們實踐微前端的過程中,我們對每個模組專案,都有一個對外的配置檔案.
是模組在註冊到singe-spa時候所用到的資訊.

{
    "name": "name", //模組名稱
    "path": "/project", //模組url字首
    "prefix": "/module-prefix/", //模組檔案路徑字首
    "main": "/module-prefix/main.js", //模組渲染出口檔案
    "store": "/module-prefix/store.js",//模組對外介面
    "base": true 
    // 當模組被定性為baseApp的時候,
    // 不管url怎麼變化,專案也是會被渲染的,
    // 使用場景為,模組職責主要為整個框架的佈局或者一直被渲染,不會改變的部分
  }

當我們的模組,有多種url字首的時候,path也可以為陣列形式

{
    "path": ["/project-url-path1/","/project-url-path2/"], //專案url字首
  }

配置自動化

我們每個模組都有上面所描述的配置檔案,當我們的專案多個模組的時候,我們需要把所有模組的配置檔案聚合起來.
我這裡也有寫一個指令碼.

micro-auto-config

使用方法:

npm install micro-auto-config -g

# 在專案根目錄,用pm2啟動該指令碼,便可啟動這個專案的配置自動化
pm2 start micro-auto-config

大概思路是:當模組部署,伺服器檢測到專案檔案發生改變,便開始找出所有模組的配置檔案,把他們合併到一起.
以陣列包物件的形式輸出一個總體的新配置檔案 project.config.js.
當我們一個模組配置有更新,部署到線上的時候,專案配置檔案會自動更新.

模組載入器

這個檔案直接引入到html中,也就是上一篇文章中的single-spa-config.js 升級版.
在載入模組的時候,我們使用SystemJS作為我們的模組載入工具.

"use strict";
import '../libs/es6-promise.auto.min'
import * as singleSpa from 'single-spa'; 
import { registerApp } from './Register'

async function bootstrap() {
    // project.config.js 檔案為所有模組的配置集合
    let projectConfig = await SystemJS.import('/project.config.js' )

    // 遍歷,註冊所有模組
    projectConfig.projects.forEach( element => {
        registerApp({
            name: element.name,
            main: element.main,
            url: element.prefix,
            store:element.store,
            base: element.base,
            path: element.path
        });
    });
    
    // 專案啟動
    singleSpa.start();
}

bootstrap()

Register.js

import '../libs/system'
import '../libs/es6-promise.auto.min'
import * as singleSpa from 'single-spa';

// hash 模式,專案路由用的是hash模式會用到該函式
export function hashPrefix(app) {
    return function (location) {
        let isShow = false
        //如果該應用 有多個需要匹配的路勁
        if(isArray(app.path)){
            app.path.forEach(path => {
                if(location.hash.startsWith(`#${path}`)){
                    isShow = true
                }
            });
        }
        // 普通情況
        else if(location.hash.startsWith(`#${app.path || app.url}`)){
            isShow = true
        }
        return isShow;
    }
}

// pushState 模式
export function pathPrefix(app) {
    return function (location) {
        let isShow = false
        //如果該模組 有多個需要匹配的路徑
        if(isArray(app.path)){
            app.path.forEach(path => {
                if(location.pathname.indexOf(`${path}`) === 0){
                    isShow = true
                }
            });
        }
        // 普通情況
        else if(location.pathname.indexOf(`${app.path || app.url}`) === 0){
            isShow = true
        }
        return isShow;
    }
}

// 應用註冊
export async function registerApp(params) {

    singleSpa.registerApplication(params.name, () => SystemJS.import(params.main), params.base ? (() => true) : pathPrefix(params));

}

//陣列判斷 用於判斷是否有多個url字首
function isArray(o){
    return Object.prototype.toString.call(o)=='[object Array]';
}

未完待續 ...

相關文章

前端微服務化解決方案1 - 思考

前端微服務化解決方案2 - Single-SPA

前端微服務化解決方案3 - 模組載入器

前端微服務化解決方案4 - 訊息匯流排

前端微服務化解決方案5 - 路由分發

前端微服務化解決方案6 - 構建與部署

前端微服務化解決方案7 - 靜態資料共享

前端微服務化解決方案8 - 二次構建

Demo

前端微服務化 Micro Frontend Demo

微前端模組載入器

微前端Base App示例原始碼

微前端子專案示例原始碼

相關文章