Webpack 可以帮助我们处理项目中的图片。在之前的版本中,我们需要通过 url-loader 或者 file-loader 来处理图片资源,从 Webpack 5 开始,Webpack 内置了这些能力,我们只需要指定特定的选项就可以了。

  • type: "asset/inline" 将图片资源转成 base64 编码的形式保存在输出的代码中。这么做减少了页面请求数量,但是会增加构建输出的大小。该能力原来是 url-loader 提供。
  • type: "asset/resource"file-loader 能力相同,输出图片到单独的文件中。
  • type: "asset/source"raw-loader 能力相同,返回模块的原始内容。
  • type: "asset"type: "asset/inline"type: "asset/source" 的混合体,取决于资源的大小,与 file-loaderlimit 功能相同。

output.assetModuleFilename 用来设置输出资源文件的名称,[hash][ext][query] 是三个占位符可选项,同时支持设置路径。

把图片添加到项目中

上面提到了各种处理图片的方式,下面是具体配置:

webpack.parts.js

exports.loadImages = ({ limit } = {}) => ({
  module: {
    rules: [
      {
        test: /\.(png|jpg)$/,
        type: 'asset',
        parser: { dataUrlCondition: { maxSize: limit } },
      },
    ],
  },
});
1
2
3
4
5
6
7
8
9
10
11

webpack.config.js

const commonConfig = merge([...parts.loadImages({ limit: 15000 })]);
1

测试一下我们配置,下载一张图片,然后添加到项目中。

src/main.css

body {
  background: cornsilk;
  background-image: url('./logo.png');
  background-repeat: no-repeat;
  background-position: center;
}
1
2
3
4
5
6

构建结果会根据 limit 的不同而不同。如果图片大小小于 limit,则图片会被内联在构建输出的代码里,否则会被以单独的文件形式输出。

使用 srcset

现在浏览器支持给图片添加 srcset 属性,来根据不同条件使用不同的图片已达到最好的显示效果。可以通过 resize-image-loaderopen in new window, html-loader-srcsetopen in new windowresponsive-loaderopen in new window 这几个包来实现这个功能。

优化图片

压缩图片可以有效减少生产环境的带宽占用,提升网站性能。如果你想压缩一下图片,则可以用这几个包,image-webpack-loaderopen in new window,svgo-loaderopen in new window(只适用于 svg),和 imagemin-webpack-pluginopen in new window. 注意,这些 loader 需要确保在最前面运行。

加载 SVG

Webpack 支持多种加载 svg 的方法,最简单的方法就是通过 type

const config = { test: /\.svg$/, type: 'asset' };
1

然后直接在样式中引用:

.icon {
  background-image: url('../assets/icon.svg');
}
1
2
3

如下几个 loader 也可以实现加载 svg。

动态加载图片

Webpack 还支持动态加载图片,原理与代码按需加载的原理相同,后面会介绍。

加载雪碧图

雪碧图可以帮助我们将多个图片合并到一个图片中,减少网页请求数量。

webpack-spritesmithopen in new window 这个插件可以将多个图片合成为一个雪碧图,同时输出 Sass/Less/Stylus 的 mixins。我们需要在配置中添加 SpritesmithPlugin 插件,指向要组合额图片,同时制定一个输出的 mixins 名称,然后,代码中就可以使用雪碧图了。

@import "~sprite.sass";

.close-button {
  sprite($close);
}

.open-button {
  sprite($open);
}
1
2
3
4
5
6
7
8
9

使用图片占位符

image-trace-loaderopen in new window 这个包加载图片,同时以 image/svg+xml 的 url 编码的形式输出图片。与 file-loaderurl-loader 一起使用,可以实现在请求真实图片的时候,先试用图片占位符显示。

lqip-loaderopen in new window 这个包实现的功能类似,但是 lqip-loader 会用一个模糊图片替代。

代码中如何使用图片

除了在样式中通过 @importurl() 的方式引用图片,在代码我们还可以这么用:

import src from './avatar.png';

const Profile = () => <img src={src} />;
1
2
3

从 Webpack 5 开始,我们还可以这么用:

const Profile = () => <img src={new URL('./avatar.png', import.meta.url)} />;
1

同时也可以动态加载图片

const src = require(`./avatars/\${avatar}`);
1

总结

通过 type 字段在调整不同资源的加载方式。在 Webpack 5 以前,通过 file-loaderurl-loader 来实现。

通过根据图片的大小来决定图片输出的方式。

可以将多个小图片合并成一个雪碧图,来减少网络请求。

Webpack 还支持动态加载图片。

关注微信公众号,获取最新推送~