前言

这篇文章主要介绍了浅谈webpack4 图片处理,觉得挺不错的,现在分享给大家,也给大家做个参考。

目录结构:
image.png
webpack4中的图片常用的基础操作:

  • 图片处理和Base64编码
  • 图片压缩
  • 合成雪碧图

    (一)准备工作


如项目代码目录展示的那样,除了常见的app.js作为入口文件,我们将用到3张图片放在/src/assets/imgs/目录下,并在样式base.css中引用这些图片。

剩下的内容叫给webpack打包处理即可。样式文件和入口app.js文件的代码分别如下所示:

  1. /* base.css */
  2. *,
  3. body {
  4. margin: 0;
  5. padding: 0;
  6. }
  7. .box {
  8. height: 400px;
  9. width: 400px;
  10. border: 5px solid #000;
  11. color: #000;
  12. }
  13. .box div {
  14. width: 100px;
  15. height: 100px;
  16. float: left;
  17. }
  18. .box .ani1 {
  19. background: url('../assets/imgs/1.jpg') no-repeat;
  20. }
  21. .box .ani2 {
  22. background: url('../assets/imgs/2.png') no-repeat;
  23. }
  24. .box .ani3 {
  25. background: url('../assets/imgs/3.png') no-repeat;
  26. }

在app.js中

import ‘./css/base.css’

安装依赖:

npm install url-loader file-loader —save-dev

(二)图片处理和base64编码


在webpack.config.js中module.rules选项中进行配置以实现让loader识别图片后缀名,并且进行制定的处理操作。

module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpg|jpeg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              name: '[name]-[hash:5].min.[ext]',
              outputPath: 'images/', //输出到 images 文件夹
              limit: 20000 //把小于 20kb 的文件转成 Base64 的格式
            }
          }
        ]
      }
    ]
  }
}

完整的配置文件

const path = require('path')

const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 单独打包成文件

module.exports = {
  entry: {
    app: './src/app.js'
  },
  output: {
    publicPath: './', // js 引用的路径或者 CDN 地址
    path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
    filename: '[name].bundle.js', // 代码打包后的文件名
    chunkFilename: '[name].js' // 代码拆分后的文件名
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          'css-loader'
        ]
      },
      {
        test: /\.(png|jpg|jpeg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              name: '[name]-[hash:5].min.[ext]',
              outputPath: 'images/', //输出到 images 文件夹
              limit: 20000 //把小于 20kb 的文件转成 Base64 的格式
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      // 打包输出HTML
      title: '自动生成 HTML',
      minify: {
        // 压缩 HTML 文件
        removeComments: true, // 移除 HTML 中的注释
        collapseWhitespace: true, // 删除空白符与换行符
        minifyCSS: true // 压缩内联 css
      },
      filename: 'index.html', // 生成后的文件名
      template: 'index.html', // 根据此模版生成 HTML 文件
      chunks: ['app'] // entry中的 app 入口才会被打包
    }),
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css'
    })
  ]
}

打包项目,查看打包结果,并在浏览器中打开index.html文件:
image.png
可以看到除了1.jpg,另外两张图片已经被打包成base64格式,在app.css文件中1.jpg这个文件超过了我们在url-loader选项中设置的limit值,所以被单独打包

这就是利用了 file-loader 的能力,如果在 url-loader 中设置了 limit 的值,却没有安装 file-loader 依赖,会怎么样?来试试看,首先卸载 file-loader 依赖npm uninstall file-loader,再运行打包命令,npm run build
image.png

如果图片较多,会发很多http请求,会降低页面性能。 url-loader会将引入的图片编码,转为base64字符串。在把这串字符串打包到文件中,最终只需要引入这个文件就能访问图片了,节省了图片请求。

但是,如果图片较大,编码会消耗性能。因此url-loader提供了一个limit参数,小于limit参数的文件会被转为base64,大于limit的使用file-loader进行处理,单独打包。

url-loader依赖file-loaderurl-loader可以看作是增强版的file-loader

(三)图片压缩


图片压缩需要使用img-loader插件,除此之外,针对不同的图片类型,还要引用不同的插件。例如,我们项目中使用的是png图片,需要引入的是imagemin-pngquant,并且指定压缩率。压缩jpg/jpeg图片为imagemin-mozjpeg 插件

这里有个bug,可以先不急着操作,先把这一小节看完,在决定!!

安装依赖

npm i img-loader imagemin imagemin-pngquant imagemin-mozjpeg —save-dev

在之前的配置上更改:

{
  test: /\.(png|jpg|jpeg|gif)$/,
  use: [
    {
      loader: 'url-loader',
      options: {
        name: '[name]-[hash:5].min.[ext]',
        outputPath: 'images/', // 输出到 images 文件夹
        limit: 20000 //把小于 20kb 的文件转成 Base64 的格式
      }
    }
  ]
}

更改为:

{
  test: /\.(png|jpg|jpeg|gif)$/,
  use: [
    {
      loader: 'url-loader',
      options: {
        name: '[name]-[hash:5].min.[ext]',
        limit: 1000, // size <= 1KB
        outputPath: 'images/'
      }
    },
    // img-loader for zip img
    {
      loader: 'img-loader',
      options: {
        plugins: [
          require('imagemin-pngquant')({
            quality: '80' // the quality of zip
          }),
          require('imagemin-mozjpeg')({
            quality: '80'
          })
        ]
      }
    }
  ]
}

打包结果:
image.png
原因在 png 图片上,jpg 图片可以压缩,但是去 imagemin-pngquant github 上也没发现有人提出类似 issue ,百度、google 找了半天,还是没发现怎么解决 ~_~,于是使用另一种压缩图片的插件 image-webpack-loader
首先卸载了之前的依赖:

npm uni img-loader imagemin imagemin-pngquant imagemin-mozjpeg

安装依赖:

npm i image-webpack-loader —save-dev

这个依赖安装的时间会比较久。。。可以做下其他的。
在之前的配置上更改:

{
  test: /\.(png|jpg|jpeg|gif)$/,
  use: [
    {
      loader: 'url-loader',
      options: {
        name: '[name]-[hash:5].min.[ext]',
        outputPath: 'images/', // 输出到 images 文件夹
        limit: 20000 //把小于 20kb 的文件转成 Base64 的格式
      }
    }
  ]
}

更改为:

{
  test: /\.(png|jpg|jpeg|gif)$/,
  use: [
    {
      loader: 'url-loader',
      options: {
        name: '[name]-[hash:5].min.[ext]',
        limit: 1000, // size <= 1KB
        outputPath: 'images/'
      }
    },
    // img-loader for zip img
    {
      loader: 'image-webpack-loader',
      options: {
        // 压缩 jpg/jpeg 图片
        mozjpeg: {
          progressive: true,
          quality: 65 // 压缩率
        },
        // 压缩 png 图片
        pngquant: {
          quality: '65-90',
          speed: 4
        }
      }
    }
  ]
}

这里故意吧url-loaderlimit属性值设的很小,不让它转化png图片为base64,因为我们要测试压缩png图片
打包结果:
image.png
图片压缩成功,这里我仔细看了下image-webpack-loader 的 github,其实这里的image-webpack-loader 插件内置了好几种图片压缩的插件
image.png
这里让我很疑惑,为什么我直接安装 imagemin-pngquant 不行,反而使用 image-webpack-loader却可以,于是我去查看 package-lock.json 文件,搜索 image-webpack-loader
image.png
我看了下我之前安装的最新版本,7.0.0!!!
终于找到原因了,,新版本有些问题没有处理好,导致压缩png图片失败,找到问题就好办了,在package.json中,将imagemin-pngquant 版本改为 ^6.0.0,重新 npm install
按照之前的操作,就可以压缩成了,对应如下:

{
  "devDependencies": {
    "imagemin": "^6.1.0",
    "imagemin-mozjpeg": "^8.0.0",
    "imagemin-pngquant": "^6.0.0",
    "img-loader": "^3.0.1"
  }
}

如果使用 image-webpack-loader ,版本为 4.6.0 .
这次我还是使用了image-webpack-loader,朋友们可以自行选择使用哪个插件,只是image-webpack-loader引入了其他图片格式压缩的依赖,如 svg/webp/gif 等,只安装 image-webpack-loader 就够了,而另一种则是要一个个插件装过去,其实原理都一样。我个人比较推荐使用image-webpack-loader

(四)生成雪碧图


安装依赖:

npm i postcss-loader postcss-sprites —save-dev

完整配置:

const path = require('path')

const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 单独打包成文件

/*********** sprites config ***************/
let spritesConfig = {
  spritePath: './dist/images'
}
/******************************************/

module.exports = {
  entry: {
    app: './src/app.js'
  },
  output: {
    publicPath: './', // js 引用的路径或者 CDN 地址
    path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
    filename: '[name].bundle.js', // 代码打包后的文件名
    chunkFilename: '[name].js' // 代码拆分后的文件名
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          'css-loader',
          /*********** loader for sprites ***************/
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss',
              plugins: [require('postcss-sprites')(spritesConfig)]
            }
          }
          /*********************************************/
        ]
      },
      {
        test: /\.(png|jpg|jpeg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              name: '[name]-[hash:5].min.[ext]',
              limit: 1000, // size <= 1KB
              outputPath: 'images/'
            }
          },
          // img-loader for zip img
          {
            loader: 'image-webpack-loader',
            options: {
              // 压缩 jpg/jpeg 图片
              mozjpeg: {
                progressive: true,
                quality: 65 // 压缩率
              },
              // 压缩 png 图片
              pngquant: {
                quality: '65-90',
                speed: 4
              }
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      // 打包输出HTML
      title: '自动生成 HTML',
      minify: {
        // 压缩 HTML 文件
        removeComments: true, // 移除 HTML 中的注释
        collapseWhitespace: true, // 删除空白符与换行符
        minifyCSS: true // 压缩内联 css
      },
      filename: 'index.html', // 生成后的文件名
      template: 'index.html', // 根据此模版生成 HTML 文件
      chunks: ['app'] // entry中的 app 入口才会被打包
    }),
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css'
    })
  ]
}

打包后查看结果:
image.png
雪碧图是为了减少网路请求,所以被处理雪碧图的图片多为各式各样的logo或者是大小相同的小图片。
而对于大图片,不推荐使用雪碧图。这样会使得图片体积很大。
除此之外,雪碧图要配合css代码定制化使用,要通过 css 代码在雪碧图上精准定位需要的图片。

总结

以上只是webpack处理图片部分,webpack还有更多的功能配置,请参考https://www.webpackjs.com/concepts/ 根据自己的项目需求,进行配置。