vue-cli4 用 image-webpack-loader

2021-04-12  本文已影响0人  AizawaSayo

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 配置详解以及资源相对路径处理(废话连篇预警)

上一篇下一篇

猜你喜欢

热点阅读