如何对 retina 图片进行 @2x 后缀识别并差异化压缩质量

解读

国内前端项目普遍要兼容高分屏,UI 会输出两套切图:logo.pnglogo@2x.png。构建阶段必须:

  1. 识别文件名中的 @2x 标记
  2. 二倍图采用更低压缩比(保留更多细节),普通图采用高压缩比(减少体积)
  3. 保证目录结构、引用路径不变,避免人工干预

面试官想看你是否能把“文件匹配规则”“条件化任务配置”“Grunt 多任务实例”三个点串起来,而不是只会跑 grunt-contrib-imagemin 默认配置。

知识点

  • Gruntfile 多任务目标(targets)机制:同一任务可定义多个 target,各自独立配置
  • glob 通配符与扩展名匹配**/*@2x.{png,jpg,jpeg} 精准命中 retina 图
  • imagemin 插件的 optimizationLevel / quality 参数:png 用 optimizationLevel(0-7),jpg 用 quality(0-100)
  • grunt-newer 或 grunt-contrib-watch 缓存:避免重复压缩已优化图片,提升 CI 速度
  • 文件对象格式(files object){src: [], dest: ''} 写法可保持目录层级
  • 中文跨平台路径问题:Windows 不区分大小写,macOS/Linux 区分,需统一小写后缀
  • 国内镜像加速npm config set sharp_binary_host=https://npmmirror.com/mirrors/sharp 可解决 imagemin 依赖下载慢的问题

答案

  1. 安装依赖(npm 源已切到国内镜像)
npm i -D grunt grunt-contrib-imagemin grunt-newer
  1. Gruntfile.js 关键片段
module.exports = function(grunt) {
  grunt.initConfig({
    imagemin: {
      // 普通图高压缩
      normal: {
        options: {
          optimizationLevel: 3,          // png
          progressive: true,               // jpg
          quality: 70                    // jpg 质量 70
        },
        files: [{
          expand: true,
          cwd: 'src/img',
          src: ['**/*.{png,jpg,jpeg}', '!**/*@2x.{png,jpg,jpeg}'], // 排除 @2x
          dest: 'dist/img'
        }]
      },
      // retina 图低压缩
      retina: {
        options: {
          optimizationLevel: 5,          // 更高保真
          progressive: true,
          quality: 85                    // jpg 质量 85
        },
        files: [{
          expand: true,
          cwd: 'src/img',
          src: ['**/*@2x.{png,jpg,jpeg}'], // 仅 @2x
          dest: 'dist/img'
        }]
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-imagemin');
  grunt.registerTask('img', ['newer:imagemin:normal', 'newer:imagemin:retina']);
};
  1. 运行
grunt img

构建后,dist/img 目录下普通图体积下降 50% 以上,@2x 图保留高分屏细节,文件名与路径完全一致,可直接上线。

拓展思考

  • 若 UI 输出 3x 图(@3x),可再增加 imagemin.target3x,用 quality 90 + optimizationLevel 6 保证印刷级清晰
  • 对 WebP 输出,可再配 grunt-contrib-webp,同样按 @2x 后缀做 quality 75 vs 85 差异化
  • 在 CI 中,把 grunt img 放到 pre-commit 钩子,结合 husky + lint-staged,防止大图片误提交
  • 若项目用小程序,可将 @2x 图统一打到 assets/_retina 目录,利用 grunt-copy 在上传前再合并,减少仓库体积
  • 国内 CDN 常自动回源 WebP,可让运维配置 User-Agent 嗅探,此时本地只需保留压缩后的 @2x PNG 作为兜底,无需输出双格式,降低构建时间