compiler
一、认识
1.1 compiler
Compiler
全局构建管理器,Webpack
启动后会首先创建 compiler
对象,负责管理配置信息、Loader
、Plugin
等。从启动构建到结束。compiler
大致上会触发如下钩子:
1.2 compilation
Compilation
单次构建过程的管理器,负责遍历模块,执行编译操作;当 watch = true
时,每次文件变更触发重新编译,都会创建一个新的 compilation
对象。compilation
生命周期中主要触发如下钩子:
二、compiler.hooks.run
class RunPlugin{
apply(compiler){
compiler.hooks.run.tap('Plugin Run', (compiler)=>{
console.log("compiler")
});
}
}
二、compiler.hooks.emit
class EmitPlugin{
apply(compiler){
compiler.hooks.emit.tap('Plugin Emit', (compilation)=>{
console.log("compilation")
});
}
}
三、compiler.hooks.done
class DonePlugin{
apply(compiler){
compiler.hooks.done.tap('Plugin Don', (stats)=>{
console.log("stats")
});
}
}
四、compiler.hooks.make
compiler.hooks.make
是在正式开始构建时触发。参数为当前编译的 compilation
对象。
class MakePlugin{
apply(compiler){
compiler.hooks.done.tap('Plugin Make', (compilation)=>{
console.log("compilation",compilation)
});
}
}
五、compiler.hooks.compile
class CompilePlugin{
apply(compiler){
compiler.hooks.compiler.tap('Plugin Compiler', (params)=>{
console.log("params",params)
});
}
}
六、compiler.hooks.compilation
compiler.hooks.compilation
是在 Webpack
刚启动完,创建出 compilation
对象后触发。参数为当前编译的 compilation
对象。
class CompilationPlugin{
apply(compiler){
compiler.hooks.compilation.tap('Plugin Compilation', (compilation,params)=>{
console.log("params",params)
});
}
}
七、compiler.hooks.normalModuleFactory
Compiler
使用 NormalModuleFactory
模块生成各类模块。从入口点开始,此模块会分解每个请求,解析文件内容以查找进一步的请求,然后通过分解所有请求以及解析新的文件来爬取全部文件。在最后阶段,每个依赖项都会成为一个模块实例。
我们可以通过 NormalModuleFactory Hook
来注入 Plugin
逻辑从而控制 Webpack
中对于默认模块引用时的处理,比如 ESM
、CJS
等模块引入前后时注入对应逻辑。
7.1 语法
class NormalModuleFactoryPlugin{
apply(compiler){
compiler.hooks.normalModuleFactory.tap('Plugin NormalModuleFactory', (normalModuleFactory)=>{
console.log("normalModuleFactory",normalModuleFactory)
});
}
}
7.2 钩子
-
beforeResolve
: 当遇到新的依赖项请求时调用。可以通过返回false
来忽略依赖项。否则,返回undefined
以继续。 -
factorize
: 在初始化解析之前调用。它应该返回undefined
以继续。 -
resolve
: 在请求被解析之前调用。可以通过返回false
来忽略依赖项。返回一个模块实例将结束进程。否则,返回undefined
以继续。 -
resolveForScheme
: 在解析符合统一资源标志符方案(URI
)的请求之前调用。 -
afterResolve
: 在请求解析后调用。 -
createModule
: 在创建NormalModule
实例之前调用。 -
module
: 在创建NormalModule
实例后调用。 -
createParser
: 在Parser
实例创建之前调用。parserOptions
是module.parser
中对应标识符或空对象的选项。 -
parser
: 在创建Parser
实例后触发。 -
createGenerator
: 在Generator
实例创建之前调用。generatorOptions
是module.parser
中对应标识符或空对象的选项。 -
generator
: 在Generator
实例创建之后调用。
八、compiler.hooks.contextModuleFactory
Compiler
使用 ContextModuleFactory
模块从 webpack
独特的 require.context API
生成依赖关系。它会解析请求的目录,为每个文件生成请求,并依据传递来的 regExp
进行过滤。最后匹配成功的依赖关系将被传入 NormalModuleFactory
。
8.1 语法
class ContextModuleFactoryPlugin{
apply(compiler){
compiler.hooks.contextModuleFactory.tap('Plugin ContextModuleFactory', (contextModuleFactory)=>{
console.log("contextModuleFactory",contextModuleFactory)
});
}
}
8.2 钩子
-
beforeResolve
: 在解析请求的目录之前调用。请求可以通过返回false
来忽略。 -
afterResolve
: 在请求的目录解析后调用。 -
contextModuleFiles
: 读取目录内容后调用。在递归模式下,也会读取每个子目录。回调参数是一个包含每个目录中所有文件和文件夹名称的数组。 -
alternativeRequests
: 在创建请求之后但依据regExp
进行过滤之前,为每个文件调用。
九、compiler.hooks.contextModuleFactory.hooks.parse
parse
实例, 在 compiler
中被发现,是用来解析由 webpack
处理过的每个模块。parser
也是扩展自 tapable
的 webpack
类 并且提供多种 tapable
钩子。
9.1 语法
class NormalModuleFactoryPlugin{
apply(compiler){
compiler.hooks.normalModuleFactory.tap('Plugin NormalModuleFactory', (normalModuleFactory)=>{
const hook = normalModuleFactory.hooks.parser.for('javascript/auto');
hook.tap('MyPlugin', (parser,options)=>{
parser.hooks.someHooks.tap();
});
});
}
}
9.2 钩子
-
evaluateTypeof
: -
evaluate
: -
evaluateIdentifier
: -
evaluateDefinedIdentifier
-
evaluateCallExpressionMember
-
statement
-
statementIf
-
label
-
import
-
importSpecifier
-
export
-
exportImport
9.3 编写
1. DonePlugin
会将模块中所有的 statementIf
节点的判断表达式修改称为 false
const t = require('@babel/types');
const g = require('@babel/generator').default;
const ConstDependency = require('webpack/lib/dependencies/ConstDependency');
class DonePlugin {
apply(compiler) {
// 解析模块时进入
compiler.hooks.normalModuleFactory.tap('pluginA', (factory) => {
// 当使用javascript/auto处理模块时会调用该hook
const hook = factory.hooks.parser.for('javascript/auto');
// 注册
hook.tap('pluginA', (parser) => {
parser.hooks.statementIf.tap('pluginA', (statementNode) => {
const { code } = g(t.booleanLiteral(false));
const dep = new ConstDependency(code, statementNode.test.range);
dep.loc = statementNode.loc;
parser.state.current.addDependency(dep);
return statementNode;
});
});
});
}
}
module.exports = DonePlugin;
十、compiler.hooks.done
compiler.hooks.done
在编译完成后触发。参数为 stats
对象,包含编译过程中的各类统计信息。