• 译文 编写一个loader


    https://doc.webpack-china.org/contribute/writing-a-loader

      loader是一个导出了函数的node模块,当资源须要被这个loader所转换的时候,这个函数就会被执行,这个函数可以通过this访问loader api。有三种方式来本地开发和测试loader。

    设置

      测试一个单独的loader,可以通过path.resolve一个本地文件来加载loader:

    {
      test: /.js$/
      use: [
        {
          loader: path.resolve('path/to/loader.js'),
          options: {/* ... */}
        }
      ]
    }

      测试多个loader的话,可以通过以下方式来添加webpack对loader的搜索路径:

    resolveLoader: {
      modules: [
        'node_modules',
        path.resolve(__dirname, 'loaders')
      ]
    }

      第三种方式:通过 npm link 从仓库中引入loader包进我们的项目中

    简单用法

      当一个loader被调用时,被导出的函数会被执行,它有一个字符串参数,代表了文件的内容。函数应该返回一个或两个值,分别代表字符串js代码和一个可选的js对象sourceMap,对于复杂的情况,可以调用 this.callback(err, values...) 来返回两个以上的值,里面的err可以直接抛出或者传递给callback都可以,返回一个值时直接return 即可

    复杂用法

      对于loader的链式调用,他们的调用次序是从后往前或者从下往上,loader接收上一个loader的处理结果作为参数

    loader的书写方针

    简单

      loader做单一简单的工作,这有利于使每个loader变得简单,而且使他们更方便地链式调用

    链式调用

      使用loader可以被链式调用的优势,把一个任务分成多个简单步骤,让每个简单的loader分别去完成。

    模块化

      使输出变得模块化。

    无状态

      保证loader每次运行仅仅依赖于上一个loader的输出结果

    loader的依赖

      如果一个loader须要读取外部的资源(如读取文件系统),则必须进行依赖声明(使用addDependency),这是为了在观察模式下使缓存无效以及重新编译

    import path from 'path';
    
    export default function(source) {
      var callback = this.async();
      var headerPath = path.resolve('header.js');
    
      this.addDependency(headerPath);
    
      fs.readFile(headerPath, 'utf-8', function(err, header) {
        if(err) return callback(err);
        callback(null, header + "
    " + source);
      });
    };

    模块内的依赖

      对于不同类型的模块,有不同的处理依赖的方式,如css,@import和url(...)会引入依赖,这些依赖须要被模块系统来处理,这有两种进行处理:

    1. 转换为require
    2. 使用this.resolve函数处理路径

      对于第一种方式,css-loader是一个好例子;而对less,不能仅仅对import或url()进行require替换,因为less须要被编译,所以less-loader须要使用第二种方式,通过webpack来处理依赖

    抽取模块内的公共代码

      使用loader对模块进行处理时,避免生成公共代码,可以在loader进行处理的时候,生成一个运行时文件,然后通过require实现模块之间的代码共享,而不是在每个模块中都重复生成相同的代码

    绝对路径

      不要在模块代码中使用绝对路径,因为当根目录发生变化(项目迁移),文件的hash会发生变化,在loader-utils中有一个函数stringifyRequest可以将绝对路径转为相对路径

    peer 依赖

      可以把对其他包的依赖作为一个perrDependency,如sass-loader依赖于node-sass:

    "peerDependencies": {
      "node-sass": "^4.0.0"
    }

    测试

      使用jest对loader进行测试

    npm i --save-dev jest babel-jest babel-preset-env

     .babelrc

    {
      "presets": [[
        "env",
        {
          "targets": {
            "node": "4"
          }
        }
      ]]
    }

     创建一个src/loader.js实现功能:处理一个txt文件,将里面的[name]替换为options里的name值。返回将结果作为一个模块返回

    import { getOptions } from 'loader-utils';
    
    export default function loader(source) {
      const options = getOptions(this);
    
      source = source.replace(/[name]/g, options.name);
    
      return `export default ${ JSON.stringify(source) }`;
    };

    要处理的文件test/example.txt如下:

    Hey [name]!

     下一步是使用nodeApimemory-fs来启动webpack,这可以让我们把生成的文件提交到内存中,还可以获取文件stats数据。下面进行安装:

    npm i --save-dev webpack memory-fs

    test/compiler.js

    import path from 'path';
    import webpack from 'webpack';
    import memoryfs from 'memory-fs';
    
    export default (fixture, options = {}) => {
      // 生成一个webpack实例
      const compiler = webpack({
        context: __dirname,
        // 这里的entry实际会被替换为要处理的文件,entry可以理解为是第一个要被处理的文件
        entry: `./${fixture}`, 
        output: {
          path: path.resolve(__dirname),
          filename: 'bundle.js',
        },
        module: {
          rules: [{
            test: /.txt$/,
            use: {
              loader: path.resolve(__dirname, '../src/loader.js'),
              options: {
                name: 'Alice'
              }
            }
          }]
        }
      });
      
      // 将webpack的输出文件设置到内存中  
      compiler.outputFileSystem = new memoryfs();
     
      // webpack 的run接收的函数的第二个参数代表webpack输出的文件信息
      return new Promise((resolve, reject) => {
        compiler.run((err, stats) => {
          if (err) reject(err);
    
          resolve(stats);
        });
      });
    }

     开始进行测试,执行 test/loader.test.js

    import compiler from './compiler.js';
    
    test('Inserts name and outputs JavaScript', async () => {
      // 这里指定的被测试文件会被替换为以上的entry文件
      const stats = await compiler('example.txt');
      const output = stats.toJson().modules[0].source;
    
      expect(output).toBe(`export default "Hey Alice!\n"`);
    });
  • 相关阅读:
    软件行业从事人员,计算机基础须知(三)---DOS命令相关
    软件行业从事人员,计算机基础须知(二)---系统介绍和进制转换说明
    软件行业从事人员,计算机基础须知(一)
    python操作数据库步骤以及操作过程中经常出现的异常
    selenium中验证码识别简单封装
    selenium对验证码识别校验解决方法
    retina屏幕截取验证码
    Nginx的负载均衡的那点事
    子网划分
    iptables 规则整理
  • 原文地址:https://www.cnblogs.com/hellohello/p/8135447.html
Copyright © 2020-2023  润新知