迷你版webpack实现

调试webpack过程了解执行流程

开始-合并配置------------实例化compile-------设置node文件读写能力-----通过循环挂载plugins-----处理webpack内部默认的插件(入口文件) 开始-compiler.beforeRun-compiler.run--------compiler.beforeCompile-compiler.compile-------compile.make

Compiler类中,构造函数内会挂载大量的钩子,这些钩子都来自tapable,挂载之后在后续的操作中,这些钩子等待被触发执行。
this.hooks = { /** @type {SyncBailHook} */ shouldEmit: new SyncBailHook(["compilation"]), /** @type {AsyncSeriesHook} */ done: new AsyncSeriesHook(["stats"]), /** @type {AsyncSeriesHook<>} */ additionalPass: new AsyncSeriesHook([]), /** @type {AsyncSeriesHook} */ beforeRun: new AsyncSeriesHook(["compiler"]), /** @type {AsyncSeriesHook} */ run: new AsyncSeriesHook(["compiler"]), /** @type {AsyncSeriesHook} */ emit: new AsyncSeriesHook(["compilation"]), /** @type {AsyncSeriesHook} */ assetEmitted: new AsyncSeriesHook(["file", "content"]), /** @type {AsyncSeriesHook} */ afterEmit: new AsyncSeriesHook(["compilation"]),/** @type {SyncHook} */ thisCompilation: new SyncHook(["compilation", "params"]), /** @type {SyncHook} */ compilation: new SyncHook(["compilation", "params"]), /** @type {SyncHook} */ normalModuleFactory: new SyncHook(["normalModuleFactory"]), /** @type {SyncHook}*/ contextModuleFactory: new SyncHook(["contextModulefactory"]),/** @type {AsyncSeriesHook} */ beforeCompile: new AsyncSeriesHook(["params"]), /** @type {SyncHook} */ compile: new SyncHook(["params"]), /** @type {AsyncParallelHook} */ make: new AsyncParallelHook(["compilation"]), /** @type {AsyncSeriesHook} */ afterCompile: new AsyncSeriesHook(["compilation"]),/** @type {AsyncSeriesHook} */ watchRun: new AsyncSeriesHook(["compiler"]), /** @type {SyncHook} */ failed: new SyncHook(["error"]), /** @type {SyncHook} */ invalid: new SyncHook(["filename", "changeTime"]), /** @type {SyncHook} */ watchClose: new SyncHook([]),/** @type {SyncBailHook} */ 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} */ afterPlugins: new SyncHook(["compiler"]), /** @type {SyncHook} */ afterResolvers: new SyncHook(["compiler"]), /** @type {SyncBailHook} */ entryOption: new SyncBailHook(["context", "entry"]) };

实现迷你版webpack暂时不需要这么多钩子.
文件目录结构,lib文件夹下package.json中 "main": "./lib/webpack.js",
迷你版webpack实现
文章图片

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 })) })

【迷你版webpack实现】运行后打印
{ entries: [], chunks: [], modules: [], assets: [] }

    推荐阅读