如何将 Lighthouse CI 集成到 grunt 构建

解读

面试官问“如何把 Lighthouse CI 集成到 grunt 构建”,并不是想听“装个插件就行”。他要确认三件事:

  1. 是否理解 Grunt 的任务调度机制(task、target、option、流程编排);
  2. 是否熟悉 Lighthouse CI 的两种运行模式(CLI 与 Node API),并能权衡其优缺点;
  3. 能否把性能卡点前置到 CI 阶段,并给出国内网络、私有仓库、权限、报告归档等工程化闭环方案。

回答时务必体现“任务拆分 → 插件选型 → 参数调优 → 报告消费 → 失败策略”五步闭环,让面试官听到“可落地、可回滚、可度量”。

知识点

  • grunt-contrib-copy / grunt-contrib-clean:准备待测产物目录,保证 Lighthouse 扫描的是真实待上线文件而非源码。
  • grunt-run / grunt-exec:在 Grunt 流程里无阻塞地调用 npx lhci autorun,并透传 token、config 路径等环境变量。
  • LHCI 配置文件(lighthouserc.js): – ci.collect.url:支持本地静态服务器地址,需与 grunt-contrib-connect 的端口随机化做联动; – ci.assert.assertions:国内项目建议先关闭 uses-webp、unused-css-rules 等“外网 CDN”敏感断言,避免误报; – ci.upload.target:若用 GitLab CI,需改target: ‘filesystem’,再配 grunt 任务把 .lighthouseci 文件夹归档到 artifacts/
  • 性能预算(budgets.json):与 grunt-perfbudget 做指标互补,但 LHCI 的 JSON 报告更利于后续数据入库
  • 失败策略:grunt 任务默认以 exit code 驱动流程,因此用 --failOnUploadFailure --failOnAssertFailure 保证红线阻断;若需软阻断,可在 grunt-run 里加 failOnError: false,再手动解析 lhr-.json 中的 score < 0.9 项,用 grunt.log.warn 输出而不中断构建。
  • 国内加速:lhci collect 阶段默认从 https://fonts.googleapis.com 拉取字体,CI 机器无外网时需加 chrome-flags --disable-web-security --block-urls=*googleapis.com,否则超时导致得分失真。
  • 并行优化:在 Grunt 多 target 场景下,用 grunt-concurrent 把 Lighthouse 扫描任务与压缩、上传 CDN 任务并行,平均节省 25% 流水线时间。

答案

  1. 安装依赖
    npm i -D @lhci/cli grunt-run grunt-contrib-connect

  2. 准备待测产物
    在 Gruntfile 中先定义 build 任务,输出到 dist/;随后用 connect:dist本地 0.0.0.0:8000 服务,保证 Lighthouse 可访问。

  3. 编写 LHCI 配置 lighthouserc.js

    module.exports = {
      ci: {
        collect: {
          startServerCommand: '', // 已在 grunt 里启动
          url: ['http://localhost:8000/index.html'],
          numberOfRuns: 3,
          settings: {
            chromeFlags: '--disable-storage-reset --block-urls=*googleapis.com'
          }
        },
        assert: {
          preset: 'lighthouse:recommended',
          assertions: {
            'categories:performance': ['error', { minScore: 0.9 }],
            'uses-webp': 'off' // 国内 CDN 误报多,先关闭
          }
        },
        upload: {
          target: 'filesystem',
          outputDir: '.lighthouseci'
        }
      }
    };
    
  4. 在 Gruntfile 注册任务

    grunt.loadNpmTasks('grunt-run');
    grunt.initConfig({
      run: {
        lighthouse: {
          cmd: 'npx',
          args: ['lhci', 'autorun'],
          options: { cwd: __dirname, env: process.env }
        }
      },
      connect: { dist: { options: { port: 8000, base: 'dist' } } }
    });
    
    grunt.registerTask('perf', ['build', 'connect:dist', 'run:lighthouse']);
    
  5. 接入 CI
    .gitlab-ci.yml 中声明 artifacts:paths: [.lighthouseci],并设置仅当分支为 main 时触发 perf 任务,实现**“开发分支不卡,主干红线卡”**策略。

  6. 报告消费
    jq 解析 .lighthouseci/lhr-*.json,把 categories.performance.score 写入云监控自定义指标,实现版本级性能趋势可视化

拓展思考

  • 如果公司项目为微前端多仓库,可在根仓库用 grunt-hub 统一聚合各子仓库的 Lighthouse 报告,一次流水线产出全局性能雷达图
  • 对于需要登录态的后台系统,Lighthouse 的 --extra-headers 方案维护成本高,建议把登录 Cookie 写入 localStorage 后,用 Puppeteer 脚本先跑一遍登录,再把 Chrome 用户目录传给 LHCI,既保证得分真实,又不泄露账号密码
  • 当构建节点为内网 Jenkins + Windows Slave 时,Chrome 安装路径不固定,可在 Grunt 任务里动态查询注册表获取 chrome.exe 绝对路径,再写到 CHROME_PATH 环境变量,避免“找不到浏览器”导致 CI 随机失败。