前言

筹备工作做了三遍文章,当初、立即、马上,咱们进入构建流程的剖析!

构建入口

这个过程还是在compiler.compiler函数里,

    // 在这之前new了一个 compilation 对象    this.hooks.make.callAsync(compilation, err => {            logger.timeEnd("make hook");            if (err) return callback(err);            logger.time("finish make hook");            this.hooks.finishMake.callAsync(compilation, err => {                logger.timeEnd("finish make hook");                if (err) return callback(err);                process.nextTick(() => {                    logger.time("finish compilation");                    compilation.finish(err => {                        logger.timeEnd("finish compilation");                                  if (err) return callback(err);                        logger.time("seal compilation");                        compilation.seal(err => {                            //dosomething                        });                    });                });            });    });

这里触发了make钩子注册的回调,还记得我在初始化局部提到的EntryPlugin吗?在这里注册了一个钩子回调,触发了 compilation.addEntry

compilation.addEntry(context, dependency, name, callback); //其中 dependency 为 EntryDependency 实例。

addEntry

addEntry 做了这么几件事:

  • 生成 EntryData
  • 调用compilation钩子addEntry
  • 执行 compilation.addModule

addModule

addModule 依据dep,拿到对应的 moduleFactory, 而后执行handleModuleCreation, 把 moduleFactorydependency等数据塞入一个队列factorizeQueue

获取moduleFactory

const Dep = /** @type {DepConstructor} */ (dependency.constructor);const moduleFactory = this.dependencyFactories.get(Dep);

this.dependencyFactories是一个 Map, 那么他是什么时候set的呢?答案还是在初始化局部提到的EntryPlugin中。

** 塞入队列

获取到依赖和模块的编译办法之后,塞入factorizeQueue队列

this.factorizeModule({    currentProfile,    factory,    dependencies,    factoryResult: true,    originModule,    contextInfo,    context},() => { // dosomethine})
// Workaround for typescript as it doesn't support function overloading in jsdoc within a classCompilation.prototype.factorizeModule = /** @type {{    (options: FactorizeModuleOptions & { factoryResult?: false }, callback: ModuleCallback): void;    (options: FactorizeModuleOptions & { factoryResult: true }, callback: ModuleFactoryResultCallback): void;}} */ (    function (options, callback) {        this.factorizeQueue.add(options, callback);    });

看到这里,有点没有脉络,add之后在整个 compilation 里没有找到相似于 factorizeQueue.startfactorizeQueue.run 之类的代码。一起去看看factorizeQueue 外部干了啥

factorizeQueue

this.factorizeQueue = new AsyncQueue({    name: "factorize",    parent: this.addModuleQueue,    processor: this._factorizeModule.bind(this)});

factorizeQueueAsyncQueue 的实例。AsyncQueue次要是做了一个队列管制。队列长度依据内部传入的parallelism来管制,factorizeQueue没有传,这里默认为1。

如果条件ok,在AsyncQueue的外部会调用_processor

this._processor(entry.item, (e, r) => {    inCallback = true;    this._handleResult(entry, e, r);});

这里就调用到_factorizeModule,接下来执行factory.create,开始reslove!

结语

到这里咱们曾经理解到webpack是如何应用配置中的entry属性,获取到modulefactory,下一篇将介绍reslove过程。