How_Require_Extensions_Work
Why
Doing require extensions correctly is essential, because:
- Users should be able to install multiple extensions in succession, and have them work together.
- Coverage tools like
nycneed it to reliably supply coverage information that takes into account sourcemaps from upstream transforms. - Because non-standard, un-predictable behavior causes hard to solve bugs, and major headaches for project maintainers.
What is a require extension anyways?
First, it's worth remembering what default ".js" extension does.
require.extenstions['.js'] = function (module, filename) {
var content = fs.readFileSync(filename, 'utf8');
module._compile(internalModule.stripBOM(content), filename);
}
Really simple. It reads the source content from the disk, and calls the module._compile. The default module._compile is a non-trivial piece of code, for simplicity I will just say it is what actually compiles the code.
Our first custom extension
Now let's install a transform that just appends the code + "bar" to the end of every file (humor me as I keep things simple).
This is how you would manually create that hook (in what is now widely accepted as the "right" way).
// append-bar.js
var oldHoook = require.extensions['.js']; // 1
require.extensions['.js'] = function (module, file) { // 2
var oldCompile = module._compile; // 3
module._compile = function (code, file) { // 4
code = code + ' + "bar"'; // 5
module._compile = oldCompile; // 6
module._compile(code + ' + "bar"'); // 7
};
oldHook(module, file); // 9
});
Note that this extension never reads from the disk. That is because the first extension in the chain (the system default one) handles loading from disk. If it's not obvious why that's true (it wasn't for me), keep reading.
The really important takeaway here is that you should be implementing require extensions almost exactly as I have above. There are multiple levels of indirection, and it can be confusing. Libraries like pirates can simplify the process.
Breakdown with 1 Custom Extension
Here is what happens when you call require("./foo.js")
// foo.js
module.exports = "foo"
What happens inside require boils down to this:
function pseudoRequire(filename) {
var ext = path.extname(filename); // ".js"
var module = new Module();
require.extensions[ext](module, filename);
}
Now let's step through the sequence of events.
- The system calls
require.extensions['.js'](module, './foo.js').
This meansappend-baris invoked with(module, './foo.js') append-barstores a reference tomodule._compile(line 3), an with its own wrapper function (line 4).
module._compilerefers to theappend-barwrapper function.
append-bar's reference tooriginalCompilerefers to the actual compile implementation.append-barcalls it'soldHook(the default.jsextension) with the modified module and filename (line 9).- The default
.jsextension reads in the source (module.exports = "foo"), and callsmodule._compile(source, filename).
Remembermodule._compilecurrently points to theappend-barwrapper function. - The append-bar wrapper adds
+ "bar"to the source (Line 5). The source is nowmodule.exports = "foo" + "bar". - The append-bar wrapper now replaces
module._compilewith it'soriginalCompilereference (Line 6).
module._compilenow points to the actual compile implementation module._compileis called again (this time pointing to actual, and the source is evaled and we get our result "foobar".
Breakdown with 2 Custom Extension
Assume we have first added the append-bar extension from above, followed by another called append-quz (which is for all purposes identical, except it appends baz instead.
- We install the
append-barextension (replacing the original hook)
append-bar#originalHookpoints to the original hook. - We install the
append-quzextension
append-quz#originalHookpoints to theappend-barhook. - We call
require('./foo.js'); append-quzhook is called with(module, './foo.js'), it replacesmodule._compilewith it's wrapper function.
append-quz#originalCompilepoints to the actual compile
module._compilepoints to theappend-quzwrapper.append-quzcalls it'soriginalHookreference, which isappend-bar.append-barreplacesmodule._compilewith it's wrapper.
append-bar#originalCompilepoints toappend-quzwrapper.
module._compilepoints to theappend-barwrapper.- The original extension is called, which loads the source from disk and calls
module._compile('module.exports = "foo"', './foo.js') - At this point
module._compilepoints to theappend-barwrapper, so the source is appended with+ "bar". - The
append-barcalls theoriginalCompilereference (which is theappend-quzwrapper). - The
append-quzwrapper does it's appending (so we've now got"foo" + "bar" + "quz") append-quzcalls it'soriginalCompilereference, which is actual and we get"foobarquz"
How_Require_Extensions_Work的更多相关文章
随机推荐
- core net 实现post 跟get
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using Syst ...
- DevExpress v18.1新版亮点——DevExtreme篇(三)
用户界面套包DevExpress v18.1日前终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExtreme JavaScript Controls v18.1 的新功能 ...
- ssh 免密登陆
A 要免密码登录要B 那么需要在A电脑上使用命令 ssh-keygen -t rsa 在~/.ssh/ 目录下生成id_rsa.pub 这个文件,然后将这个文件的内容拷到B电脑de ~/.ssh/au ...
- mysql创建存储过程,定时任务,定时删除log
-- 创建存储过程 清除30天前的日志create procedure deleteLog()BEGINdelete from contract_vlog where create_time<D ...
- L305 发邮件15分钟
发个邮件-不用那么纠结-把事情讲清楚就好-限制在15分钟写完-长的邮件25分钟-难点是讲清楚细节-比如软件调试bug-DFM-这里有些专业词汇 发现问题:发给客户的There are some qua ...
- day 29 socket 初级版
# 客户端介绍简单版# import socket# #1买手机# phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #SOCK_STR ...
- 在html5中不支持<table>的cellpadding 和 cellspacing ; 2) 如何用css实现 cellpadding, cellspacing ; 3) tr , th 是 有 border, 没有 padding 的.
1.初始: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...
- jetty404web界面服务器信息隐藏
jetty服务器报以上的404错误时,为了信息安全必须隐藏信息错误提示 在jetty的配置文件jetty.xml添加以下内容: 重启一下jetty服务器就OK了,在验证时是这样的:
- HIVE点滴:group by和distinct语句的执行顺序
同一条语句之中,如果同时有group by和distinct语句,是先group by后distinct,还是先distinct后group by呢? 先说结论:先group by后distinct. ...
- LeetCode--219、268、283、414、448 Array(Easy)
219. Contains Duplicate II Given an array of integers and an integer k, find out whether there are t ...