绝大多数人都在使用 webpack 作为构建工具。那么 loader 作为处理各种资源的工具,大家肯定也不会陌生。很多人没写过 loader,但是都对 loader 的具体怎么写,怎样执行的一无所知。那么本文就对 3.0.0 版本做一个全方位的揭秘。

loader

所谓 loader 只是一个导出为函数的 JavaScript 模块。它接收上一个 loader 产生的结果或者资源文件(resource file)作为入参。也可以用多个 loader 函数组成 loader chain。compiler 需要得到最后一个 loader 产生的处理结果。这个处理结果应该是 String 或者 Buffer(被转换为一个 string)。具体的用法,可以看 Loader 官网的描述。接下来我们从源码的角度去分析,为什么可以这样做,为什么可以实现同异步钩子,内部到底是怎么实现的。那么这就是 loader-runner 的作用所在。

入口

loader-runner 是一个独立出去的 npm 包,它的入口在 lib/LoaderRunner.js

exports.runLoaders = function runLoaders(options, callback) {// read optionsvar resource = options.resource || ""; // loaders 处理的资源var loaders = options.loaders || []; // loaders 配置var loaderContext = options.context || {}; // 所有 loaders 共享的数据var readResource = options.readResource || readFile; // 文件输入系统//var splittedResource = resource && splitQuery(resource);var resourcePath = splittedResource ? splittedResource[0] : undefined; // 资源路径var resourceQuery = splittedResource ? splittedResource[1] : undefined; // 资源的 queryvar contextDirectory = resourcePath ? dirname(resourcePath) : null; // 资源的目录// execution statevar requestCacheable = true; // 缓存的标识位var fileDependencies = []; // 文件依赖的缓存var contextDependencies = []; // 目录依赖的缓存// prepare loader objectsloaders = loaders.map(createLoaderObject); // 处理 loaders 的若干属性// loaderContext 是在所有 loaders 处理资源时候共享的一份数据// loaderIndex 是一个指针,它控制了所有 loaders 的 pitch 与 normal 函数的执行loaderContext.context = contextDirectory;loaderContext.loaderIndex = 0;loaderContext.loaders = loaders;loaderContext.resourcePath = resourcePath;loaderContext.resourceQuery = resourceQuery;loaderContext.async = null; // 为了实现异步 loader 的闭包函数loaderContext.callback = null; // 为了实现同步或者异步 loader 的闭包函数loaderContext.cacheable = function cacheable(flag) {if(flag === false) {requestCacheable = false;}};loaderContext.dependency = loaderContext.addDependency = function addDependency(file) {fileDependencies.push(file);};loaderContext.addContextDependency = function addContextDependency(context) {contextDependencies.push(context);};loaderContext.getDependencies = function getDependencies() {return fileDependencies.slice();};loaderContext.getContextDependencies = function getContextDependencies() {return contextDependencies.slice();};// 清除所有缓存loaderContext.clearDependencies = function clearDependencies() {fileDependencies.length = 0;contextDependencies.length = 0;requestCacheable = true;};// 这些 getter/setter 都是为了在 loader 函数里面通过 this 求值能动态得到对应的值Object.defineProperty(loaderContext, "resource", {enumerable: true,get: function() {if(loaderContext.resourcePath === undefined)return undefined;return loaderContext.resourcePath + loaderContext.resourceQuery;},set: function(value) {var splittedResource = value && splitQuery(value);loaderContext.resourcePath = splittedResource ? splittedResource[0] : undefined;loaderContext.resourceQuery = splittedResource ? splittedResource[1] : undefined;}});Object.defineProperty(loaderContext, "request", {enumerable: true,get: function() {return loaderContext.loaders.map(function(o) {return o.request;}).concat(loaderContext.resource || "").join("!");}});Object.defineProperty(loaderContext, "remainingRequest", {enumerable: true,get: function() {if(loaderContext.loaderIndex >= loaderContext.loaders.length - 1 && !loaderContext.resource)return "";return loaderContext.loaders.slice(loaderContext.loaderIndex + 1).map(function(o) {return o.request;}).concat(loaderContext.resource || "").join("!");}});Object.defineProperty(loaderContext, "currentRequest", {enumerable: true,get: function() {return loaderContext.loaders.slice(loaderContext.loaderIndex).map(function(o) {return o.request;}).concat(loaderContext.resource || "").join("!");}});Object.defineProperty(loaderContext, "previousRequest", {enumerable: true,get: function() {return loaderContext.loaders.slice(0, loaderC

webpack 之 LoaderRunner 全方位揭秘相关推荐

  1. 一款APP从设计稿到切图过程全方位揭秘 Mark

    纯干货!一款APP从设计稿到切图过程全方位揭秘 @BAT_LCK :我本身是一名GUI设计师,所以我只站在GUI设计师的角度去把APP从项目启动到切片输出的过程写一写,相当于工作流程的介绍吧.公司不同 ...

  2. 一款APP从设计稿到切图过程全方位揭秘(IOS版)

    9月17日凌晨,IOS9正式推送,它使用的字体最终还是变了,我下面写的内容你们也要酌情更新,因为我写的实在赶不上它更新的速度了 iOS9使用的西文字体由Helvetica Neue变更为 San Fr ...

  3. 纯干货!一款APP从设计稿到切图过程全方位揭秘

    @BAT_LCK :我本身是一名GUI设计师,所以我只站在GUI设计师的角度去把APP从项目启动到切片输出的过程写一写,相当于工作流程的介绍吧.公司不同,流程不尽相同,但是终究还是能有些帮助. 依旧声 ...

  4. 一款APP从设计稿到切图过程全方位揭秘

    9月17日凌晨,IOS9正式推送,它使用的字体最终还是变了,我下面写的内容你们也要酌情更新,因为我写的实在赶不上它更新的速度了(泪奔中...) iOS9使用的西文字体由Helvetica Neue变更 ...

  5. 全方位揭秘!大数据从0到1的完美落地之大数据简介

    大数据简介 什么是大数据 ​ 最近几年,IT行业最火的名词中,少不了"大数据"."人工智能"."云计算"."物联网".& ...

  6. 全方位揭秘!大数据从0到1的完美落地之Linux二进制软件安装

    软件管理 软件安装介绍 学软件开发,各种台的软件熟练安装是必须要熟练掌握.大家都知道,Windows下安装软件时,只需用鼠标双击软件的安装程序,或者用Zip等解压缩软件解压缩即可安装:在android ...

  7. 全方位揭秘!大数据从0到1的完美落地之Linux系统目录和网络连接

    Linux目录简介 目录说明 目录 描述.说明 / Linux的根目录 /bin binaries,存放系统命令的目录,所有用户都可以执行 /sbin super user binaries,保存和系 ...

  8. 一文教你全方位揭秘Ajax指南

    Ajax初识 1.ajax的产生 ajax是前后端通信的桥梁,所以前端程序员一定要掌握Ajax这个知识点.是一种创建交互式网页应用的网页开发技术,通过在后台与服务器进行少量数据交换,AJAX可以使网页 ...

  9. 问答精选|新年特辑:全方位揭秘MeterSphere一站式开源持续测试平台

    MeterSphere新年特辑直播回放已开放观看.在本次直播中,FIT2CLOUD解决方案架构师刘宴婷详细介绍了MeterSphere产生的背景及MeterSphere的使命.架构.特点和功能.欢迎进 ...

最新文章

  1. Hacking PostgreSQL
  2. Matlab弹出窗口
  3. python爬虫程序的流程图_Python即时网络爬虫项目: 内容提取器的定义(Python2.7版本)...
  4. emacs mysql代码阅读_Emacs + etags + cscope 阅读代码
  5. 苹果设备频繁杀后台问题在iOS 13.2.2正式版更新后得以抑制
  6. 使用exp导出报错EXP-00091
  7. 阶段3 2.Spring_03.Spring的 IOC 和 DI_10 构造函数注入
  8. 每周全球科技十大新闻(2019.8.12-8.18)
  9. swiper / 移动端触摸滑动插件 / 手机轮播插件
  10. 教你删除Mac下的iCloud数据
  11. 王佩丰excel教程笔记(认识excel)
  12. 11g中hanganalyze的格式
  13. 美国队长的工资 python代码-Python入门必学,用Python练习画个美队盾牌
  14. 第二周Java学习总结
  15. IE6、IE7、IE8之IE多版本共存的几种方法(转)
  16. Java break outer和continue outer的用法
  17. MAC免费解压软件——解压RAR、7Zip等五六十种格式
  18. 关于asc、txt格式到pcd、ply格式数据转换
  19. c语言标识符的开头字母能不能大写,C语言-标识符
  20. H264码流打包分析.整理

热门文章

  1. Jmeter 证书导入
  2. pdu报头内容_发送具有分段和打包扩展报头的macpdu的装置及其方法
  3. 域名申请·多域名SSL证书申请·SSL证书认证流程·CAA解析记录添加
  4. 3种蓝牙架构实现方案(蓝牙协议栈方案)
  5. 小满nestjs(第二十八章 nestjs 事务)
  6. openSUSE 13.1 yah3c 出错 no such device
  7. python爬虫及数据可视化分析
  8. 扁平化设计学习之二 设计原则
  9. EasyTouch使用教程
  10. 手机通讯录页面html,手机通讯录怎么快速导入