优化 Vite 开发环境:实现 JS 错误日志监控

459 阅读2分钟

背景

在调试过程中,某些 JavaScript 错误信息容易被忽视。例如,控制台有报错信息,但由于日志量大,可能被迅速刷掉,未能留意;或页面表现正常,误以为自测已完成,而未注意到 JavaScript 报错,从而导致潜在的隐藏 Bug。这会对项目质量产生负面影响。这类报错信息希望能主动展示在一个显眼的位置,以引起开发的重视并及时修复,同时也希望能被动发现这些错误信息。

解决方案

为了解决开发时主动与被动查看错误日志的问题,考虑了以下机制:

  1. 当控制台出现报错信息时,会将其写入错误日志,并直接在页面上显示,以便开发关注。
  2. 在提交代码时,使用 Git hook 检查错误日志是否包含内容。如果存在错误日志,将不允许提交代码,必须先检查并处理错误日志后,才能进行提交。

改进效果

在本地开发环境中,若代码出现错误,将直接在页面上直观展示错误信息,并支持跳转编辑器,便于快速定位修复。示意图如下:

image.png

同时,系统会将这些报错信息自动保存至项目的根目录,以便后续查阅与分析。

image.png

此外,在执行 Git 提交操作时,若检测到日志中存在错误,将禁止提交。

image.png

实现细节

实现一个 Vite 插件,向页面注入一段代码,以监听错误信息。当发生错误时,将错误信息发送至 Vite 服务器自定义插件。

function sendErrorToServer(body: { msg: string; host: string; stack: string }) {
  fetch('/plugin-capture-error', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  });
}

const HOST = `${window.location.protocol}//${window.location.host}`;

// 捕获全局错误
window.addEventListener('error', event => {
  sendErrorToServer({
    msg: event.message,
    stack: event.error.stack,
    host: HOST,
  });
});

// 捕获promise未处理拒绝错误
window.addEventListener('unhandledrejection', event => {
  sendErrorToServer({
    msg: event.reason.message,
    stack: event.reason.stack || '',
    host: HOST,
  });
});

利用 Vite 本身的 WebSocket 通信机制和全局遮罩报错机制,Vite 服务器的自定义插件将这些错误信息推送至浏览器client。client会监听服务端发送的消息,并根据需求进行不同处理;在这里,使用默认的错误遮罩显示,点击路径可以直接通过编辑器打开对应错误的文件和行号。

export default function viteCaptureErrorsPlugin () {
  return {
    name: 'plugin-capture-error',
    enforce: 'pre',
    apply: 'serve',
    configureServer(server) {
      // ...省略处理文件代码

      // 发送到vite client,显示到页面上
      server.ws.send({
        type: 'error',
        err: {
          message: errorData.msg,
          stack: errorData.stack,
          plugin: PLUGIN_NAME,
        },
      });

      // ...省略代码
    },
  };
}

修改 husky 的 pre-commit 提交检查脚本,提交代码时会检查错误日志中是否存在内容,如果存在,则需确认该错误是否影响项目。

# 检查 .log/error.log 是否有内容
if [ -s ".logs/error.log" ]; then
    echo ".logs/error.log 文件中包含错误信息,请仔细检查是否已解决所有问题。确认无误后,请清空该文件内容再提交。"
    exit 1
fi