记录一个问题的调研过程。
在研究webpack4和webpack5编译过程的不同,写了插件用于暴露整个编译过程,准备逐个研究hook的回调。插件代码如下:
const PLUGIN_NAME = 'TestPlugin'
const traverse = {
contextModuleFactory: (arg) => {
console.log(arg)
}
}
module.exports = class TestPlugin {
apply(compiler) {
Object.keys(traverse).forEach(hook => {
compiler.hooks[hook].tap(PLUGIN_NAME, traverse[hook])
})
}
}
在调用contextModuleFactory
或者run
之类的hooks时报错:
[webpack-cli] TypeError: Function has non-object prototype 'null' in instanceof check
at Function.[Symbol.hasInstance] (<anonymous>)
at getConstructorName (internal/util/inspect.js:535:13)
at formatRaw (internal/util/inspect.js:803:23)
at formatValue (internal/util/inspect.js:793:10)
at formatProperty (internal/util/inspect.js:1679:11)
at formatRaw (internal/util/inspect.js:1007:9)
at formatValue (internal/util/inspect.js:793:10)
at formatProperty (internal/util/inspect.js:1679:11)
at formatRaw (internal/util/inspect.js:1007:9)
at formatValue (internal/util/inspect.js:793:10)
全都是internal/*
的错误。
但是当回调函数没有入参的时候,不会报错:
const traverse = {
// 去掉入参,不报上述错误
contextModuleFactory: () => {
console.log()
}
}
先上百度搜一下,没啥结果,这个得吐槽了。
然后翻墙用google搜,找到一条webpack的issue:github.com/webpack/web… ,情况描述一摸一样。有人认为是node的bug,并写了个demo复现:
function X () {}
X.prototype = null;
x = {};
x.constructor = X;
console.log(x);
我当时的node版本是14.9,会复现这个问题。浏览器没事。
结合这个例子,这个bug大概问题是,在node执行instanceof
检查的时候,一个function
类的prototype为null时,导致报错。
在调用compiler.hooks.contextModuleFactory.tap
时,正常情况下会返回一个ContextModuleFactory
对象入参。怀疑这个入参的构造过程有点问题,不过没看源码核实,因为讨论中都觉得这是node的锅。
好在后面的讨论里,有人说node修复了这个问题:github.com/nodejs/node…
通过brew
把node版本升级到15,问题解决。