webpack - 自定义loader

自定义loader基本方法,节选自 webpack实战。

 

1、loader初始化

如果已知loader无法满足我们的需求的时候,就需要动手开发一个定制的loader,我们将实现一个loader:它会为所有的JS文件启用严格模式,也就是说它会在文件头部加上如下代码:

"use strict";
  1. 创建一个force-strict-loader目录,然后在该目录下执行npm初始化命令。npm init -y
  2. 创建index.js,也就是loader的主体
    module.exports = function(content){
      var useStrictPrefix = '\'use strict\'; \n\n';
      return useStrictPrefix + content;   
    }

    现在我们可以在webpack工程中安装并使用这个loader了

  3. npm install <path-to-loader>/force-strict-loader;在webpack工程目录下使用相对路径安装,会在项目的node_modules中创建一个指向实际force-strict-loader目录的软链,也就是说之后我们可以随时修改loader源码并且不需要重复安装了
  4. 修改webpack配置
    module: {
      rules:[
        {
            test: /\.js$/,
            use: 'force-strict-loader'  
        }  
      ]  
    }

    我们将这个loader设置为对所有js文件生效,此时对该工程进行打包,应该可以看到js文件的头部都已经加上了启用严格模式的语句。

 

2、启用缓存

  当文件输入和其依赖没有发生变化时,应该让loader直接使用缓存。在webpack中可以使用this.cacheable进行控制,修改我们的loader。

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

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

 

3、获取options

    loader的配置项通过use.options传进来,如:

{
            test: /\.js$/,
            use: [
                
                {
                    loader: 'force-strict-loader',
                    options: {
                        sourceMap: true
                    }
                },
            ],
        }

    下面我们在loader中获取它

    需要先安装一个依赖库 "loader-utils" 

// force-strict-laoder/index.js
var
loaderUtils = require('loader-utils'); module.exports = (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可以获取到配置对象,这里我们只是把它打印了出来。

 

4、实现Soure-Map

  source-map可以便于实际开发者在浏览器控制台查看源码。如果没有对source-map进行处理,最终也就无法生成正确的map文件,在浏览器的dev tool中可能就会看到错讯的源码。

下面是支持了source-map特性后的版本:

var loaderUtils = require('loader-utils');
var SourceNode = require('source-map').SourceNode;
var SourceMapConsumer = require('source-map').SourceMapConsumer;
module.exports = (content, sourceMap) => {
    var useStrictPrefix = '\'use strict\'\n\n';
    if(this.cacheable){
        this.cacheable();
    }
    
    // 获取和打印 options
    var options = loaderUtils.getOptions(this) || {}
    console.log('options', options);
    // source-map
    if(options.sourceMap && sourceMap){
        var currentRequest = loaderUtils.getCurrentRequest(this);
        var node = SourceNode.fromStringWithSourceMap(content, new SourceMapConsumer);
    }
    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。

posted on 2020-07-18 16:15  KyleLjc  阅读(1467)  评论(0编辑  收藏  举报

导航