如何保留特定注释(如 legal)并删除 console 语句
解读
在国内前端面试中,这道题表面问“配置”,实则考察三点:
- 你是否理解构建产物合规性(license、法律免责必须保留);
- 你是否熟悉Grunt 插件的协同机制(uglify、babel、strip 多插件组合);
- 你是否具备**“最小侵入”思维**——只删 console,不破坏源码映射、不误杀合法日志。
回答时务必给出可落地的 Gruntfile 片段,并解释“为什么这样写”而不是“能跑就行”。
知识点
- uglify-es / terser 的 output.comments 正则过滤策略
- babel-plugin-transform-remove-console 的“选择性移除”与 sourcemap 无损
- grunt-strip-comments 与 grunt-contrib-uglify 的冲突规避(双插件顺序)
- banner 模板与 @preserve/@license 标记在国内版权审计中的法律效力
- Grunt 任务链:babel → strip → uglify,保证 AST 先干净再压缩
- sourcemap 同步更新,否则线上报错无法定位
- CI 卡点:在 gitlab-ci 或 GitHub Actions 里加
grunt legal-check任务,防止后人改配置误删注释
答案
- 安装依赖
npm i -D grunt-contrib-uglify@^5 babel-plugin-transform-remove-console grunt-babel @babel/core
- Gruntfile.js 核心配置
module.exports = function(grunt) {
grunt.initConfig({
babel: {
dist: {
files: [{
expand: true,
cwd: 'src',
src: '**/*.js',
dest: '.tmp'
}],
options: {
plugins: [['transform-remove-console', { exclude: ['error', 'warn'] }]]
}
}
},
uglify: {
options: {
output: {
comments: /^\**!|@preserve|@license|legal/i // 保留带 legal 的注释
},
banner: '/*! <%= pkg.name %> v<%= pkg.version %> | (c) <%= grunt.template.today("yyyy") %> */'
},
dist: {
files: [{
expand: true,
cwd: '.tmp',
src: '**/*.js',
dest: 'dist'
}]
}
}
});
grunt.loadNpmTasks('grunt-babel');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.registerTask('default', ['babel', 'uglify']);
};
- 验证
grunt default
grep -n console dist/*.js # 应无结果
grep -i legal dist/*.js # 应仍保留
拓展思考
- 若项目用 TypeScript,把 babel 换成 grunt-ts + ts-loader,并在
tsconfig.json里同样配置remove-console插件,保证类型检查与移除一次性完成。 - 对第三方库(如 lodash)不想删其 console,可在 babel 配置里加
ignore: ['node_modules/**'],再用 webpack 的 externals 把库分离出去,避免合规风险。 - 国内很多甲方要求**“代码可审计”**,此时需把
uglify.options.sourceMap设为true并上传.map到私有源,审计人员可还原原始代码验证 legal 注释未被误删。 - 如果后续迁移到 Vite/Rollup,可用 rollup-plugin-terser 的
format.comments保持相同正则,实现配置知识无损耗迁移,体现你对工程化长期演进的思考。