react拋出組件化的概念後,對於開發者而言,爲了提升代碼的可讀性與結構性,經過文件目錄結構去闡述組件嵌套關係無疑是一個很好的辦法,可是目錄級別的加深,同時讓require的文件路徑讓人頭疼。絕大多數公司會使用本身定製的alias工具,在腳手架入口配置文件中給相應的filePath賦予別名,pack時,進行統一替換。node
#ykit.config ... alias:{ 'Common':'./src/util/index.js', 'Component':'src/components/index.js' } ...
固然也能夠在文件中寫入惟一的標識位,pack時將該標識位與當前聲明標識位的filePath創建聯繫,facebook提供的@providesModule的就是這一策略。使用方法以下:react
#a.js /** * @providesModule Common */ export const isArray = () => { ... } export const isObject = () => { ... } #b.js import { isArray } from 'Common' isArray([])
fbjs-script/gulp:json
shared/provides-module.js中提供了這樣一段正則,用於匹配文件中是否有相似@providesModule的標識符gulp
module.exports = { regexp: /\r?\n \* \@providesModule (\S+)(?=\r?\n)/, };
modules-map.js 中:babel
transform函數調用如上正則對讀入文本進行解析,並將alias的別名與filePath創建映射關係ide
flush函數將前面拿到的映射表進行處理加上統一前綴,並導入到json文件中函數
function transform(file, enc, cb) { if (file.isNull()) { cb(null, file); return; } if (file.isStream()) { cb(new gutil.PluginError('module-map', 'Streaming not supported')); return; } // Get the @providesModule piece of out the file and save that. var matches = file.contents.toString().match(PM_REGEXP); if (matches) { var name = matches[1]; if (moduleMap.hasOwnProperty(name)) { this.emit( 'error', new gutil.PluginError( PLUGIN_NAME, 'Duplicate module found: ' + name + ' at ' + file.path + ' and ' + moduleMap[name] ) ); } moduleMap[name] = file.path; } this.push(file); cb(); } function flush(cb) { // Keep it ABC order for better diffing. var map = Object.keys(moduleMap).sort().reduce(function(prev, curr) { // Rewrite path here since we don't need the full path anymore. prev[curr] = prefix + path.basename(moduleMap[curr], '.js'); return prev; }, {}); fs.writeFile(moduleMapFile, JSON.stringify(map, null, 2), 'utf-8', function() { // avoid calling cb with fs.write callback data cb(); }); }
最後導出以下json(以fbjs build爲例)工具
{ "BrowserSupportCore": "fbjs/lib/BrowserSupportCore", "CSSCore": "fbjs/lib/CSSCore", "CircularBuffer": "fbjs/lib/CircularBuffer", "DOMMouseMoveTracker": "fbjs/lib/DOMMouseMoveTracker", "DataTransfer": "fbjs/lib/DataTransfer", "Deferred": "fbjs/lib/Deferred", "ErrorUtils": "fbjs/lib/ErrorUtils", "EventListener": "fbjs/lib/EventListener", "ExecutionEnvironment": "fbjs/lib/ExecutionEnvironment", "Heap": "fbjs/lib/Heap", "IntegerBufferSet": "fbjs/lib/IntegerBufferSet", "Keys": "fbjs/lib/Keys", "Locale": "fbjs/lib/Locale", "Map": "fbjs/lib/Map", "PhotosMimeType": "fbjs/lib/PhotosMimeType", "PrefixIntervalTree": "fbjs/lib/PrefixIntervalTree", "Promise": "fbjs/lib/Promise", "PromiseMap": "fbjs/lib/PromiseMap", }
然後該作什麼你們也清楚了,要麼node腳本去把文件裏require 對應別名的進行路徑替換,要麼經過babel替換,固然,facebook是經過babel玩的組件化
其實對於alias system目前提供的兩種方法,各有利弊。fb提供的方法,使得使用上更加便利,可是因爲alias遍地存在,聲明衝突也變得屢見不鮮(固然能夠經過統一前綴解決)。傳統在腳手架配置文件中聲明的方法,雖然能讓你對alias的聲明一目瞭然,可是使用上也繁瑣不少ui