天天看點

使用webpack的動态子產品功能實作類似包掃描來簡化配置

昨天在浏覽幾個react項目的源碼,發現當項目較大時,會有個很蛋疼的地方:

大型項目會根據子產品來分拆reducer,是以會有大量的 <業務包名>/reducer/reducer.js 這樣的結構,然後在createStore時又得合并起來。

是以需要寫一個類似這樣的代碼來進行合并:

rootReducer.js

import aTodos from '../../xxxxx/reducers/xxxxxTodos'
import bTodos from '../../yyyyy/reducers/yyyyyTodos'
import cTodos from '../../zzzzz/reducers/zzzzzTodos'

const rootReducer = combineReducers({
  aTodos : aTodos ,
  bTodos : bTodos ,
  cTodos : cTodos
})

           

随着子產品的增加,該檔案需要不斷修改和調整。即使簡化寫成

export aTodos from '../../xxxxx/reducers/xxxxxTodos'
export bTodos from '../../yyyyy/reducers/yyyyyTodos'
export cTodos from '../../zzzzz/reducers/zzzzzTodos'
           

然後sotre檔案去import * as ABC這樣引入,也免不了寫一些繁瑣的格式化代碼。

當時先想是不是可以做一些預處理根據格式來生成檔案,但是覺得還是比較麻煩,版本管理器裡還得儲存這些版本。在翻閱webpack資料時,看到動态子產品這塊突然靈光乍現:是否可以實作自動掃描我的源碼結構來動态生成呢?

于是翻閱了一些資料,發現我的想法是可以的,因為:

1)require.context 能夠使用正則周遊你的檔案結構,這個正是包掃描需要的

2)exports是一個對象結構,也就意味着你可以通過exports[key]=value的形式動态來導出你的export

3)combineReducers需要的是一個對象結構,我隻需要通過 import * 導入我的檔案,就能夠作為一個對象導入

說幹就幹,于是有了這樣的一個檔案:

autoRecucers.js

/**
 * 基于路徑掃描的配置模式.
 * @Author JIM on 2017/2/21.
 * 
 * 等效語句:
 * export aaa from './../module/aaa/reducer/reducer'
 * export bbb from './../module/bbb/reducer/reducer'
 * export ccc from './../module/ccc/reducer/reducer'
 * ....
 */

let contexts = require.context("../module", true, /^\.\/.*\/redux\/reducer\.js$/);
contexts.keys().forEach((key) => {
    let name = /\.\/([^/]+)\//g.exec(key); //把包路徑名變成導出名
    let func = contexts(key).default;
    if(typeof(func)!="undefined"){
        exports[name[1]] = func;
    }
});
           

将我路徑下的所有redux目錄下的reducer.js的default export全部都變成export導出,然後:

import * as reducers from './auto/autoReducers';
           
store = createStore(
        combineReducers(reducers),
        applyMiddleware(thunk)
    );
           

好了,大功告成,再也不用維護rootReducer.js了。

這裡隻是抛磚引玉,同樣的原理,使用webpack動态導出的特性,你還可以對其它的檔案進行合并導出,例如actionType,等等,不限于redux。