webpack4流程分析2

1.Compiler


// 1. 执行run方法开始编译
run() {
  // 开始编译 编译完成了执行onCompiled(stats)
  this.compiler(onCompiled)
}
// 编译
compiler(callback) {
  // 创建参数
  // const params = this.newCompilationParams();
  const params = {
    // 普通模块工厂
    normalModuleFactory: this.createNormalModuleFactory(),
    // 上下文模块工厂
    contextModuleFactory: this.createContextModuleFactory(),
    // 依赖的集合
    compilationDependencies: new Set(),
  }
  // 创建compilation对象  params中有普通模块工厂的
  const compilation = this.newCompilation(params);
  // 执行make构建 执行单入口插件中注册的钩子
  this.hooks.make(compilation, callback)
}
复制代码

2. SingleEntryPlugin

// class SingleEntryPlugin 在webpack执行过程中会注册插件
apply(compiler) {
    compiler.hooks.compilation.tap(
      "SingleEntryPlugin",
      (compilation, { normalModuleFactory }) => {
        // 给compilation的dependencyFactories属性添加属性
        compilation.dependencyFactories.set(
          SingleEntryDependency,
          normalModuleFactory
        );
      }
    );

    // compiler中执行make的时候就会执行这个插件
    compiler.hooks.make.tapAsync(
      "SingleEntryPlugin",
      (compilation, callback) => {
        console.log("SingleEntryPlugin 从此入口文件开始编译");
        // entry是入口文件 name是代码块的名称 context上下文绝对路径
        const { entry, name, context } = this;
        // 给entry添加了一些属性
        const dep = SingleEntryPlugin.createDependency(entry, name);
        // 编译入口文件和他的依赖 这里的dep简单看就是entry
        // {loc: {name: 'main'}, module: null, request:'./src/index.js', single entry }
        compilation.addEntry(context, dep, name, callback);
      }
    );
}
static createDependency(entry, name) {
    // 继承ModuleDependency 继承Dependency
    const dep = new SingleEntryDependency(entry);
    dep.loc = { name };
    return dep;
}
复制代码

3.Compilation

class Compilation extends Tapable {
  constructor(compiler) {
    // 在SingleEntryPlugin的compilation钩子会给变量赋值 不同的文件会对应不同的模块工厂
    this.dependencyFactories = new Map();
  }
  // 执行make之后会执行单入口插件的hook执行addEntry() 开始编译一个入口
  addEntry() {
    // 增加模块链
    this._addModuleChain(
      context,
      entry,
      (module) => this.entries.push(module),
      callback
    );
  }
  _addModuleChain(context, dependency, onModule, callback) {
    //dep = new new SingleEntryDependency() singleEntryDependency
    const Dep = dependency.constructor;
    // 拿到普通模块工厂 normalModuleFactory
    const moduleFactory = this.dependencyFactories.get(Dep);
    // 调用create方法创建模块
    moduleFactory.create({}, (err, module) => {
      // 调用module的build方法开始构建
      this.buildModule(module, false, null, null, (err) => {});
    });
  }
}
复制代码

4. NormalModuleFactory

// 普通模块工厂 如何产生normalModule的
// 简单理解为 create() {return new NormalModule()}
// NormalModuleFactory只是做了一些其他的处理
class NormalModuleFactory extends Tapable {
  constructor(context, resolverFactory, options) {
    // 注册factory钩子 触发返回一个function
    this.hooks.factory.tap("NormalModuleFactory", () => (result, callback) => {
      let resolver = this.hooks.resolver.call(null);
      // 执行resolver处理loader相关的逻辑
      resolver(result, (err, data) => {
        this.hooks.afterResolve.callAsync(data, (err, result) => {
          // 创建模块 NormalModule
          let createdModule = this.hooks.createModule.call(result);
          // 普通模块
          if (!createdModule) createdModule = new NormalModule(result);
          createdModule = this.hooks.module.call(createdModule, result);
          // 我们的到的模块就普通模块 给create方法
          return callback(null, createdModule);
        });
      });
    });

    // 注册resolver钩子 会处理一些loader 也会返回一个函数 给factory执行
    this.hooks.factory.tap("NormalModuleFactory", () => (result, callback) => {
      // loader的处理
      callback(null, {});
    });
  }

  // create方法 普通模块创建模块
  create(data, callback) {
    // 这些参数都会给 factory 执行 factory 的时候会创建 NormalModule 普通模块
    const dependencies = data.dependencies;
    const context = data.context || this.context;
    const resolveOptions = data.resolveOptions || {};
    const request = dependencies[0].request; // './src/index.js'
    const contextInfo = data.contextInfo || {};
    this.hooks.beforeResolve.callAsync({}, (err, result) => {
      const factory = this.hooks.factory.call(null);
      factory(result, (err, module) => {
        // 这里拿到的module就是factory中callback中的createdModule
        // 这个module也是执行create返回的module
        // 之后再调用module.build方法开始构建
        callback(null, module);
      });
    });
  }
}
复制代码

5.demo

// 简化下上面的逻辑

// 在factory中会执行resolver方法 处理loader
function resolver(data, callback) {
  console.log("resolve", data);
  callback(null, {
    context: "context",
    request: "./src/index.js",
  });
}

// 注册的factory钩子 执行的时候会返回一个函数
function factory(result, callback) {
  resolver(result, (err, data) => {
    console.log("resolver", data);
    createdModule = new NormalModule(result);
    callback(null, createdModule);
  });
}

// 一些参数
let result = {
  contextInfo: "contextInfo",
  resolveOptions: "resolveOptions",
  context: "context",
  request: "request",
  dependencies: "dependencies",
};

// 在create中会执行factory方法
factory(result, (err, module) => {
  // 这里就可以拿到NormalModule
  console.log("factory", module);
});

复制代码

6. NormalModule

class NormalModule extends Module {
  // 调用模块的build方法开始编译
  build(options, compilation, resolver, fs, callback) {
    return this.doBuild(options, compilation, resolver, fs, (err) => {
      console.log("build");
    });
  }
}
复制代码

7.总结

无标题-2021-06-09-1537.png

在compiler中执行compiler 
==> 创建params 普通模块工厂 normalModuleFactory
==> 创建compilation对象 里面有一个 dependencyFactories 来记录不同模块的工厂函数
    ==> 创建过程中会触发 this.hooks.compilation.call(compilation, params)
    ==> 执行SingleEntryPlugin中对应的钩子 记录SingleEntryDependency: normalModuleFactory
==> 执行make ==> 执行SingleEntryPlugin中的钩子 
    ==> 处理entry包装为SingleEntryDependency ==> compilation.addEntry()
    => addEntry开始编译一个新的入口 
    ==> addModuleChain()增加模块链
        ==> 从dependencyFactories中找到普通模块工厂 
        ==> 调用moduleFactory.create()方法创建
        ==> create()执行factory 得到module = new NormalModule() 普通模块
        ==> 执行模块的build方法(NormalModule.build)开始构建模块
        ==> afterBuild 递归处理依赖
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享