前言

准备工作做了三遍文章,现在、立刻、马上,我们进入构建流程的分析!

构建入口

这个过程还是在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 class
Compilation.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过程。


csywweb
232 声望8 粉丝

最担心的事不是写出ipcode,而是从不开始