当前位置: 首页 > 科技观察

送给大家的Node.js小魔法

时间:2023-03-18 20:33:46 科技观察

本文转载自微信公众号《神光的编程秘籍》,作者神说必有光。转载本文请联系神光编程秘籍公众号。对于魔术表演,我们准备了一个Node.js模块input.js://input.jsfunctionfunc(){return'Carsonne'}module.exports=func();这个模块返回的值是多少?东东:是“卡赞”。然后我在另一个模块test.js中引入这个input.js,然后打印出来://test.jsconstdata=require('./input.js');控制台日志(数据);之后,我在entry.js中引入test.js:require('./test.js');执行后打印什么?东东:就是“卡松”。真的吗?然后我们运行:打印出来的是什么:东东:是“卡帅”,哇,好神奇,它是怎么做到的。我:你想学吗?冬冬:对。我:那么是时候揭开魔法的秘密了。魔术揭示Node.js中加载模块的过程是这样的:模块加载会调用load方法,load会调用后缀名对应的_extensions方法进行处理,会调用_compile进行编译并把结果进入缓存,然后返回。所以?如果我们想改变js模块的返回值,只需要修改Module._extensions['.js']即可。constModule=require('module');constfs=require('fs');Module._extensions['.js']=function(module,filename){letcontent=fs.readFileSync(filename,'utf8');if(filename.includes('input')){content=content.replace('Casson','Casson');}module._compile(content,filename);};我们读取输入filename的文件内容后,进行替换,然后调用module._compile进行编译,后面的流程不变。模块导入方式不变,只是模块内容悄悄修改。神奇的名字是requirehook。冬冬:原来是你把一段代码藏起来了,没有展示出来。我:魔术就是这样。而且不要小看这个requirehook,它可以做很多强大的功能。东东:哦?比如我:比如ts-node,怎么直接requirets模块呢?它是通过require钩子秘密编译的。其实你执行的是编译好的js。比如babel-register如何直接执行带有esnext新特性的代码?它还通过requirehook偷偷编译。还有覆盖率测试,其实就是通过函数检测来完成的,就是你执行的每一条语句都会被统计。如何插入存根?运行单个测试时没有手动插入存根,因为该工具已通过require钩子偷偷插入存根以获取覆盖率数据。冬冬:这个魔法还是挺有用的。学习了~总结一下Node.js的js模块加载过程是load->_extensions['.js']->_compile,可以通过修改_extensions['.js']来达到hook的目的,比如在_compile之前做一些转码。这种hook用于babel-register、ts-node和单测覆盖测试,可以达到透明修改代码的目的。因为开发者不知道什么时候修改了代码,所以看起来很神奇。