如何编写一个Loader

2020-01-15  本文已影响0人  指尖跳动

创建一个demo(make_loader)

目录结构如下:

|--make_loader
    |--node_modules
    |--src
        |--index.js
    |--loaders
        |--replaceLoader.js
    |--package-lock.json
    |--package.json
    |--webpack.config.js

src/index.js中的业务代码:

 console.log('hello xiaochengzi');

在loaders/replaceLoader.js文件里书写我们的loader代码:

module.exports = function(source) { // 这里不能用箭头函数
  return source.replace('xiaochengzi', this.query.name);
}

在webpack.config.js中做loader的使用配置:

const path = require('path');
module.exports = {
  mode: 'development',
  entry: {
    main: './src/index.js'
  },
  module: {
    rules: [{
      test: /\.js/,
      use: [
        {
          loader: path.resolve(__dirname, './loaders/replaceLoader.js'),
          options: {
            name: 'world' // 传递给loader的参数
          }
        }
      ] // 使用自己写的loader模块 
    }] 
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  }
}

执行打包:npm run build

打包后的文件为:hello world
由此可见,我们在业务代码中打印的 ‘hello xiaochengzi’ 通过我们编写的loader替换成了 ‘hello world’。
到此,一个最最简单的loader就编写好了~
————————————————————

loader中常用的API

使用loader-utils分析参数:

// loader-utils模块需要单独使用npm下载安装
const loaderUtils = require('loader-utils');
module.exports = function(source) { 
  // 使用loader-utils中的getOptions接收loader参数
  const options = loaderUtils.getOptions(this);
  return source.replace('xiaochengzi', options.name);
}

callback的使用:

const loaderUtils = require('loader-utils');
module.exports = function(source) { 
  const options = loaderUtils.getOptions(this);
  const result = source.replace('xiaochengzi', options.name);
  this.callback(null, result);
}

对于callback回调函数,官方解释是这样的:



如果loader里要写一些异步的代码的时候,需要先声明:

const loaderUtils = require('loader-utils');
module.exports = function(source) { 
  const options = loaderUtils.getOptions(this);
  const callback = this.async(); // 声明一下异步操作
  setTimeout(() => {
    const result = source.replace('xiaochengzi', options.name);
    callback(null, result); // 在回调里返回结果
  }, 1000)
}

编写打包多个loader时webpack.config.js配置:

const path = require('path');
module.exports = {
  mode: 'development',
  entry: {
    main: './src/index.js'
  },
  module: {
    rules: [{
      test: /\.js/,
      use: [
        {
          loader: path.resolve(__dirname, './loaders/replaceLoader.js')
        },
        {
          loader: path.resolve(__dirname, './loaders/replaceLoaderAsync.js'),
          options: {
            name: 'world'
          }
        }
      ] // 使用自己写的loader模块 
    }] 
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  }
}  
const loaderUtils = require('loader-utils');
module.exports = function(source) { 
  const options = loaderUtils.getOptions(this);

  const callback = this.async(); // 声明一下异步操作
  setTimeout(() => {
    const result = source.replace('xiaochengzi', options.name);
    callback(null, result); 
  }, 1000)
}
module.exports = function(source) { 
  return source.replace('world', 'ranran')
}

再次执行打包:npm run build

知识补充

当配置多个自己编写的loader时,每次都需要使用path.resolve来指定路径读取loader,如:



其实,我们可以通过其他配置,去除这部分冗余代码:(如)

const path = require('path');
module.exports = {
  mode: 'development',
  entry: {
    main: './src/index.js'
  },
  resolveLoader: {
    modules: ['node_modules', './loaders']
  }, // 当你去使用loader的时候,它会帮你去做一些事情
  module: {
    rules: [{
      test: /\.js/,
      use: [
        {
          loader: 'replaceLoader'
        },
        {
          loader: 'replaceLoaderAsync',
          options: {
            name: 'world'
          }
        }
      ] // 使用自己写的loader模块 
    }] 
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  }
}  

执行打包:npm run build



最终打印为 ‘hello ranran’ ,成功执行。

总结:loader在我们项目开发中的用处还是比较大的,比如:代码的异常捕获、中英文网站的切换等。

上一篇 下一篇

猜你喜欢

热点阅读