微前端 Micro-Frontends - Single-SPA

Felix皇子發表於2020-11-07

微前端 Micro-Frontends - Single-SPA

single-spa 包含兩部分,
1. Applications ,每個應用都是一個完整的 SPA,每個應用需要知道怎麼從 DOM 上 bootstrap(引導), mount(安裝), and unmount(解除安裝)(這三個可以理解為 single-spa 的生命週期)
2. 一個配置檔案 single-spa-config ,可以理解為 HTML 頁面和 single-spa 註冊應用程式的 js 配置檔案,註冊應用需要的引數:
1. 一個應用的名字,不能重複
2. 一個載入應用程式碼的函式
3. 一個決定什麼時候啟用/滅活應用的函式
4. 自定義引數

Single-SPA 提供了自己的一個腳手架 create-single-spa
使用這個腳手架建立專案的時候可以附加引數

# --dir 宣告生成的專案檔名
npx create-single-spa my-dir
npx create-single-spa --dir my-dir

# --moduleType 指定生成哪一種型別的 single-spa ,參考下面三種型別
create-single-spa --moduleType root-config
create-single-spa --moduleType app-parcel
create-single-spa --moduleType util-module

# --framework 指定使用何種框架的,例如 react vue
create-single-spa --framework react
create-single-spa --framework vue
create-single-spa --framework angular 

在single-spa中,有以下三種微前端型別:
1. single-spa applications :為一組特定路由渲染元件的微前端。
- 有多個路由
- 宣告式 API ———— registerApplication
- 渲染 UI
- single-spa 管理生命週期:負責管理 regist 註冊後的應用
- 核心構建模組
2. single-spa parcels : 不受路由控制,渲染元件的微前端。

它們的存在主要是允許您在多個框架中編寫應用程式時在應用程式之間重用UI
- 無路由
- 命令式 API
- 渲染 UI
- 自定義生命週期:mountParcel mountRootParcel unmount 等方法來控制 parcels,參考API
- 僅在多個框架中需要
4. utility modules : 非渲染元件,用於暴露共享javascript邏輯的微前端。
- 無路由
- 暴露介面
- 可能渲染 UI
- 外部模組:沒有直接的單spa生命週期
- 共享通用邏輯或建立服務很有用

Single-SPA Config

配置檔案包含兩部分:
1. 一個所有應用共享的 html 檔案
2. 一個呼叫了 singleSpa.registerApplication() 的 js 檔案

singleSpa.registerApplication() 引數說明

  1. application name,一個字串,用於描述應用的名稱
  2. 載入函式或者應用
    • 引數是應用時:一個實現了生命週期方法的物件
const application = {
  bootstrap: () => Promise.resolve(), //bootstrap function
  mount: () => Promise.resolve(), //mount function
  unmount: () => Promise.resolve(), //unmount function
}
registerApplication('applicationName', application, activityFunction)
- 引數是載入函式時:一個返回值時 Promise 或者 async Function 的函式,通常的實現方式 `() => import('/path/to/application.js')`
  1. 啟用方法
    • 一個純函式,window.location 作為第一個引數,返回 true 表示啟用當前應用,如果 false 就不啟用
    • 在以下情況下 single-spa 會呼叫每個應用的啟用函式
      • hashchange popstate 事件觸發
      • pushState replaceState 方法被呼叫
      • triggerAppChange api 被呼叫
      • checkActivityFunction 方法被呼叫
  2. 自定義屬性
    自定義屬性時傳遞給應用的生命週期方法的,自定義屬性可以時一個物件,或者是一個以應用名 name 和 window.location 作為引數,返回物件的函式(name, location) => {}

使用配置物件的方式

singleSpa.registerApplication({
  name: 'myApp',
  app: () => import('src/myApp/main.js'),
  activeWhen: ['/myApp', (location) => location.pathname.startsWith('/some/other/path')],
  customProps: {
    some: 'value',
  },
});

singleSpa.registerApplication({
  name: 'myApp',
  app: () => import('src/myApp/main.js'),
  activeWhen: ['/myApp', (location) => location.pathname.startsWith('/some/other/path')],
  customProps: (name, location) => ({
    some: 'value',
  }),
});

config.name: 應用的名字
Config.app: 宣告你的應用,可以是包含bootstrap、mount、unmount這些生命週期的物件,或者是一個載入函式,與上面第二個引數一樣
Config.activeWhen:啟用函式,類似於上面第三個引數,可以是一個路徑的字首或者是一個包含兩者陣列
config.customProps: 自定義引數

single.Start()

Single-spa 配置必須呼叫start()API,以便實際安裝應用程式。在呼叫start之前,將載入應用程式,但不會引導/安裝/解除安裝應用程式。開始的原因是讓您控制效能。例如,您可能想立即註冊應用程式(以開始下載活動程式碼的程式碼),但是在初始AJAX請求(可能要獲取有關登入使用者的資訊)完成之前才真正安裝應用程式。在這種情況下,立即呼叫registerApplication即可獲得最佳效能,但是在AJAX請求完成後呼叫start。

Application lifecycle

Load

當應用的 activity function 返回 true 的時候就會立即執行,最好不要在 load 中執行任何操作,如果您需要在載入期間執行某些操作,只需將程式碼放入已註冊應用程式的主入口點,而不是放在匯出函式的內部。

console.log("The registered application has been loaded!");

export async function bootstrap(props) {...}
export async function mount(props) {...}
export async function unmount(props) {...}

Bootstrap

該生命週期函式將在首次安裝已註冊的應用程式之前被呼叫一次。

export function bootstrap(props) {
  return Promise
    .resolve()
    .then(() => {
      // One-time initialization code goes here
      console.log('bootstrapped!')
    });
}

Mount

每當未安裝已註冊的應用程式時,都會呼叫此生命週期函式,但是其活動函式將返回真實值。呼叫此函式時,該函式應檢視URL以確定活動路由,然後建立DOM元素,DOM事件偵聽器等以將內容呈現給使用者。任何後續的路由事件(例如hashchange和popstate)都不會觸發更多的裝載請求,而應由應用程式本身處理。

export function mount(props) {
  return Promise
    .resolve()
    .then(() => {
      // Do framework UI rendering here
      console.log('mounted!')
    });
}

Unmount

Activity function 返回 false 時,每當安裝已註冊的應用程式,都會呼叫此生命週期函式。呼叫此函式時,應清除所有在掛載已註冊應用程式時建立的DOM元素,DOM事件偵聽器,記憶體洩漏,全域性變數,可觀察的訂閱等。

export function unmount(props) {
  return Promise
    .resolve()
    .then(() => {
      // Do framework UI unrendering here
      console.log('unmounted!');
    });
}

Unload

解除安裝生命週期是一個可選實現的生命週期功能。每當應解除安裝應用程式時,它將被呼叫。除非有人呼叫unloadApplication API,否則這永遠不會發生。如果已註冊的應用程式未實現解除安裝生命週期,則假定解除安裝該應用程式為無操作。

相關文章