前端模塊化架構設計與實現(二|模塊接口設計)

模塊接口設計

從結果提及

API

JModule.define(moduleKey, {
    init(jModuleInstance) {}, // jModuleInstance 爲JModule 實例
    routes: [], // 路由
    store: {}, // vuex
    imports: [], // 定義模塊依賴
    exports: {}, // 對外API
});
複製代碼

這裏作一點解釋:javascript

  1. JModule 是一個模塊管理器,加載到平臺層,負責模塊模塊的管理、模塊平臺之間的通訊等
  2. moduleKey 是識別模塊的惟一標識,做用很大,後面細說
  3. init函數,可選配置,模塊加載後會自動執行它,函數參數是模塊實例,能夠從實例獲取到當前模塊的域名等信息
  4. routes,可選配置,模塊的路由配置,註冊到平臺的 vueRouter 進行工做
  5. store, 可選配置,數據中心,註冊到平臺的 Vuex 進行工做
  6. imports,可選配置,定義該模塊依賴的其它模塊
  7. exports,模塊對外暴露的API, 能夠是任意類型變量,好比function、component等

Demo

舉個例子,開發一個研發流水線(pipeline)的模塊:vue

  1. 它有列表和詳情頁面
  2. 它須要從代碼倉庫(coding模塊)獲取一些基礎信息
  3. 它須要共享當前執行的流水線信息
  4. 它須要提供對外的接口,容許其它模塊單獨嵌入(不經過路由)流水線列表組件

應該會獲得兩個這樣的模塊配置:java

// coding 模塊配置
JModule.define('coding', {
    exports: {
        loadHooks() {},
    },
});

// pipeline 模塊配置
JModule.define('pipeline', {
    routes: [{
        path: '/list',
        name: 'PipelineList',
        component: ListView,
    }, { ... }],
    store: {
        currentPipeline: {}, // vuex 裏的模塊概念
    },
    imports: ['coding'], // 它依賴coding提供的API, 
    exports: {
        ListView,
    },
});

// pipeline 業務代碼
JModule.require('coding.loadHooks').then((loadHooks) => {
    loadHooks('...');
});

複製代碼

爲何設計這些字段

把問題具體化,應該有三個問題須要回答vuex

  1. 這些字段的做用是什麼?有多餘嗎?
  2. 這些字段夠用嗎?
  3. 爲何設計成這樣?

這些字段的做用是什麼?有多餘嗎?

這裏總共涉及六個字段:moduleKey、init、routes、store、imports、exports。api

moduleKey

  1. 做用跨域

    這是模塊的標識符,用於識別一個模塊。服務器

  2. 它不重要函數

    若是從「讓模塊代碼順利運行」這一個目標來說,它其實不須要,我把代碼加載了,該註冊的路由註冊了,代碼就能夠正確工做了,業務邏輯根本不須要它。不過,讓代碼運行,只是工程中的一部分工做。工具

  3. 它很重要 從管理的角度講,它真的必不可少。好比:ui

    a. 權限管理: 特定的人羣只能訪問特定的模塊,須要它識別模塊身份

    b. 資源加載管理: 好比因爲某些緣由,屢次要求執行加載某個模塊的資源,咱們能夠經過模塊標識進行模塊加載狀態管理,避免重複從服務器加載資源

    c. 調試: 能夠跟蹤指定模塊的資源加載進度以及執行異常,另外,當同一個平臺注入了同一個模塊的兩套資源配置時,好比既有生產環境配置又因開發須要注入了本地資源配置,能夠選擇本地優先。

routes 和 store

  1. 做用

    聲明模塊的路由信息和須要全局共享的數據

  2. 它不重要

    一個模塊有哪些頁面,有哪些數據須要共享,是業務範疇的事情,業務是複雜多變的,它可能根本沒有須要共享的數據,甚至根本不須要註冊路由,好比我可能聲明一個公共組件做爲模塊,或者它甚至沒有視圖,只是負責一些特定數據的加載,它其實能夠不須要。因此這是可選字段。

  3. 它很重要

    routes 很重要,對大多數場景而言,咱們須要根據不一樣的地址顯示不一樣的視圖,路由就必不可少。並且業務範疇的事情,也應該在模塊內管理,平臺不會預測到一個模塊有幾個頁面叫什麼名字。store 的存在我卻是猶豫過,沒有它並不會讓業務開發不下去,若是須要共享數據,用 events 和 exports 事實上也能夠達到相同的目的,可是從開發者習慣、易用性及歷史項目改造難度的角度講,store能避免一些額外的工做。

exports 和 imports

  1. 做用

    模塊間的依賴管理,聲明模塊對外提供服務的api, 以及依賴關係的外部模塊的聲明。可選

  2. 它不重要

    沒有這兩個字段,事實上也確實有其它方式去知足功能開發的需求。沒有imports,本身手動加載依賴的模塊代碼也能夠工做;沒有exports,往全局變量寫點東西,其它模塊也照樣能訪問到。若是隻是爲了實現功能,說它不重要,其實也沒毛病。

  3. 它很重要

    從代碼可維護的角度講,imports 聲明依賴的模塊,能夠實現自動加載依賴的模塊,否則可能會面臨腦力記住依賴關係,手動加載依賴模塊的尷尬場面。exports 除了對外暴露模塊功能之外,能夠告知開發者哪些是對外開放的功能,避免不兼容的修改致使其它模塊不能正常工做。

init

  1. 做用

    模塊加載完以後自動執行的一個函數,可選

  2. 它不重要

    絕大多數場景下,它確實沒有存在必要。目前我也沒有用到它了。

  3. 它很重要

    這個字段存在的意義,主要是爲了之後擴展功能,它能夠拿到模塊的實例信息,在早期的跨域解決方案中,模塊內的http請求須要知道模塊所在的域名,但在代碼不容許使用域名硬編碼的原則下,這個信息只有從模塊實例才能獲取到。後來爲了研發方便調整了這部分方案,不過考慮到模塊運行可能須要其它來源於外部配置的信息,因此保留了這個配置。

這些字段夠用嗎?

可能不必定夠用,但我並無遇到更復雜場景。從模塊管理的角度講,提供了moduleKey 做爲身份識別;從模塊自身功能完備性角度講,通常業務場景中須要全局掛載使用的只有router和store了;從模塊間的關係講,定義了入口和出口,應該也齊活了。

爲何設計成這樣?

這裏我大概參考了一下angular的模塊設計,angular是個自帶模塊設計的東西,因此借鑑了一下。或許有更好的方式。

有什麼能夠改進的?

或許能夠改爲這樣

export default {
    routes: [],
    ...
};
複製代碼
  1. JModule.define的使用其實能夠去掉,在編譯工具中自動加上它也是能夠的
  2. moduleKey 能夠根據項目內的路徑自動生成,而不須要手動去填,好比:/projectA/src/modules/b 能夠自動提取爲'projectA.b'做爲moduleKey。
相關文章
相關標籤/搜索