乐趣区

关于webpack4:迷你版webpack实现

调试 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: []}
退出移动版