美文网首页
自己写一个Webpack插件

自己写一个Webpack插件

作者: 西麦smile | 来源:发表于2019-11-08 11:02 被阅读0次

需求分析

当我们使用 Jest 进行自动化测试时,我们可能会需要在测试文件中获取某个 DOM 节点,这时就会在相应的 DOM 上加一个 data-test 属性来获取,比如:

<button class="button-class" data-test="button"><button>

在测试文件中判断 button 是否存在

it('页面上存在 button', () => {
  const button = document.querySelector('[data-test="button"]')
  expect(button).toBeDefined()
})

因此 data-test 实际上只是用于测试文件,并没有其它实质性的作用,因此希望在打包时把该属性去掉,这时就可以通过 webpack 插件来清除它,如:

<!-- 未使用移除 data-test 属性插件编译前 -->
<button class="button-class" data-test="button"><button>
<!-- 使用插件后 -->
<button class="button-class"><button>

编写插件

参考官方文档 Writing a Plugin 可知,一个插件由以下几个部分组成:

  • 一个具名的 JavaScript 函数或一个 Class
  • 在它的原型上定义 apply 方法
  • 通过 apply 函数中传入 compiler 并插入指定的事件钩子,在钩子回调中取到 compilation 对象
  • 通过 compilation 处理 webpack 内部特定的实例数据
  • 如果是插件是异步的,在插件的逻辑编写完后调用 webpack 提供的 callback

编写插件

// step1: 创建 plugins/RemoveDataTest.js
class RemoveDataTestPlugin {
  constructor(options) {
    this.options = options
  }

  // step2: 需要定义 apply 方法,并传入 compiler
  apply(compiler) {
    // 匹配所有 data-test 属性的正则
    const reg = /\s*data-test="(.*?)"/g

    // step3: 插入事件钩子,在回调中取到 compilation
    compiler.hooks.emit.tap('RemoveDataTest', (compilation) => {
      Object.keys(compilation.assets).forEach(filename => {
        // step4: 得到资源内容
        let content = compilation.assets[filename].source()
        // step5: 清除 html 文件中的 data-test 属性
        if (/\.html$/.test(filename)) {
          content = content.replace(reg, '')
        }
        // step6: 更新 compilation.assets[filename] 对象
        compilation.assets[filename] = {
          source() {
            return content
          },
          size() {
            return content.length
          }
        }
      })
    })
  }
}

module.exports = RemoveDataTestPlugin

过程分析

compiler 中的 emit 钩子

emit 钩子可以把编译好的代码发射到指定的 stream 中触发,在执行这个钩子的时候,我们能从回调函数返回的 compilation 对象上拿到已经编译好的 stream

compiler.hooks.emit.tap('自定义事件名', (compilation) => {
  // ...
})

访问 compilation 对象

在每一次编译时,都会拿到最新的 compilation 对象,所有的资源都会以 key-value 的形式存在 compilation 对象下的 compilation.assets

遍历 assets

通过遍历 assets,我们可以拿到 main.js 和 index.html 文件,通过 compilation.assets[filename].source() 取得资源内容,最后用正则 replace 方法去掉 data-test

更新 assets

compilation.assets[filename] = {
  source() {
    return content
  },
  size() {
    return content.length
  }
}

使用插件

// webpack.dev.config.js
const RemoveDataTestPlugin = require('./plugins/RemoveDataTestPlugin')

module.exports = {
  // ...
  plugins: [
    // ...
    new RemoveDataTestPlugin()
  ],
  // ...
}

源码地址

相关文章

  • 自己写一个Webpack插件

    需求分析 当我们使用 Jest 进行自动化测试时,我们可能会需要在测试文件中获取某个 DOM 节点,这时就会在相应...

  • electron之使用两个package.json

    要自定义生成electron的package.json没有现成的webpack插件,需要自己写一个 插件代码 we...

  • 深入webpack4源码(一)——插件与Tapable

    包含内容:什么是Tapable、Tapable和webpack的关系、如何写一个webpack插件。 最近再开始学...

  • webpack技术内幕

    babel解析 webpack内部插件与钩子的解析 1. 自己写一个loader 来看markdownd的load...

  • 写一个 Webpack 插件

    通过前面章节内容的讲解,对于 Webpack 的插件应该已经不陌生了,而且对于 Webpack 很多高级的知识点应...

  • 写一个webpack插件

    webpack的工作机制是基于事件流,将各个插件串联起来,而核心就是tapable对象 核心概念: tapable...

  • webpack插件& loader篇

    插件 webpack入门中 列出了下面这些插件 本篇则对它们做一个介绍 插件分文webpack内置插件 和 要外部...

  • 编写一个webpack plugin(基础篇)

    编写一个webpack plugin(基础篇) 创建插件 webpack插件由以下组成 一个具名javaScrip...

  • webpack插件指南

    webpack 有着丰富的插件接口。webpack 自身的多数功能都使用插件接口。插件接口使 webpack 变得...

  • webpack-bundle-analyzer插件快速入门

    前言 首先,这是一个webpack的插件,需要配合webpack和webpack-cli一起使用。这个插件的功能是...

网友评论

      本文标题:自己写一个Webpack插件

      本文链接:https://www.haomeiwen.com/subject/afeibctx.html