面试必备!10分钟搞懂 Webpack Loader 和 Plugin 开发,快速拿下大厂 Offer!

710 阅读5分钟

Hello,大家好,我是 Sunday。

在前两天同学的面试中,有一位同学被问到 如何开发 webpack 的 loader 和 plugin?有没有实际 loader 或者 plugin 的开发经验。果然,面试只会越来越卷啊。

webpack 是大家所熟知的打包工具,里面包含了 5 个核心概念:

  1. 入口:entry
  2. 出口:output
  3. 加载器:loader
  4. 插件:plugin
  5. 模式:mode

入口、出口、模式 的概念其实都比较好理解。但是一旦涉及到 loaderplugin,特别是实现 loaderplugin 很多小伙伴就比较懵了。

所以,今天咱们就拿出 20 分钟的时间,一起来看那看那 loaderplugin 是如何实现的!

module、chunk、bundle

如果要讲解 pluginloader 那么会涉及到三个术语:module、chunk、bundle

所以咱们就先说明下 module、chunk、bundle 然后再来看下 pluginloader

在打包工具中,有三个 “术语”:module、chunk、bundle

  1. module:模块:通常一个模块代表了一个文件。一般指的是 js 文件,当然也可以是 css 文件 或者 图像文件。
  2. chunk:块:块通常是在构建过程中由打包工具(如: Webpack)根据配置生成的,它们由一组相关的模块放在一起打包组成。
  3. bundle:打包文件:打包文件是指构建工具在打包过程中生成的最终输出文件,可以在浏览器中加载并运行。

总的来说:模块是组成项目的一个个文件,块是由一组相关模块组成的单元,而打包文件是构建工具最终生成的包含模块和资源的输出文件。

实现 loader 和 plguin

那么明确好了这三个基本的概念之后,接下来咱们来看下 loaderplugin

loader 一般被称为 加载器webpack 默认只能处理 .js 的文件。如果项目中遇到其他类型的文件,那么就需要通过 loader 进行处理。

plugin 一般被叫做 插件,它可以为 构建工具(不只是 webpack,还包含 vite 或者 rollup 提供一些附加的功能。比如说,咱们上一小节用到了 HtmlWebpackPlugin 它就是一个典型的插件,它可以在 webpack 构建的过程中生成一个新的 HTML 文件。并且自动生成新的 bundle 文件。

明确好了它们的基本概念之后,接下来咱们来看下它们 运行时机 的区别,咱们来看下面这张图:

从图中咱们可以看到:

  1. loader 是在打包之前执行的,执行的时机比较固定。其实也很好理解嘛。loader 它实质就是一个转换器,将 A 文件进行编译形成 B 文件,操作的是文件,比如:将A.scss 转变为B.css,单纯的文件转换过程。
  2. plugin 是在整个编译的周期中都会起作用。webpack 在整个运行的生命周期中,会广播出很多的事件,plugin 就可以监听这些事件,然后在某一个时机下,改变输出结果就可以了。

那么明确好了它们的一个运行机制之后,接下来咱们来实现一个简单的 loaderplugin

loader 的简单实现

需求:

实现一个 loader 处理 txt 文件,把 hello world 转化为 配置对象下 content 属性的值

  1. webpack-project/vue.config.js 中利用 chainWebpack 添加新的 loader
// 添加一个处理 txt 文件的loader
config.module
// 创建一个新的规则,命名为 'custom-loader'
.rule('txt-loader')
// 适用于哪些文件
.test(/\.txt$/)
// 指定要使用的 loader 的名称
.use('txt-loader')
// loader 的路径
.loader('./src/loaders/textLoader')
// 配置对象
.options({
    content: '你好,世界'
})
.end()
  1. 然后创建 test.txt 文件:
hello world

3. 实现 textLoader

const loaderUtils = require('loader-utils')
// 接收options配置
module.exports = function (source) {
// 获取配置文件
const options = loaderUtils.getOptions(this)
// 把 hello world 替换成 content 属性配置
source = source.replace(/hello world/, options.content)
// 最后需要返回一个可执行的代码,所以需要 module.exports = '内容'
return `module.exports = '${source}'`
}
  1. 最后在 main.js 中导入该文件,并打印:
const text = require('./test.txt')
console.log(text)

plugin 的简单实现

看完 loader 之后,接下来咱们来看一个 plugin 的构建。

需求:

webpack 打印完成之后,在终端输出指定内容

  1. 创建 webpack-project/src/plugins/logPlugin.js 文件:
class LogPlugin {
// 通过构造函数,获取到传入的内容 content
constructor(options) {
    this.content = options.content
}

// Webpack 会调用 logPlugin 实例的 apply 方法给插件实例传入 compiler 对象。compiler 表示编译器的实例,它代表了完整的 webpack 环境配置
apply(compiler) {
    // 指定一个挂载到 webpack 自身的事件钩子。done 会在 webpack 构建完成后回调
    compiler.hooks.done.tap('logPlugin', (compilation) => {
        // compilation: 当前打包构建流程的上下文
        console.log(this.content)
    })
}
}

module.exports = LogPlugin
  1. vue.config.js 中,添加 plugin
// 添加一个新的 plugin
// 添加一个新的插件
config
.plugin('LogPlugin')
.use(LogPlugin, [{ content: 'hello sunday' }])
.end()

此时,运行项目可在终端打印指定内容。

webpack 在官网中提供了 如何构建 loader如何构建 plugin 的文档,大家如果想要深入了解它们的构建方式的话,那么可以查询下对应的文档内容。

前端训练营:1v1私教,终身辅导计划,帮你拿到满意的 offer 已帮助数百位同学拿到了中大厂 offer