使用 grunt-license-finder 生成依赖许可证清单

解读

在国内前端团队面试中,“合规”与“安全” 已成为必考维度。grunt-license-finder 并不是高频插件,但面试官借它考察三点:

  1. 你是否能把“合规风险”纳入构建流程,而非事后补票;
  2. 是否熟悉 Grunt 多任务(multi-task) 机制与动态任务注册
  3. 能否把产出物(license.json)无缝接入CI 门禁制品库审计
    题目看似简单,实则要求你给出“可落地、可集成、可审计”的完整方案,而不是跑通一次命令。

知识点

  • grunt-license-finder 本质:对 npm/yarn/pnpm 安装的依赖树执行 license-checker,再按 Grunt File 规范输出 JSON/CSV/HTML;
  • Grunt 任务阶段initConfig → registerTask → grunt.loadNpmTasks,需理解任务管道顺序
  • 国内镜像场景:淘宝镜像、华为云镜像可能导致 license-checker 拿不到 repository 字段,需兜底策略(自定义 transform);
  • CI 集成:在 GitLab-CI 或 Jenkins 中,把生成的 license-summary.json 作为**制品(artifact)**上传,供法务扫描;
  • 合规红线:GPL-3.0、CC-BY-NC 等传染性或商业受限许可证需触发失败阈值,用 --failOn 参数或自定义 reporter 抛出 exit code=1;
  • 性能优化:monorepo 项目依赖量大,需用 --excludePrivate--onlyunknown 过滤,避免 5min+ 的扫描阻塞
  • 缓存策略:把 node_modules/.cache/license 目录缓存到 GitLab runner,二次构建提速 70%

答案

  1. 安装与版本锁定
npm i -D grunt-license-finder@~4
# 锁定小版本,防止 5.x 破坏性变更
  1. Gruntfile.js 配置(可直接拷贝到企业脚手架)
module.exports = function(grunt) {
  grunt.initConfig({
    license_finder: {
      options: {
        // 国内镜像兼容:强制离线扫描,不发送 github api 请求
        offline: true,
        // 只关心生产依赖,过滤 dev 包
        production: true,
        // 自定义输出格式,方便后续脚本解析
        customFormat: {
          name: '',
          version: '',
          licenses: '',
          repository: '',
          licenseFile: ''
        },
        // 合规红线:出现 GPL-3.0 直接失败
        failOn: ['GPL-3.0', 'GPL-2.0'],
        // 输出路径,必须放到 CI 制品目录
        out: 'dist/reports/license-summary.json'
      },
      src: ['./']   // 扫描当前项目根
    }
  });

  grunt.loadNpmTasks('grunt-license-finder');

  // 注册合规门禁任务
  grunt.registerTask('compliance', ['license_finder']);
  // 默认构建链路插入合规检查
  grunt.registerTask('default', ['clean', 'eslint', 'compliance', 'webpack']);
};
  1. GitLab-CI 片段(符合国内私有化部署)
compliance:
  stage: security
  script:
    - npm ci --registry=https://registry.npmmirror.com
    - npx grunt compliance
  artifacts:
    reports:
      license: dist/reports/license-summary.json
    expire_in: 90 days
  only:
    - merge_requests
    - master
  1. 本地验证
grunt compliance --debug
# 若出现 GPL-3.0,终端 exit code=1,MR 被 GitLab 拒绝

拓展思考

  • 双引擎备份:若 grunt-license-finder 后续无人维护,可快速切换至 license-webpack-pluginvite-plugin-license,但需统一输出格式,保证法务系统无感切换;
  • SBOM 升级:国内监管正在对标《网络安全审查办法》,下一步需把 license.json 转成 SPDX 标准,再上传至国家互联网应急中心接口;
  • 微前端场景:主应用 + 多个子应用独立仓库,需在构建基座时聚合所有子应用 license 文件,用 grunt-contrib-concat 合并为单一视图,避免“许可证碎片化”风险;
  • 性能极限:当依赖超过 5k 包时,可先用 pnpm licenses list --json 生成缓存,再让 grunt-license-finder 增量扫描,把耗时从 180s 降到 20s;
  • 合规左移:在 husky pre-push 阶段增加 grunt compliance提前拦截不合规依赖,减少 MR 被驳回带来的代码冻结成本。