版本

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:

经过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结束

最新文章

  1. JAAS 是个什么梗
  2. ffmpeg 安装,转视频格式为m3u8,压缩视频
  3. MySQL复制环境(主从/主主)部署总结性梳理
  4. margin-top无效的解决方法
  5. 我常用的delphi 第三方控件
  6. struts2指定集合元素的泛型
  7. BZOJ_1607_ [Usaco2008_Dec]_Patting_Heads_轻拍牛头_(筛数)
  8. 分享注册AltiumDesignerLive官网账号注册方法教程
  9. 轻松搞定Ajax(分享下自己封装ajax函数,其实Ajax使用很简单,难是难在你得到数据后来怎样去使用这些数据)
  10. unity3d由于Camera.main.transform报空引用错误的解决方案
  11. Linux的proc文件系统
  12. 一道js题
  13. Zepto.js-表单方法
  14. Linux常见命令(四)——mkdir
  15. anaconda安装qt错误
  16. Alpine Linux常用命令
  17. 分布式计算框架Spark
  18. flex布局下, 内容改变 不重新渲染问题
  19. 2016年,谁是最受欢迎的 Java EE 服务器?
  20. [转帖]SAP MES生产执行系统解决方案

热门文章

  1. 3.kubernetes的CNI网络插件-Flannel
  2. git 的使用:
  3. RockeMQ安装与入门
  4. Linux 集群安装zookeeper
  5. 尚硅谷maven视频教程笔记
  6. java scoket Blocking 阻塞IO socket通信一
  7. dart快速入门教程 (3)
  8. vue全家桶(3.2)
  9. java中执行cmd命令
  10. JavaScript图形实例:递归生成树