昨天在浏覽幾個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。