手把手教你写webpack plugin

93 阅读1分钟

背景

随着公司前端开发流程越来越规范,从开发到发布都集成了CICD,而一些老项目还是存在本地打包和部署,打包时依然是在feature分支,导致发包错误。错误的包在线上一时半儿可以也察觉不出来,这时候就需要用plugin自动注入打包时的分支信息。

自定义plugin模板

plugin:带apply属性的对象。

class MyPlugin {
    constructor(options) {
        this.options = options
    }
    apply(compiler) {
        compiler.hooks.钩子名.tap('MyPlugin', () => {
            // todo
        })
    }
}

项目中引用

## vue.config.js
const MyPlugin = require('./plugin/MyPlugin.js')

module.exports = {
    configureWebpack: {
        plugins: [
            new MyPlugin()
        ]
    }
}

compiler钩子

  • beforeRun,开始读取配置文件前触发。
  • run,开始编译后触发。
  • watchRun,在监听模式下,一个新的compilation触发之后,但在compilation实际开始之前触发。
  • compile, 一次新的编译(compilation)创建之前触发。
  • emit,生成资源资源到output目录之前触发。
  • done,compilation编译完成后触发。
  • failed,compilation编译失败后触发。

实战

const dayjs = require('dayjs')
const fs = require('fs')
const path = require('path')
const { exec } = require('child_process')

/**
 * 自动注入变量__timestamp__、__lastCommitId__、__branchName__
 */
class TimestampPlugin {
  apply(compiler) {
    compiler.hooks.done.tap('TimestampPlugin', async() => {
      // 获取最新的commitId
      const lastCommitId = await this.getLastCommitId()
      // 获取当前分支
      const branchName = await this.getBranchName()
      // index.html里注入变量
      this.setVarToHtml(lastCommitId, branchName)
    })
  }
  /* 获取最新的commitId */
  getLastCommitId() {
    return new Promise((resolve) => {
      exec('git rev-parse HEAD', (error, stdout) => {
        if (error) {
          console.error(`执行Git命令时出错: ${error}`)
          return
        }
        resolve(stdout.trim())
      })
    })
  }
  /* 获取分支名 */
  getBranchName() {
    return new Promise((resolve) => {
      exec('git symbolic-ref --short HEAD', (error, stdout) => {
        if (error) {
          console.error(`执行Git命令时出错: ${error}`)
          return
        }
        resolve(stdout.trim())
      })
    })
  }
  /* html网页注入变量 */
  setVarToHtml(lastCommitId, branchName) {
    fs.readFile(path.resolve('./dist/index.html'), 'utf8', (err, data) => {
      if (err) {
        console.error(`读取html文件错误:${err}`)
        return
      }
      var time = dayjs().format('YYYY-MM-DD HH:mm:ss') // 当前时间
      data = data.replace(
        '</title>',
        `</title><script>console.log("发布时间,分支,commitId:", "${time}", "${branchName}", "${lastCommitId}")</script>`
      )
      fs.writeFileSync(path.resolve('./dist/index.html'), data)
    })
  }
}

module.exports = TimestampPlugin

总结

自动注入些打包信息,确实能提高诊断线上包问题的速度。