没有任何处理手段的Webpack只认识js文件,这就意味着图片等资源文件是不能被识别的。
这就需要借助loader来处理不同类型的文件了,通常file-loader、url-loader、raw-loader这三个loader在webpack 4时代就能胜任图片加载操作。

webpack4图片处理

  • file-loader:将图像引用转换为 url 语句并生成相应图片文件;

其加载原理是:经过 file-loader 处理后,原始图片会被重命名并复制到产物文件夹,同时在代码中插入图片 URL 地址:

  1. // webpack.config.js
  2. module.exports = {
  3. // ...
  4. module: {
  5. rules: [{
  6. test: /\.(png|jpg)$/,
  7. use: ['file-loader']
  8. }],
  9. },
  10. };

使用:

  1. import csg from './csg_nezha.jpeg'
  2. // document.getElementById('my-img').src = csg
  3. // build之后是:
  4. const __WEBPACK_DEFAULT_EXPORT__ = (__webpack_require__.p + \"80a7572f2fb0cf3704f1d34905600dcd.jpeg\"
  • url-loader:有两种表现,对于小于阈值 limit 的图像直接转化为 base64 编码;大于阈值的图像则调用 file-loader 进行加载;

    1. module.exports = {
    2. // ...
    3. module: {
    4. rules: [{
    5. test: /\.(png|jpg)$/,
    6. use: [{
    7. loader: 'url-loader',
    8. options: {
    9. limit: 1024 // 阈值
    10. }
    11. }]
    12. }],
    13. },
    14. };

    经过 url-loader 处理后,小于 limit 参数即 1024B 的图片会被转译为 Base64 编码。同时,它对于超过阈值的图片,其功能和file-loader基本一致。

  • raw-loader:不做任何转译,只是简单将文件内容复制到产物中,适用于 SVG 场景。经过 raw-loader 处理后,SVG 资源会被直接复制成字符串形式

    1. module.exports = {
    2. // ...
    3. module: {
    4. rules: [
    5. {
    6. test: /\.svg$/i,
    7. use: ['raw-loader'],
    8. },
    9. ],
    10. },
    11. };

    webpack5图片处理

    上述 file-loader、url-loader、raw-loader 都并不局限于处理图片,它们还可以被用于加载任意类型的多媒体或文本文件,使用频率极高,所以 Webpack5 直接内置了这些能力。webpack5中只需要通过module.rules.type 属性指定资源类型即可:

  • file-loader 对标到 type = “asset/resource”‘:

    1. module: {
    2. rules: [
    3. {
    4. test: /\.(png|jpg|jpeg)$/,
    5. type: 'asset/resource'
    6. },
    7. ],
    8. },
  • url-loader 对标到 type = “asset” 或 type = “asset/inline”:

    1. module: {
    2. rules: [
    3. {
    4. test: /\.(png|jpg|jpeg)$/,
    5. type: "asset", // url-loader
    6. parser: {
    7. dataUrlCondition: {
    8. maxSize: 1024, // 1kb
    9. },
    10. },
    11. },
    12. ],
    13. },
  • raw-loader 对标到 type = “asset/source”:

    1. {
    2. // ...
    3. module: {
    4. rules: [
    5. {
    6. test: /\.svg$/i,
    7. use: ['raw-loader']
    8. type: "asset/source"
    9. },
    10. ],
    11. },
    12. };

    除了加载图片之外,webpack5的module.rules.type 已经支持 JSON、WebAssemsbly、二进制、文本等资源类型。

    webpack图片相关的优化

    Web 页面中的图片做各种优化,提升页面性能,常见的优化方法包括:

  • 图像压缩:减少网络上需要传输的流量;

  • 雪碧图:减少 HTTP 请求次数;
  • 响应式图片:根据客户端设备情况下发适当分辨率的图片,有助于减少网络流量;
  • CDN:减少客户端到服务器之间的物理链路长度,提升传输效率;
    压缩图片
    压缩图片可以使用:(图像压缩是耗时操作,在生产环境下开启)
    1. yarn add -D image-webpack-loader
    简单配置如下
    1. module.exports = {
    2. // ...
    3. module: {
    4. rules: [{
    5. test: /\.(gif|png|jpe?g|svg)$/i,
    6. // type 属性适用于 Webpack5,旧版本可使用 file-loader
    7. type: "asset/resource",
    8. use: [{
    9. loader: 'image-webpack-loader',
    10. options: {
    11. // jpeg 压缩配置
    12. mozjpeg: {
    13. quality: 80
    14. },
    15. }
    16. }]
    17. }],
    18. },
    19. };

    image-webpack-loader 底层依赖于 imagemin 及一系列的图像优化工具:

    • mozjpeg:用于压缩 JPG(JPEG) 图片;
    • optipng:用于压缩 PNG 图片;
    • pngquant:同样用于压缩 PNG 图片;
    • svgo:用于压缩 SVG 图片;
    • gifsicle:用于压缩 Gif 图;
    • webp:用于将 JPG/PNG 图压缩并转化为 WebP 图片格式。

此外还有很多压缩工具比如:image-webpack-loaderimagemin-webpack-pluginimage-minimizer-webpack-plugin

雪碧图

将许多细小的图片合并成一张大图 —— 从而将复数次请求合并为一次请求,之后配合 CSS 的 background-position 控制图片的可视区域,这种技术被称作“雪碧图”。在 Webpack 中,我们可以使用 webpack-spritesmith 插件自动实现雪碧图效果,首先安装依赖

  1. yarn add -D webpack-spritesmith
  1. module.exports = {
  2. // ...
  3. resolve: {
  4. modules: ["node_modules", "assets"]
  5. },
  6. plugins: [
  7. new SpritesmithPlugin({
  8. // 需要
  9. src: {
  10. cwd: path.resolve(__dirname, 'src/icons'),
  11. glob: '*.png'
  12. },
  13. target: {
  14. image: path.resolve(__dirname, 'src/assets/sprite.png'),
  15. css: path.resolve(__dirname, 'src/assets/sprite.less')
  16. }
  17. })
  18. ]
  19. };

此SpritesmithPlugin插件会将 src.cwd 目录内所有匹配 src.glob 规则的图片,合并成一张大图并保存到 target.image 指定的文件路径,同时生成兼容 SASS/LESS/Stylus 预处理器的 mixins 代码。

雪碧图曾经是一种使用广泛的性能优化技术,但 HTTP2 实现 TCP 多路复用之后,雪碧图的优化效果已经微乎其微 —— 甚至是反优化,可以预见随 HTTP2 普及率的提升,未来雪碧图的必要性会越来越低,因此建议读者们了解作用与基本原理即可,不必深究。

响应式图片

响应式图片其实就是:为不同设备提供不同的分辨率、不同尺寸的图片 。
这里介绍

  1. yarn add -D responsive-loader sharp
  1. module.exports = {
  2. // ...
  3. module: {
  4. rules: [{
  5. test: /\.(png|jpg)$/,
  6. oneOf: [{
  7. type: "javascript/auto",
  8. resourceQuery: /sizes?/,
  9. use: [{
  10. loader: "responsive-loader",
  11. options: {
  12. adapter: require("responsive-loader/sharp"),
  13. },
  14. }],
  15. }, {
  16. type: "asset/resource",
  17. }],
  18. }],
  19. }
  20. };

我们通常没必要对项目里所有图片都施加响应式特性,因此这里使用 resourceQuery 过滤出带 size/sizes 参数的图片引用,使用方法

  1. // 引用图片,并设置响应式参数
  2. import responsiveImage from './webpack.jpg?sizes[]=300,sizes[]=600,sizes[]=1024';

引用参数 ‘./webpack.jpg?sizes[]=300,sizes[]=600,sizes[]=1024’; 最终将生成宽度分别为 300、600、1024 三张图片,之后设置 img 标签的 srcset 属性即可实现图片响应式功能
此外,还能简单地通过 size 参数精确控制不同条件下的图像尺寸:

  1. .foo {
  2. background: url("./webpack.jpg?size=1024");
  3. }
  4. @media (max-width: 480px) {
  5. .foo {
  6. background: url("./webpack.jpg?size=300");
  7. }
  8. }