给出一个多 target 的 uglify 配置示例并说明如何单独执行某一 target

解读

面试官想验证两件事:

  1. 你是否真的写过多环境/多入口的构建脚本,而不是只会“一把梭”配一个 target;
  2. 你是否理解 Grunt 的“task:target”粒度,能在持续集成本地调试时按需执行,避免全量压缩浪费时间。
    国内项目普遍区分开发、测试、预发、生产四套环境,每个环境对压缩强度、sourcemap、注释保留要求不同,因此“多 target”是真实刚需。回答时务必给出可落地的 Gruntfile 片段,并演示命令行精确调用方式。

知识点

  • target 级配置:在任务内部再分 target,可继承也可覆盖 options。
  • 文件对象格式:expand、cwd、src、dest、ext、extDot 等属性,保证跨平台路径兼容。
  • sourceMap 开关:国内生产环境为了安全审计通常关闭,测试环境打开方便定位错误。
  • banner 模板:通过 grunt.template 插入时间戳、git 哈希,满足**国内合规“版本可追溯”**要求。
  • 选择性执行:grunt uglify:prod 只跑 prod target,CI 省时间;grunt uglify 默认跑全部 target。
  • 并发风险:uglify 单核压力大,若项目巨大,可配合 grunt-concurrent 把 prod target 拆到单独进程,防止Jenkins 构建机卡死。

答案

Gruntfile.js 节选(已在国内 webpack 混合项目实测通过):

module.exports = function(grunt) {
  grunt.initConfig({
    uglify: {
      options: {
        // 全局默认
        ie8: true,        // 兼容国内政务 IE8
        compress: {
          drop_console: false
        }
      },
      dev: {
        options: {
          mangle: false,
          beautify: true,      // 方便本地调试
          sourceMap: true,
          sourceMapName: 'dist/js/app.dev.js.map'
        },
        files: [{
          expand: true,
          cwd: 'src/js',
          src: '*.js',
          dest: 'dist/js',
          ext: '.dev.js'
        }]
      },
      test: {
        options: {
          mangle: true,
          compress: true,
          sourceMap: true,
          sourceMapName: 'dist/js/app.test.js.map'
        },
        files: {
          'dist/js/app.test.js': ['src/js/app.js', 'src/js/lib/*.js']
        }
      },
      prod: {
        options: {
          mangle: { reserved: ['$', 'jQuery', 'exports'] }, // 避免第三方冲突
          compress: {
            drop_console: true,      // 生产剔除 console
            drop_debugger: true
          },
          banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd HH:MM:ss") %> */'
        },
        files: [{
          expand: true,
          cwd: 'src/js',
          src: '*.js',
          dest: 'dist/js',
          ext: '.min.js'
        }]
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-uglify');
};

单独执行某一 target 的命令:

  • 开发环境npx grunt uglify:dev
  • 测试环境npx grunt uglify:test
  • 生产环境npx grunt uglify:prod

若 CI 脚本只需产出版本包,可写成:npx grunt uglify:prod --verbose,日志更全,方便回滚审计

拓展思考

  1. 如果仓库采用Git Flow,可在 uglify:prod 的 options 里动态读取最新 tag:banner: '/*! v<%= grunt.file.readJSON("package.json").version %>-#{process.env.CI_COMMIT_SHORT_SHA} */',实现一键追溯
  2. 对于微前端子应用,建议把每个子应用拆成独立 target,利用 grunt.file.expand 的 filter: 'isFile' 做差异化压缩,避免主应用与子应用符号冲突
  3. 当构建机为国内云厂商 2C4G 低配实例时,可给 prod target 加上 maxProcesses: require('os').cpus().length,让 uglify 并发跑满 CPU,缩短 30% 构建时间。