最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • webpack4流程分析2

    正文概述 掘金(dream_99517)   2021-07-10   347

    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.总结

    webpack4流程分析2

    在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 递归处理依赖
    

    起源地下载网 » webpack4流程分析2

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元