webpack系列学习-loader编写
字节爱好者 613 5

前言:笔者把学习的webpack知识从基础到原理写个系列,以便回顾。希望能帮助到更多正在学习webpack的小伙伴。

webpack系列学习-初体验

webpack系列学习-基本用法一

webpack系列学习-各种loader使用

webpack系列学习-热更新和压缩

webpack系列学习-使用eslint和发布npm包

webpack系列学习-构建webpack配置

webpack系列学习-详细的实现简易webpack

定义

loader只是一个导出为函数的js模块

结构

一个最简单的loader代码结构:

module.exports = function(source){
  return source;
}

多个loader执行顺序

执行顺序是串行执行,从右向左

通过一个例子进行验证loader执行顺序

  • 1.在webpack.config.js中先后配置a-loader和b-loader
    // webpack.config.js
    const path = require('path');
    

module.exports = { entry: './src/index.js', output: { path: path.join(__dirname, 'dist'), filename: 'main.js', }, module: { rules: [ { test: /.js$/, use: [path.resolve('./loaders/a-loader.js'), path.resolve('./loaders/b-loader.js')], }, ], }, };

+ 2.分别写下a-loader.js和b-loader.js
```js

// a-loader.js
module.exports = function a(source) {
  console.log('loader a is used;');
  return source;
};

// b-loader.js
module.exports = function b(source) {
  console.log('loader b is used;');
  return source;
};
  • 3.运行web pack,可以看出先打印了b,再打印了a webpack系列学习-loader编写

loader调试利器:loader-runner

定义:

loader-runner 允许在不安装webpack的情况下运行loaders

作用:

作为webpack的依赖,webpack中使用它执行loader,进行loader的开发和调试

loader-runner的使用

import { runLoaders } from "loader-runner";

runLoaders({
  resource: "/abs/path/to/file.txt?query",
  // String: 资源的绝对路径(可以增加查询字符串)
  loaders: ["/abs/path/to/loader.js?query"],
  // String[]: loader的绝对路径(可以增加查询字符串)
  context: { minimize: true },
  // 基础上下文之外的额外loader上下文
  readResource: fs.readFile.bind(fs)
  // 读取资源的函数
}, function(err, result) {
  // err: Error?
})

下面使用loader-runner开发一个raw-loader(将一个文件内容转换为string)

1.编写raw-loader和测试用例


// src/raw-loader.js
module.exports = function (source) {
  const json = JSON.stringify(source)
    .replace(/\u2028/g, '\\u2028')
    .replace(/\u2029/g, '\\u2029');

  return `export default ${json}`;
};

// src/demo.txt
aaa

2.使用run-loader


// /run-loader.js
const { runLoaders } = require('loader-runner');
const fs = require('fs');
const path = require('path');

runLoaders(
  {
    resource: path.join(__dirname, './src/demo.txt'),
    loaders: [path.join(__dirname, './src/raw-loader.js')],
    context: {
      minimize: true,
    },
    readResource: fs.readFile.bind(fs),
  },
  (err, res) => {
    err ? console.log(err) : console.log(res);
  }
);

3.运行node run-loader.js,可以看出结果

webpack系列学习-loader编写

获取loader参数

使用loader-utils包。先安装下。

npm i loader-utils -S

在run-loader.js中引入一个参数,如下:


loaders: [
      {
        loader: path.join(__dirname, './src/raw-loader.js'),
        options: {
          name: 'test',
        },
      },
    ],

接着在raw-loader.js中使用loader-utils获取参数

const loaderUtils = require('loader-utils');
module.exports = function (source) {
  const { name } = loaderUtils.getOptions(this);
  console.log(name);
  const json = JSON.stringify(source)
    .replace(/\u2028/g, '\\u2028')
    .replace(/\u2029/g, '\\u2029');

  return `export default ${json}`;
};

打印下name,查看结果 webpack系列学习-loader编写

loader的异常处理

1.loader内直接通过throw抛出

2.通过this.callback传递错误


this.callback(
  err: Error | null,
  content: string | Buffer,
  sourceMap?: SourceMap,
  meta?: any
)

如何开发一个异步的loader

通过 this.async来返回一个异步函数。第一个参数是Error, 第二个参数是处理的结果


const fs = require('fs');
const path = require('path');
module.exports = function (source) {
  const callback = this.async();

  fs.readFile(path.join(__dirname, './async.txt'), 'utf-8', (err, data) => {
    callback(null, data);
  });
};

运行打印,可以看到是异步结果 webpack系列学习-loader编写

在loader中使用缓存:

1.webpack中默认开启loader缓存,可以使用this.cacheable(false)关闭缓存

2.缓存条件:loader的结果在相同的输入下有确定的输出。有依赖的loader无法使用缓存。 webpack系列学习-loader编写

评论区

索引目录