调试 webpack 过程理解执行流程
开始 - 合并配置 ------------ 实例化 compile------- 设置 node 文件读写能力 ----- 通过循环挂载 plugins----- 解决 webpack 外部默认的插件(入口文件)开始 -compiler.beforeRun-compiler.run--------compiler.beforeCompile-compiler.compile-------compile.make
在 Compiler
类中,构造函数内会挂载大量的钩子, 这些钩子都来自tapable
,挂载之后在后续的操作中,这些钩子期待被触发执行。
this.hooks = {/** @type {SyncBailHook<Compilation>} */
shouldEmit: new SyncBailHook(["compilation"]),
/** @type {AsyncSeriesHook<Stats>} */
done: new AsyncSeriesHook(["stats"]),
/** @type {AsyncSeriesHook<>} */
additionalPass: new AsyncSeriesHook([]),
/** @type {AsyncSeriesHook<Compiler>} */
beforeRun: new AsyncSeriesHook(["compiler"]),
/** @type {AsyncSeriesHook<Compiler>} */
run: new AsyncSeriesHook(["compiler"]),
/** @type {AsyncSeriesHook<Compilation>} */
emit: new AsyncSeriesHook(["compilation"]),
/** @type {AsyncSeriesHook<string, Buffer>} */
assetEmitted: new AsyncSeriesHook(["file", "content"]),
/** @type {AsyncSeriesHook<Compilation>} */
afterEmit: new AsyncSeriesHook(["compilation"]),
/** @type {SyncHook<Compilation, CompilationParams>} */
thisCompilation: new SyncHook(["compilation", "params"]),
/** @type {SyncHook<Compilation, CompilationParams>} */
compilation: new SyncHook(["compilation", "params"]),
/** @type {SyncHook<NormalModuleFactory>} */
normalModuleFactory: new SyncHook(["normalModuleFactory"]),
/** @type {SyncHook<ContextModuleFactory>} */
contextModuleFactory: new SyncHook(["contextModulefactory"]),
/** @type {AsyncSeriesHook<CompilationParams>} */
beforeCompile: new AsyncSeriesHook(["params"]),
/** @type {SyncHook<CompilationParams>} */
compile: new SyncHook(["params"]),
/** @type {AsyncParallelHook<Compilation>} */
make: new AsyncParallelHook(["compilation"]),
/** @type {AsyncSeriesHook<Compilation>} */
afterCompile: new AsyncSeriesHook(["compilation"]),
/** @type {AsyncSeriesHook<Compiler>} */
watchRun: new AsyncSeriesHook(["compiler"]),
/** @type {SyncHook<Error>} */
failed: new SyncHook(["error"]),
/** @type {SyncHook<string, string>} */
invalid: new SyncHook(["filename", "changeTime"]),
/** @type {SyncHook} */
watchClose: new SyncHook([]),
/** @type {SyncBailHook<string, string, any[]>} */
infrastructureLog: new SyncBailHook(["origin", "type", "args"]),
// TODO the following hooks are weirdly located here
// TODO move them for webpack 5
/** @type {SyncHook} */
environment: new SyncHook([]),
/** @type {SyncHook} */
afterEnvironment: new SyncHook([]),
/** @type {SyncHook<Compiler>} */
afterPlugins: new SyncHook(["compiler"]),
/** @type {SyncHook<Compiler>} */
afterResolvers: new SyncHook(["compiler"]),
/** @type {SyncBailHook<string, Entry>} */
entryOption: new SyncBailHook(["context", "entry"])
};
实现迷你版 webpack 临时不须要这么多钩子.
文件目录构造,lib 文件夹下 package.json 中 "main": "./lib/webpack.js",
NodeEnvironmentPlugin.js
文件次要给 compiler 挂载 node 读写文件性能
const fs = require('fs')
class NodeEnvironmentPlugin {constructor(options) {this.options = options || {}
}
apply(complier) {
// 源码中还有解决日志的性能,这里暂不须要,这里只须要使 compiler 具备文件读写能力即可
complier.inputFileSystem = fs
complier.outputFileSystem = fs
}
}
module.exports = NodeEnvironmentPlugin
Compiler.js
文件实现 compiler 实例化,挂载钩子,实现 run
办法。
const {
Tapable,
AsyncSeriesHook
} = require('tapable')
class Compiler extends Tapable {constructor(context) {super()
this.context = context
// 源码中的钩子会有很多
this.hooks = {done: new AsyncSeriesHook(["stats"])
}
}
run(callback) {
callback(null, {toJson() {
return {entries: [], // 以后打包入口信息
chunks: [], // 以后打包代码块信息
modules: [], // 模块信息
assets: [], // 打包生成的资源}
}
})
}
}
module.exports = Compiler
webpack.js
实现 webpack 流程次要步骤
const Compiler = require("./Compiler")
const NodeEnvironmentPlugin = require('./node/NodeEnvironmentPlugin')
const webpack = function (options) {
// 实例化 compiler 对象
let compiler = new Compiler(options.context)
compiler.options = options
// 初始化 NodeEnvironmentPlugin(让 compiler 具体文件读写能力)
new NodeEnvironmentPlugin().apply(compiler)
// 挂载所有 plugins 插件至 compiler 对象身上
if (options.plugins && Array.isArray(options.plugins)) {for (const plugin of options.plugins) {plugin.apply(compiler)
}
}
// 挂载所有 webpack 内置的插件(入口)// 最初返回
return compiler
}
module.exports = webpack
测试代码
let webpack = require('./myPack')
let options = require('./webpack.config.js')
let complier = webpack(options)
complier.run((err, stats) => {console.log(err)
console.log(stats.toJson({
entries: true,
chunks: false,
modules: false,
assets: false
}))
})
运行后打印
{entries: [], chunks: [], modules: [], assets: []}