Webpack入门,自定义loader

有时开发者会遇到现有loader无法很好满足需求的情况,这时就需要对其进行修改,或者编写新的loader。

下面以一个简单的示例,讲解以下如何实现一个loader。

需求

实现一个loader,为所有JS文件启用严格模式。也就是说,它会在文件头部加上“use strict”。

创建一个force-strict-loader目录,然后在该目录下执行npm初始化命令。npm init -y

接着创建index.js,也就是loader的主体。

module.exports = function (content) {
  var useStrictPrefix = "'use strict';\n\n";
  return useStrictPrefix + content;
};

现在就可以在Webpack工程中安装并使用这个loader了。

npm install <path-to-loader>/force-strict-loader -D

在Webpack工程目录下使用相对路径安装,会在项目的node_modules中创建一个指向实际force-strict-loader目录的软链,也就是说之后开发者可以随时修改loader源码并且不需要重复安装了。

下面修改Webpack配置。

// webpack.config.js
module.exports = {
  ...
  module: {
    rules: [{
      test: /\.js$/,
      use: 'force-strict-loader'
    }]
  }
}

上面的配置为对所有JS文件生效。此时对该工程进行打包,应该可以看到JS文件的头部都已经加上了启用严格模式的语句。

当文件输入和其依赖没有发生变化时,应该让loader直接使用缓存,而不是重复进行转换的工作。在Webpack中可以使用this.cacheable进行控制,修改自定义的loader。

// force-strict-loader/index.js
module.exports = function(content) {
  if(this.cacheable) {
    this.cacheable();
  }
  var useStrictPrefix = "\'use strict\';\n\n";
  return useStrictPrefix + content;
}

通过启用缓存可以加快Webpack打包速度,并且可保证相同的输入产生相同的输出。

在之前的文章讲过,loader的配置项通过use.options传进来。就是说,在工程配置文件中配置了loader的options对象。

// webpack.config.js
module.exports = {
  ...
  module: {
    rules: [{
      test: /\.js$/,
      use: {
        loader: 'force-strict-loader',
        options: {
          sourceMap: true,
        }
      }
    }]
  }
}

上面的配置为force-strict-loader传入了一个配置项sourceMap。要在loader中获取,需要在force-strict-loader中安装一个依赖库loader-utils,它主要用于提供一些帮助函数。在force-strict-loader目录下执行以下命令。

npm install loader-utils -D

接着更改loader。

// force-strict-loader/index.js
var loaderUtils = require("loader-utils");
module.exports = function(content) {
  if(this.cacheable) {
    this.cacheable();
  }
  // 获取和打印options
  var options = loaderUtils.getOptions(this) || {};
  console.log("options",options);
  // 处理content
  var useStrictPrefix = "'use strict\';\n\n";
  return useStrictPrefix + content;
}

通过loaderUtils.getOptions可以获取到配置对象。

开启source-map可以便于开发者在浏览器的开发者工具中查看源码。在上面的示例中,工程配置已开启source-map,但是在force-strict-loader中没有对source-map进行处理,这样会使Webpack无法生成正确的map文件。需要修改force-strict-loader。

// force-strict-loader/index.js
var loaderUtils = require("loader-utils");
var SourceNode = require("source-map").SourceNode;
var SourceMapConsumer = require("source-map").SourceMapConsumer;
module.exports = function(content,sourceMap) {
  var useStrictPrefix = "\'use strict\';\n\n";
  if(this.cacheable) {
    this,cacheable();
  }
  // source-map
  var options = loaderUtils.getOptions(this) || {};
  if (options.sourceMap && sourceMap) {
    var currentRequest = loaderUtils.getCurrentRequest(this);
    var node = SourceNode.fromStringWithSourceMap(content,new SourceMapConsumer(sourceMap));
    node.prepend(useStrictPrefix);
    var result = node.toStringWithSourceMap({file:currentRequest});
    var callback = this.async();
    callback(null,result.code,result.map.toJSON());
  }
  // 不支持source-map情况
  return useStrictPrefix + content;
}

首先,在loader函数的参数中获取到sourceMap对象,这时由Webpack或者上一个loader传递下来的,只有当它存在时loader才能进行继续处理和向下传递。

之后通过source-map这个库来对map进行操作,包括接收和消费之前的文件内容和source-map,对内容节点进行修改,最后产生新的source-map。

在函数返回的时候要使用this.async获取callback函数(主要是为了一次性返回多个值)。callback函数的3个参数分别是抛出的错误、处理后的源码,以及source-map。

示例代码库

https://gitee.com/zero_79152105/webpack-vblog

原创文章,作者:ZERO,如若转载,请注明出处:https://www.edu24.cn/course/webpack-custom-loader.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
ZEROZERO
上一篇 2022年11月23日
下一篇 2022年11月24日

相关推荐

  • 两栏布局之左侧固定,右侧自适应的实现方法

    实现左侧固定,右侧自适应的两栏布局的方法有很多。其中经常用到的有float方法、BFC方法、CSS3的flex布局及grid布局。并非所有的布局都会在开发中使用,但是其中也会涉及一些知识点。

    2018年10月13日
    2.7K
  • Java自学之泛型

    在Java语言中,为了方便接收参数类型的统一,提供了核心类Object,利用此类对象可以接收所有类型的数据(包括基本数据类型和引用数据类型)。但是由于其所描述的数据范围过大,所以在…

    2020年12月8日
    1.4K
  • Angular环境搭建(Windows 10)

    目前前端开发正处于快速发展阶段,接触angular时,Angular 2刚刚发布,现在第五版也已经发布。由于刚开始没有系统的学习,导致工作中,经常捉襟见肘。现在把自己在工作中踩过的…

    2018年9月5日
    4.2K
  • 函数防抖与函数节流

    函数防抖 定义 触发高频事件后 n 秒内函数只会执行一次,如果 n 秒内高频事件再次被触发,则重新计算时间;更直白一点就是:一个需要频繁触发的函数,在规定时间内,只让最后一次生效,…

    2020年7月17日
    1.5K
  • JavaScript 事件委托详解

    基本概念 事件委托,通俗地来讲,就是把一个元素响应事件(click、keydown……)的函数委托到另一个元素; 一般来讲,会把一个或者一组元素的事件委托到…

    2021年3月8日
    1.2K
  • 从零开始开发vue组件库

    前言 很早之前,就有开发一套vue组件库的想法,直到现在想法依旧只是想法。汗颜啊……此篇文章将讲述如何开发vue组件库,虽然文章标题为《从零开始开发vue组件库》,实际上是从搭建v…

    2024年6月23日
    771
  • MyBatis配置之枚举类型typeHandler讲解(上)

    之前发布了一篇《MyBatis配置之typeHandler类型处理器》的文章,讲解了在使用MyBatis时如何自定义typeHandler。但是在MyBatis中枚举类型的type…

    2022年4月21日
    963
  • 如何封装VUE组件库?

    之前一直在使用Angular开发项目,也封装过Angular组件。由于种种原因,现需要转战VUE。好在本人有扎实的实战经验,结合各位网络大神整理的经验,现总结一篇关于封装VUE组件…

    2019年7月31日
    2.4K
  • MyBatis配置之typeHandler类型处理器

    typeHandler类型处理器作用 MyBatis在预处理语句(PreparedStatement)中设置一个参数时,或者从结果集(ResultSet)中取出一个值时,都会用注册…

    2022年4月20日
    1.2K
  • Webpack入门,预处理器

    一个Web工程通常会包含HTML、JS、CSS、图片、字体等多种类型的静态资源,且这些资源之间都存在着某种联系。对于Webpack来说,所有这些静态资源都是模块,开发者可以像加载一…

    2022年11月21日
    764