webpack源码之loader机制详解


Posted in Javascript onApril 06, 2018

loader概念

loader是用来加载处理各种形式的资源,本质上是一个函数, 接受文件作为参数,返回转化后的结构。

loader 用于对模块的源代码进行转换。loader 可以使你在 import 或"加载"模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的强大方法。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件!

loader和plugin区别

之前一篇文章中介绍了plugin机制,和今天研究的对象loader,他们两者在一起极大的拓展了webpack的功能。它们的区别就是loader是用来对模块的源代码进行转换,而插件目的在于解决 loader 无法实现的其他事。为什么这么多说呢?因为plugin可以在任何阶段调用,能够跨Loader进一步加工Loader的输出,在构建运行期间,触发事件,执行预先注册的回调,使用compilation对象做一些更底层的事情。

loader用法

配置

module: {
  rules: [
   {
    test: /\.css$/,
    use: [
     { loader: 'style-loader' },
     {
      loader: 'css-loader'
     }
    ]
   }
  ]
 }

内联

import Styles from 'style-loader!css-loader?modules!./styles.css';

CLI

webpack --module-bind 'css=style-loader!css-loader'

说明 上面三种使用方法作用都是将一组链式的 loader, 按照从右往左的顺序执行,loader 链中的第一个 loader 返回值给下一个 loader。先使用css-loader解析 @import 和 url()路径中指定的css内容,然后用style-loader 会把原来的 CSS 代码插入页面中的一个 style 标签中。

loader实现

//将css插入到head标签内部
module.exports = function (source) {
  let script = (`
   let style = document.createElement("style");
   style.innerText = ${JSON.stringify(source)};
   document.head.appendChild(style);
  `);
  return script;
}
//使用方式1
resolveLoader: {
  modules: [path.resolve('node_modules'), path.resolve(__dirname, 'src', 'loaders')]
},
{
  test: /\.css$/,
  use: ['style-loader']
},
//使用方式2
//将自己写的loaders发布到npm仓库,然后添加到依赖,按照方式1中的配置方式使用即可

说明 上面是一个简单的loader实现,同步的方式执行,相当于实现了style-loader的功能。

loader原理

function iteratePitchingLoaders(options, loaderContext, callback) {
  var currentLoaderObject = loaderContext.loaders[loaderContext.loaderIndex];
  // load loader module
  loadLoader(currentLoaderObject, function(err) {
    var fn = currentLoaderObject.pitch;
    runSyncOrAsync(
      fn,
      loaderContext, [loaderContext.remainingRequest, loaderContext.previousRequest, currentLoaderObject.data = {}],
      function(err) {
        if(err) return callback(err);
        var args = Array.prototype.slice.call(arguments, 1);
        if(args.length > 0) {
          loaderContext.loaderIndex--;
          iterateNormalLoaders(options, loaderContext, args, callback);
        } else {
          iteratePitchingLoaders(options, loaderContext, callback);
        }
      }
    );
  });
}

说明 上面是webpack源码中loader执行关键步骤,递归的方式执行loader,执行机流程似于express中间件机制

参考源码

  1. webpack: "4.4.1"
  2. webpack-cli: "2.0.13"

参考文档
https://webpack.js.org/concepts/loaders/

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
在一个form用一个SUBMIT(或button)分别提交到两个处理表单页面的代码
Feb 15 Javascript
将string解析为json的几种方式小结
Nov 11 Javascript
jqgrid 表格数据导出实例
Nov 21 Javascript
JavaScript中的原型和继承详解(图文)
Jul 18 Javascript
JavaScript如何调试有哪些建议和技巧附五款有用的调试工具
Oct 28 Javascript
用JavaScript来美化HTML的select标签的下拉列表效果
Nov 17 Javascript
JS获取屏幕高度的简单实现代码
May 24 Javascript
jquery实现折叠菜单效果【推荐】
Mar 08 Javascript
详解react-router如何实现按需加载
Jun 15 Javascript
layui点击按钮添加可编辑的一行方法
Aug 15 Javascript
了解JavaScript函数中的默认参数
May 30 Javascript
原生Vue 实现右键菜单组件功能
Dec 16 Javascript
vue.js项目nginx部署教程
Apr 05 #Javascript
常用的 JS 排序算法 整理版
Apr 05 #Javascript
通过 JS 判断页面是否有滚动条的实现方法
Apr 05 #Javascript
mint-ui在vue中的使用示例
Apr 05 #Javascript
webpack热模块替换(HMR)/热更新的方法
Apr 05 #Javascript
详解Vue基于 Nuxt.js 实现服务端渲染(SSR)
Apr 05 #Javascript
express默认日志组件morgan的方法
Apr 05 #Javascript
You might like
经典的星际争霸,满是回忆的BGM
2020/04/09 星际争霸
PHP一些常用的正则表达式字符的一些转换
2008/07/29 PHP
PHP 正则表达式常用函数
2014/08/17 PHP
ThinkPHP查询返回简单字段数组的方法
2014/08/25 PHP
php生成excel列名超过26列大于Z时的解决方法
2014/12/29 PHP
PHP和Shell实现检查SAMBA与NFS Server是否存在
2015/01/07 PHP
详解PHP+AJAX无刷新分页实现方法
2015/11/03 PHP
PHP开发中常用的十个代码样例
2016/02/02 PHP
php加密解密字符串示例
2016/10/13 PHP
JavaScript 异步方法队列链实现代码分析
2010/06/05 Javascript
nodejs实现黑名单中间件设计
2014/06/17 NodeJs
浅析Node.js中的内存泄漏问题
2015/06/23 Javascript
JavaScript获取各大浏览器信息图示
2015/11/20 Javascript
jQuery Timelinr实现垂直水平时间轴插件(附源码下载)
2016/02/16 Javascript
实现点击下箭头变上箭头来回切换的两种方法【推荐】
2016/12/14 Javascript
vue子组件使用自定义事件向父组件传递数据
2017/05/27 Javascript
详解webpack分包及异步加载套路
2017/06/29 Javascript
jQuery+Ajax请求本地数据加载商品列表页并跳转详情页的实现方法
2017/07/12 jQuery
EasyUI创建人员树的实例代码
2017/09/15 Javascript
node.js中http模块和url模块的简单介绍
2017/10/06 Javascript
JS选取DOM元素常见操作方法实例分析
2018/12/10 Javascript
layui关闭弹窗后刷新主页面和当前更改项的例子
2019/09/06 Javascript
Vue如何基于es6导入外部js文件
2020/05/15 Javascript
在Python中使用异步Socket编程性能测试
2014/06/25 Python
python实现JAVA源代码从ANSI到UTF-8的批量转换方法
2015/08/10 Python
python 实现求解字符串集的最长公共前缀方法
2018/07/20 Python
Django框架模板文件使用及模板文件加载顺序分析
2019/05/23 Python
python分数表示方式和写法
2019/06/26 Python
解决django 新增加用户信息出现错误的问题
2019/07/28 Python
python实现LRU热点缓存及原理
2019/10/29 Python
将数据集制作成VOC数据集格式的实例
2020/02/17 Python
Strawberrynet草莓网新加坡站:护肤、彩妆、香水及美发产品
2018/08/31 全球购物
Brother加拿大官网:打印机、贴标机、缝纫机
2019/10/09 全球购物
教育基金募捐倡议书
2014/05/14 职场文书
七一党日活动总结
2014/07/08 职场文书
市场营销专业毕业生求职信
2014/07/21 职场文书