閱讀本文時但願您對babel-register有必定了解,若是還有不瞭解的能夠閱讀以前的文章傳送門node
在以前的文章中已經簡單介紹了babel-register的功能es6
那麼babel如何給require加上鉤子,使得在node環境下實現動態編譯的呢(靜態編譯:統一babel。動態編譯:js編譯到這行的時候進行編譯)npm
注:本文參考代碼爲babel-0.7.0-beta版本代碼。segmentfault
其實在上文babel-register中能夠看到,node環境下babel的編譯,是經過一個require上addHook的解決方法,那麼這個hook是怎麼掛載到require上的呢babel
首先想到的是node官版有沒有提供原生的方法處理,官版確實提供了一個require.extensions的方法,惋惜已經廢棄了,moudle模塊也沒有所謂addhook的辦法。那就只能安靜點看pirate的實現了less
深刻pirate的源碼時,咱們卻發現實際pirate這個npm包並無作什麼功能ui
核心代碼不超過100行,以下this
const Module = module.constructor.length > 1 ? module.constructor : BuiltinModule; export function addHook(hook, opts = {}) { // eslint-disable-line import/prefer-default-export let reverted = false; const loaders = []; const oldLoaders = []; let exts; const originalJSLoader = Module._extensions['.js']; const matcher = opts.matcher || null; const ignoreNodeModules = opts.ignoreNodeModules !== false; exts = opts.extensions || opts.exts || opts.extension || opts.ext || ['.js']; if (!Array.isArray(exts)) exts = [exts]; exts.forEach((ext) => { if (typeof ext !== 'string') throw new TypeError(`Invalid Extension: ${ext}`); const oldLoader = Module._extensions[ext] || originalJSLoader; oldLoaders[ext] = oldLoader; loaders[ext] = Module._extensions[ext] = function newLoader(mod, filename) { let compile; if (!reverted) { if (shouldCompile(filename, exts, matcher, ignoreNodeModules)) { compile = mod._compile; mod._compile = function _compile(code) { mod._compile = compile; const newCode = hook(code, filename); if (typeof newCode !== 'string') { throw new Error(HOOK_RETURNED_NOTHING_ERROR_MESSAGE); } return mod._compile(newCode, filename); }; } } oldLoader(mod, filename); }; }); return function revert() { if (reverted) return; reverted = true; exts.forEach((ext) => { if (Module._extensions[ext] === loaders[ext]) { Module._extensions[ext] = oldLoaders[ext]; } }); }; }
看起來這個代碼作的事很簡單就是在給原生moudle方法上不斷地掛載moudle._extension['.js/.es6/.jsx']之類的處理func,始終沒有看到執行時機。spa
因而簡單寫了一個demodebug
console.log('naturelessTT') debugger; require('require.js')
babel-node index.js --inspect-brk運行去看這個hook的執行時機以及call stack。
實際是require文件時,io讀取文件後會經過moudle.load的方法加載文件,而後依次執行_extension裏掛載的方法
真相大白,可是使人驚訝的是0.7以前的版本並無引入pirate這個包,看了0.6.26版本後,emmmm,babel大佬使用了官版已經標記爲廢棄的require.extensions。
固然雖然是廢棄的,可是node這個模塊已經鎖死,因此babel大佬還在肆無忌憚的用,固然0.7已經作了修正
Deprecated In the past, this list has been used to load non-JavaScript modules into Node.js by compiling them on-demand. However, in practice, there are much better ways to do this, such as loading modules via some other Node.js program, or compiling them to JavaScript ahead of time. Since the module system is locked, this feature will probably never go away. However, it may have subtle bugs and complexities that are best left untouched. Note that the number of file system operations that the module system has to perform in order to resolve a require(...) statement to a filename scales linearly with the number of registered extensions. In other words, adding extensions slows down the module loader and should be discouraged.