vue-cli4 用 image-webpack-loader 配置 webpack 图片压缩处理/优化

vue-cli4已经默认帮我们做了很多优化处理,包括静态资源输出、样式处理、代码分割等等。我们需要自己手动配置的事情更少了,而图片压缩处理就是其中的一件。
推荐这个插件,GitHub地址:image-webpack-loader
安装:npm i image-webpack-loader -D

很多人直接这样在vue.config.js里面加 image-webpack-loader 配置:

chainWebpack: config => {
  config.module
    .rule("images")
      .use("image-webpack-loader")
        .loader("image-webpack-loader")
        .options({
          mozjpeg: { progressive: true, quality: 65 },
          optipng: { enabled: true },
          pngquant: { quality: [0.65, 0.9], speed: 4 },
          gifsicle: { interlaced: false }
          // webp: { quality: 75 }
        })
}

image-webpack-loaderGitHub文档已经明确告诉我们:
In your webpack.config.js, add the image-loader, chained after the file-loader.
即:添加 image-loader 的时候,必须要链式地跟在 file-loader 后面。其实是先执行image-webpack-loader,然后再交由file-loader去处理。这很好理解,当然是先压缩后再复制输出到打包的静态资源目录去啦。
关于 loader 处理顺序可参考 webpack loader 执行顺序

// 官方示例
rules: [{
  test: /\.(gif|png|jpe?g|svg)$/i,
  use: [
    'file-loader',
    {
      loader: 'image-webpack-loader',
      options: {
        bypassOnDebug: true, // webpack@1.x
        disable: true, // webpack@2.x and newer
      },
    },
  ]
}]

然鹅,在 vue-cli4 中 file-loader 的部分已经帮我们像这样配置过了:

webpackConfig => {
  webpackConfig.module
    .rule('images')
      .test(/\.(png|jpe?g|gif|webp)(\?.*)?$/)
      .use('url-loader')
        .loader(require.resolve('url-loader'))
        .options({
          limit: 4096,
          fallback: {
            loader: require.resolve('file-loader'),
            options: {
              name: `static/img[name].[hash:8].[ext]`
            }
          }
      })

那我们可以像如下配置:
image-webpack-loader 要先执行所以要配置在下面,实测按照 webpack-chain 文档配置 enforce 没有什么卵用(我还故意把顺序弄错),结果都会正常压缩图片,感觉还是老老实实根据需要的先后顺序从下到上配置好了😂
chainWebpack 配置参考 webpack-chain 配置之 ChainedMap

chainWebpack: config => {
  if(IS_PROD){
    config.module
      .rule('images')
        .exclude.add(resolve('src/assets/icons')) // 排除icons目录,这些图标已用 svg-sprite-loader 处理,打包成 svg-sprite 了
        .end()
        .use('url-loader')
          .tap(options => ({
            limit: 10240, // 稍微改大了点
            fallback: {
              loader: require.resolve('file-loader'),
              options: {
                // 在这里修改file-loader的配置
                // 直接把outputPath的目录加上,虽然语义没分开清晰但比较简洁
                name: 'static/img/[name].[hash:8].[ext]'
                // 从生成的资源覆写 filename 或 chunkFilename 时,`assetsDir` 会被忽略。
                // 因此别忘了在前面加上静态资源目录,即assetsDir指定的目录,不然会直接在dist文件夹下
                // outputPath: 'static/img' 
              }
            }
        }))
        .end()
        .use('image-webpack-loader')
          .loader('image-webpack-loader')
          .options({
            mozjpeg: { progressive: true, quality: 50 }, // 压缩JPEG图像
            optipng: { enabled: true }, // 压缩PNG图像
            pngquant: { quality: [0.5, 0.65], speed: 4 }, // 压缩PNG图像
            gifsicle: { interlaced: false } // 压缩GIF图像
          })
          .end()
          .enforce('post') // 表示先执行配置在下面那个loader,即image-webpack-loader
  }
}

图片被 image-webpack-loader 压缩后,小于10kb 的转成base64(by url-loader),大于这个 size 的则被file-loader输出到dist/static/img文件夹了

static/img目录

完美~

如果想要图片资源打包输出时保持原有的目录结构,或者根据自定义条件决定不同的输出目录,可以用函数配置 outputPath;如果要让资源引用地址输出为相对路径,可以把 outputPath 的内容拷贝一份放到 publicPath

.options({
  name: '[name].[hash:8].[ext]',
  // outputPath: 'static/img', // 别忘了加上静态资源目录这个前缀,即assetsDir指定的目录,不然会直接在dist文件夹下
  outputPath: function (url, resourcePath, context) {
    // 返回从项目根目录到该图片的相对路径
    const relativePath = path.relative(context, resourcePath)
    const pathArr = relativePath.split('/')
    // 如果你的静态资源目录结构较为简单(最多二个层级),图片只放在/src/assets/ 或/src/assets/xxx
    // 希望根据assets下的目录结构原样输出,可以这样做
    if (pathArr[3] !== undefined) {
      return `static/img/${pathArr[2]}/${url}` // url 是上面配置的 name 的值,必须加在路径最后
    }
    return `static/img/${url}`

    // 这些都可依照个人习惯来安排,个人建议没必要太复杂
    // if (/denglun-bg\.jpg/.test(resourcePath)) {
      // 如果图片以 denglun-bg.jpg 结尾
      // return `static/denglun/${url}`
    // }
    // if (/bg_images\//.test(resourcePath)) {
      // 如果图片路径包含 bg_images 目录
      // return `static/bg_images/${url}`
    // }
    // return `static/img/${url}`
  },
  publicPath: (url, resourcePath, context) => {
    // 如果要让资源引用地址输出为相对路径,把 `outputPath` 的内容拷贝一份到这里即可
  }
},
如上配置后图片输出在不同的目录

关于 file-loader 的详细配置说明以及 vue-cli4 涉及图片处理的源码分析:➡️ file-loader 配置详解以及资源相对路径处理(废话连篇预警)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容