webpack——手写loader

154 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情

前言

前面学完了loader的基础写法,下面这一篇文章主要就写一些loader的写法!

清除console.log

在我们开发的时候会有很多的console.log()可能会忘记删除还留着,但是在生产环境中这些东西并没有用,所以下面写一下清除js文件中的console.log的loader,代码如下。loader接收到的content是一个字符串,所以我们可以用字符串的replace方法,将console.log进行替换!

// loaders/clean-log.js
module.exports = function (content) {
  return content.replace(/console\.log\(.*\);?/g, '')
}

image.png

给js代码添加文本注释

image.png 想给代码加上如下注释,可以通过如下loader进行实现,将代码进行拼接!

module.exports = function (content) {
  const prefix = `
  /*
  * Author: fdhou
  */
`;
  return prefix + content
}

上面的写法相当于在loader中将头部注释信息写死了,但是需要将这个信息写成可以配置的,那就需要用到option进行传递参数。

image.png 增加上参数之后就可以通过this.getOptions(schema)获取到,函数需要传递一个schema,这个是对参数的验证规则,传递的参数需要符合 JSON schema 规则。

// schema.json
{
  "type": "object",
  "properties": {
    "Author": {
      "type": "string"
    }
  },
  "additionalProperties": false // 不能够新增字段
}

如此便完成了一个可配置的头部注释的loader image.png

image.png

手写 babel-loader

babel-loader主要实现js语法的向后兼容,以便能够运行在当前和旧版本的浏览器或其他环境中,实现如下:

配置

首先需要安装插件

npm i @babel/core @babel/preset-env -D

代码

// webpack.config.js
{
    test: /\.js$/,
    loader: './loaders/babel-loader',
    options: {
      presets: ['@babel/preset-env']
    }
},
// loaders/babel-loader/index.js
const babel = require("@babel/core");
const schema = require("./schema.json");

module.exports = function (content) {
  const callback = this.async()
  const options = this.getOptions(schema)
  babel.transform(content, options, function (err, result) {
    if (err) callback(err)
    else callback(null, result.code)
  });
}
// loaders/babel-loader/schema.json
{
  "type": "object",
  "properties": {
    "presets": {
      "type": "array"
    }
  },
  "additionalProperties": true
}

如此配置完成再次进行打包即可看到,箭头函数已经被转换成function()

image.png 参考babel-loader官网

  • @babel/preset-env智能预设,主要功能是帮助我们将ES6+的语法编译成ES5以下的语法,来去兼容更多版本的浏览器。

  • @babel/core通过transform对代码进行编译转换

// code 要处理的代码
// options 进行什么处理
// function 处理好的回调
babel.transform(code, options, function(err, result) { 
    result; // => { code, map, ast }
});

手写file-loader

file-loader的作用是用来处理字体图标、图片等资源的,让这些资源原封不动的打包进dist目录,在webpack中是通过type: "asset/resource"或者type: "asset"来实现的。

image.png

处理步骤

  1. 根据文件内容生成一个带有hash值的文件名称,参考(interpolateName方法)
  2. 将文件输出出去
  3. 返回module.exports = '文件路径'

配置

首先需要安装用来生成hash值的包

npm i loader-utils -D

代码

// loaders/file-loader/index.js
const loaderUtils = require('loader-utils')
module.exports = function (content) {
  // 1. 根据文件内容生成一个带有hash值的文件名称
  const interpolatedName = loaderUtils.interpolateName(
    this, // loader 上下文
    '[hash].[ext][query]', // 名字
    {
      content // 文件内容
    }
  );
  //  interpolatedName = `images/${interpolatedName}` 可以设置文件输出的目录
  // 2. 将文件输出出去
  this.emitFile(interpolatedName, content)
  // 3. 返回module.exports = '文件路径'
  return `module.exports = '${interpolatedName}'`
}
// 处理图片、字体图标等资源
// 因为他们都是Buffer数据,所以需要使用raw loader来处理
module.exports.raw = true

image.png 通过以上配置,进行打包会发现只明明只有两张图片,但打包后却生成了四张图片,这是因为图片等资源不但经过了file-loader的处理,同时webpack也进行了处理,所以现在需要设置成只经过file-loader处理,参考webpack官网,只需要进行如下配置即可

webpack.config.js
  {
    test: /\.(png|jpe?g|gif)$/,
    loader: './loaders/file-loader',
    type: 'javascript/auto' // 阻止微博pack处理这些资源,只用file-loader处理
  }

image.png

小结

通过这篇的学习,就能够掌握loader的基本写法了,加油!