likes
comments
collection
share

来写一个 Webpack 构建信息插件

作者站长头像
站长
· 阅读数 21
  1. 使用过 Webpack 插件
  2. 阅读过该章节 Webpack plugin

tips: 别指望我这一篇文章能够把 plugin 讲清楚,更多我的希望能做到抛砖引玉的效果。

目标

我们的目标很明确:造一个插件在构建完成后,开发者能够知道一些构建信息,如果构建失败了有失败原因,能够通知开发者及时处理。

目标很明确,剩下的问题就是怎么达成目标。

在查资料的时候偶然看到这篇文章:

webpack 源码阅读一:webpack 流程以及重要钩子

阅读后发现 done 钩子,也许能够在这个钩子做点文章……

开发插件

使用 vue-cli 初始化 vue2 的项目。

并在根目录创建 build-info.js

const pluginName = "BuildInfoPlugin";

class BuildInfoPlugin {
  apply(compiler) {
    compiler.hooks.done.tap(pluginName, (stats) => {
      console.log("webpack 构建的结果:", stats);
    });
  }
}

module.exports = BuildInfoPlugin;

修改 vue.config.js

const { defineConfig } = require("@vue/cli-service");
const BuildInfoPlugin = require("./build-info");
module.exports = defineConfig({
  transpileDependencies: true,
  configureWebpack: {
    plugins: [new BuildInfoPlugin()],
  },
});

执行 npm run build

来写一个 Webpack 构建信息插件

打印的有点多哇。我拉个晓得拉个是我的用到的……

来写一个 Webpack 构建信息插件

调试

根目录创建 .vscode/launch.json

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "调试 webpack 插件",
      "skipFiles": ["<node_internals>/**"],
      "runtimeExecutable": "npm",
      "runtimeArgs": ["run", "build"]
    }
  ]
}

再修改下 build-info.js

const pluginName = "BuildInfoPlugin";

class BuildInfoPlugin {
  apply(compiler) {
    compiler.hooks.done.tap(pluginName, (stats) => {
      console.log("webpack 构建的结果:", stats);
      // eslint-disable-next-line no-debugger
      debugger;
    });
  }
}

module.exports = BuildInfoPlugin;

当你点击红框的按钮时,就开始进入调试流程。

来写一个 Webpack 构建信息插件

代码会在我们打 debugger 的地方暂停运行……还可以在左侧看到一堆信息(不知道怎么描述了)

来写一个 Webpack 构建信息插件

stats 是哈玩意就一清二楚了……

写入构建日志

改造下 build-info.js

const fs = require("fs");
const pluginName = "BuildInfoPlugin";

class BuildInfoPlugin {
  constructor(options) {
    this.options = options;
  }
  apply(compiler) {
    compiler.hooks.done.tap(pluginName, (stats) => {
      const {
        compilation: { errors, startTime, endTime, outputOptions },
      } = stats;
      // 如果构建没有错误
      if (!errors.length) {
        const appName = this.options.appName;

        let log = `console.log("------${appName}构建日志------")
          console.log("开始时间:", ${startTime})
          console.log("结束时间:", ${endTime})
        `;

        // 从 outputOptions 中拿到构建输出的目录
        const filePath = `${outputOptions.path}/index.html`;
        let content = fs.readFileSync(filePath, "utf-8");
        const scriptPos = content.indexOf("</body>");
        content = `${content.slice(
          0,
          scriptPos
        )}<script>${log}</script>${content.slice(scriptPos)}`;
        // 最后写入日志
        fs.writeFileSync(filePath, content, "utf-8");
      }
    });
  }
}

module.exports = BuildInfoPlugin;

vue.config.js 也要改造下!

// 可以在这里增加各种信息,如 `last commit`, 自研包版本, 构建人信息等等……
plugins: [
    new BuildInfoPlugin({
        appName: "hello-world", // 增加 appName
    }),
],

执行构建后,使用 live service 启动项目,即可查看到构建日志信息。

来写一个 Webpack 构建信息插件

构建失败

上面的代码,我们只考虑了构建成功场景,如果构建失败的话怎么处理呢?

一般情况下,是不用管…… cicd 工具已经很成熟了,构建失败或者成功可以通过 cicd 钩子接入不同的消息机器人。

当然我们要在插件里做 构建失败 的通知也是很简单的!

const fs = require("fs");
const axios = require("axios");
const pluginName = "BuildInfoPlugin";

class BuildInfoPlugin {
  constructor(options) {
    this.options = options;
  }
  apply(compiler) {
    compiler.hooks.done.tapAsync(pluginName, async (stats, callback) => {
      const appName = this.options.appName;

      const {
        compilation: { errors, startTime, endTime, outputOptions },
      } = stats;
      // 如果构建没有错误;
      if (!errors.length) {
        let log = `console.log("------${appName}构建日志------")
          console.log("开始时间:", ${startTime})
          console.log("结束时间:", ${endTime})
        `;

        // 从 outputOptions 中拿到构建输出的目录
        const filePath = `${outputOptions.path}/index.html`;
        let content = fs.readFileSync(filePath, "utf-8");
        const scriptPos = content.indexOf("</body>");
        content = `${content.slice(
          0,
          scriptPos
        )}<script>${log}</script>${content.slice(scriptPos)}`;
        // 最后写入日志
        fs.writeFileSync(filePath, content, "utf-8");
        callback();
      }

      await axios.get(`/build-error`, {
        appName,
      });
      callback();
    });
  }
}

module.exports = BuildInfoPlugin;

只需要把 tap 改为 tapAsync, 我们在回调函数中增加 callback

完结

下一篇为大家带来 webpack loader

课后作业:如果是多页的情况,怎么给每个 html 增加构建信息?

转载自:https://juejin.cn/post/7268673775033843771
评论
请登录