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日

相关推荐

  • MySQL数据库入门之单表数据记录查询

    简单数据查询 语法形式如下: 在上述语句中,参数fieldn表示所要查询的字段名字,参数table_name表示所要查询数据记录的表名。 当需要查询表中所有字段时,可使用&#822…

    2020年7月15日
    1.5K
  • MyBatis配置之typeHandler类型处理器

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

    2022年4月20日
    1.2K
  • Spring Boot的常用注解

    未来的框架趋势是“约定大于配置”,代码的封装会更加严密。开发人员会将更多的精力放在代码的整体优化和业务逻辑上,所以注解式编程会被更加广泛地使用。那么什么是注解?Spring Boo…

    2024年8月29日
    485
  • Webpack入门,模块打包原理分析

    面对工程中成百上千个模块,Webpack究竟是如何将它们有序地组织在一起,并按照开发者预想的顺序运行在浏览器上的呢?本篇文章将通过一个简单的示例。分析一下Webpack模块打包的原…

    2022年11月14日
    865
  • 外层有一个自适应高度的div,里面有两个div,一个高度固定300px,另一个怎么填满剩余的高度?

    可以设置外层自适应高度的容器为flex布局,利用flex-basis属性即可实现自动填满剩余高度;代码如下:

    2021年2月22日
    1.4K
  • JAVA基础知识整理

    终于下定决心2020年转JAVA开发,自学之路坎坷曲折。俗话说的话,好记性不如烂笔头。如果有小伙伴们也像我一样在JAVA自学之路上徘徊,那就关注一下我的博客网站。我会不定期更新一下…

    2020年1月11日
    1.8K
  • Java自学之泛型

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

    2020年12月8日
    1.4K
  • 一维数组结构数据转换树形结构数据JS方法

    在写小程序项目时,自定义了一个组织机构树形展示组件,后端接口返回的组织机构数据是一维数组。需要在前端转换成树形结构的数据,并且添加一些节点的树形,比如是否为叶子节点,节点是否展开等…

    2022年11月10日
    532
  • Vue项目中实现用户登录及token验证

    在前后端完全分离的情况下,Vue项目中实现token验证大致思路如下: 第一次登录的时候,前端调后端的登陆接口,发送用户名和密码 。 后端收到请求,验证用户名和密码,验证成功,就给…

    2019年8月8日
    5.2K
  • 深入理解JS原型和继承

    在学习JS中的原型,原型链,继承这些知识之前,必须先了解并掌握基础知识:函数和对象的关系。 我们一直都知道,函数也是对象的一种,因为通过instanceof就可以判断出来。但是函数…

    2019年6月29日
    2.3K