• webpack源码-loader的原理


    版本

    webpack :"version": "3.12.0",

    webpack配置中的loaders配置是如何传递的

    webpack/lib/NormalModuleFactory.js

    //从webpack的参数中获取自定义的所有loaders 
    this.ruleSet = new RuleSet(options.rules || options.loaders); 
    

    经过ruleSet.exec处理找到处理当前模块的loader

    const result = this.ruleSet.exec({
       resource: resourcePath,
       resourceQuery,
       issuer: contextInfo.issuer,
       compiler: contextInfo.compiler
    });
    

    到此处,result中的loader字段的值仍为babel-loader:
    FE0E25CF-5772-48EC-B6DD-7517DC4A6D71
    经过compiler.resolvers.loader处理之后变成了
    /Users/cc/killer/webpack-L/wb/node_modules/babel-loader/lib/index.js

    处理代码如下:

    asyncLib.parallel([
       this.resolveRequestArray.bind(this, contextInfo, this.context, useLoadersPost, this.resolvers.loader),
       this.resolveRequestArray.bind(this, contextInfo, this.context, useLoaders, this.resolvers.loader),
       this.resolveRequestArray.bind(this, contextInfo, this.context, useLoadersPre, this.resolvers.loader)
    ]
    
    

    ....

    经过多次回调传递

    到达钩子factory 然后创建新的模块:new NormalModule(..,loader,..)

    执行一系列回调函数

    -->触发before-resolve NormalModuleFactory.js
    -->触发factory NormalModuleFactory.js
    -->触发resolver NormalModuleFactory.js
    -->执行this.buildModule Compilation.js
    -->执行module.build NormalModule.js
    -->doBuild回调函数 NormalModule.js
    到达runLoaders,执行LoaderRunner.js中的runLoaders方法
    执行 iteratePitchingLoaders,该方法是个递归函数,先处理pitch阶段,然后再处理normal阶段

    先加载loader的代码
    加载:
    require(loader.path)
    定义currentLoaderObject的normal:
    loader.normal = typeof module === "function" ? module : module.default; // normal阶段的执行方法
    定义currentLoaderObject的pitch:
    loader.pitch = module.pitch;
    
    pitch阶段

    loader-runner/blob/master/lib/LoaderRunner.js

    获取loader提供的pitch方法:
    var fn = currentLoaderObject.pitch;
    调用pitch:
    runSyncOrAsync(fn,loaderContext,[loaderContext.remainingRequest..],callback)
    递归调用:
    iteratePitchingLoaders
    pitch阶段不进行读取资源文件(readResource),而是向loader传递了 remainingRequest,previousRequest等参数。比如在vue-style-loader仅接受了remainingRequest参数。
    
    normal阶段

    loader-runner/blob/master/lib/LoaderRunner.js

    如果 loaderContext.loaderIndex >= loaderContext.loaders.length,进入normal阶段
    根据loaderContext.resourcePath读取资源内容:
        options.readResource(resourcePath)
        iterateNormalLoaders递归调用
    

    loader.raw = module.raw; //如果raw配置了,根据raw是否转为buffer
    runSyncOrAsync方法是真正调用loader的api并完成转换的地方:

    function runSyncOrAsync(fn, context, args, callback) {
        ......
        try {
          var result = (function LOADER_EXECUTION() {
              return fn.apply(context, args);
            }());
        } catch(e) {......}
    }
    

    结束之后通过层层回调,回到normalModule.js的runLloader的回调函数处,紧接着把转译之后内容复制给模块的_source属性,然后调用模块源码的解析,分析资源依赖:

    this.parser.parse(this._source.source(), {
      current: this,
      module: this,
      compilation: compilation,
      options: options
    });
    

    根据资源类型使用对应的loader,直至make结束

  • 相关阅读:
    一点技巧
    题解G
    WA七次,疯了》》》》》OTZ
    就是过不了啊无奈。。。。。水题都过不了…………OTZ OTZ OTZ
    [IOS]使用UIScrollView和UIPageControl显示半透明帮助蒙板
    [System]几种同步方式
    [Objective C] Singleton类的一个模版
    [IOS] 自定义AlertView实现模态对话框
    [IOS] UIKit Animation
    [IOS]使用genstrings和NSLocalizedString实现App文本的本地化
  • 原文地址:https://www.cnblogs.com/walkermag/p/zhu-yao-yuan-ma.html
Copyright © 2020-2023  润新知