描述在 grunt 中实现误报白名单管理

解读

在国内真实项目里,静态检查(eslint/jshint/stylelint)、单元测试(karma/mocha)、压缩混淆(uglify/terser) 等环节常因历史代码或第三方依赖产生大量“假错误/假警告”。
面试官问“误报白名单管理”,本质想看三件事:

  1. 你能否用 Grunt 插件体系把“误报”识别出来;
  2. 你能否把白名单文件化、版本化,而不是口头“忽略”;
  3. 你能否让白名单随构建生命周期自动生效,且不影响 CI 失败判定。

知识点

  • grunt-contrib-jshint/eslint-gruntoptions.ignoreFilesreport/output 钩子
  • grunt-log-filter 社区插件原理:在 grunt.event.on('grunt-verbose',...) 层做正则拦截
  • grunt.file.readJSON/yaml 加载白名单配置,支持按文件、按规则、按行号三级粒度
  • Gruntfile.js 的 task 级变量作用域:用 grunt.config.set('whiteList',...) 实现多 task 共享
  • 非零退出码控制this.async() 手动回传 falseforce:continue 保证 CI 不误报成功
  • npm script 与 husky 结合:在 pre-commit 阶段只增量检查,白名单路径通过 --config 动态注入

答案

  1. 白名单文件化
    在项目根目录建 .grunt-whitelist.json,格式:

    {
      "jshint": {
        "src/js/legacy.js": ["W103", "E024"],
        "src/vendor/*.js": ["*"]
      },
      "eslint": {
        "src/api/mock.js": ["no-console"]
      }
    }
    

    文件必须进 Git,保证团队一致。

  2. 封装统一任务 grunt-filter-check
    在 Gruntfile 里先读白名单:

    const whiteList = grunt.file.readJSON('.grunt-whitelist.json');
    grunt.config.set('whiteList', whiteList);
    
  3. 以 jshint 为例,二次封装官方任务

    grunt.registerTask('jshint-with-white', function() {
      const done = this.async();
      const white = grunt.config('whiteList.jshint') || {};
      grunt.util.spawn({
        grunt: true,
        args: ['jshint:raw', '--no-color'],
      }, function(err, res, code) {
        const lines = (res.stdout || '').split(/\n/);
        const filtered = lines.filter(ln => {
          // 解析出 文件名:行号 错误码
          const m = ln.match(/^(.+?):.*?(W\d+|E\d+)/);
          if (!m) return true;          // 保留无法解析的行
          const file = path.relative(process.cwd(), m[1]);
          const rule = m[2];
          const rules = white[file] || white[file.replace(/\/[^\/]+$/, '/*.js')];
          if (rules && (rules.includes(rule) || rules.includes('*'))) return false;
          return true;
        });
        filtered.forEach(l => grunt.log.writeln(l));
        const stillError = filtered.some(l => l.includes('error'));
        done(stillError ? false : null);
      });
    });
    

    关键点:

    • 不修改官方插件源码,用 spawn 拿到原始输出再过滤;
    • 过滤后若仍有错误,主动 done(false) 让 Grunt 退出码非零,CI 仍会失败;
    • 支持通配符与星号,减少重复配置。
  4. 其他任务复用
    eslint、stylelint 只需把正则和 white 键名换一下,逻辑完全一致,封装成 tasks/lib/filter.js 供复用。

  5. 增量检查优化
    husky 的 pre-commit 钩子内,通过 git diff --cached --name-only 拿到增量文件列表,动态生成临时白名单,只忽略旧文件规则,新文件零容忍,解决“历史债务滚雪球”问题。

拓展思考

  • 如何把白名单反向同步?
    可写 grunt task whitelist-sync,定期把“已修复”的文件从白名单剔除,防止名单无限膨胀。
  • 如何与 SonarQube 集成?
    grunt-shell 里调 Sonar Scanner,把白名单转成 sonar.exclusions 参数,实现服务端与本地双端一致
  • 如何做到“可视化审计”?
    grunt-markdown 把白名单生成为 .whitelist-report.md在 MR 模板中强制展示,让每一次忽略都有记录、有责任人。