Vue 项目之 Webpack 打包图片资源——Asset Modules 的使用

1,767 阅读3分钟

「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战

前面我们讲了 file-loaderurl-loader 的使用,url-loader 可以替换掉 file-loader,在开发中,如果我们想把所有图片全部做单独的打包,可以选择使用 file-loader,而如果想把图片转成 base64 编码,就可以选择使用 url-loader

下面,我们再来介绍一个 Webpack5 中的新功能:Asset Module

我们当前项目中使用的 webpack 版本是 Webpack5,在 Webpack5 之前,加载资源文件(字体、图标等等)需要使用一些 loader,比如 raw-loader(现在用的不多,在特殊场景会用到)、url-loaderfile-loader;而从 Webpack5 开始,我们可以直接使用资源模块类型(asset modules type,来替代前面的这些 loader。资源模块类型(asset modules type)通过添加 4 种新的模块类型,来替换所有这些 loader

  • asset/resource 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现;
  • asset/inline 导出一个资源的 data URI,之前通过使用 url-loader 实现;
  • asset/source 导出资源的源代码,之前通过使用 raw-loader 实现;
  • asset 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader 并配置资源体积限制实现;

因此,前面我们配置的 file-loaderurl-loader 现在就可以替换成 Asset Modules 了,我们来修改 webpack.config.js 中的内容:

...

module.exports = {
  ...
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/i,
        use: [
          'style-loader',
          'css-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(jpe?g|png|gif|svg)$/,
        type: "asset/resource" // 使用类型为 asset/resource 的 Asset Modules
      }
    ]
  }
}

我们在规则对象中设置 type: "asset/resource",就相当于使用了 file-loader,即将匹配到的所有图片文件都进行单独的打包。修改完配置后,我们先删除项目中的 ./build 文件夹,再来打包看下效果:

image-20211112185801216

当然,我们最常用的可能是 asset 类型的 Asset Modules,所以我们再来修改 webpack.config.js 中的内容:

...

module.exports = {
  ...
  module: {
    rules: [
      ...
      {
        test: /\.(jpe?g|png|gif|svg)$/,
        type: "asset", // 使用类型为 asset 的 Asset Modules,
        parser: {
          dataUrlCondition: {
            maxSize: 100 * 1024 // 小于 100kb 的文件将会被当作 asset/inline 类型对待,即会进行 base64 编码;否则会被当作 asset/resource 类型对待,即会被做单独的打包
          }
        }
      }
    ]
  }
}

修改完配置后,我们先删除项目中的 ./build 文件夹,再来打包看下效果:

image-20211112191309044

现在,一张大小为 148kb 的图片被单独打包了,而另一张大小为 56kb(小于 100kb)的图片则被编码成了 base64 编码格式打包进了 bundle.js 中。

如果只是配置了 type: 'asset',而没有手动配置 Rule.parser.dataUrlCondition.maxSize 选项,那么 webpack 会默认将大小在 8kb 以下(不包括 8kb)的文件作为 asset/inline 类型对待,否则作为 asset/resource 类型对待。具体内容可以阅读官方文档:

webpack.js.org/guides/asse…

如果想把单独打包的图片文件放在一个 img 文件夹下,我们可以这样做:

...

module.exports = {
  ...
  module: {
    rules: [
      ...
      {
        test: /\.(jpe?g|png|gif|svg)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 100 * 1024
          }
        },
        generator: {
          filename: 'img/[name]_[hash:6][ext]' // 注意,这里 [ext] 获取到的扩展名前面已经带了 . 号
        }
      }
    ]
  }
}

修改完配置后,我们先删除项目中的 ./build 文件夹,再来打包看下效果:

image-20211112194216090

你也可以这样配置(用得较少):

const path = require('path');

module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, './build'),
    filename: 'bundle.js',
    assetModuleFilename: 'img/[name]_[hash:6][ext]' // 指定 asset modules 的输出文件名
  },
  module: {
    rules: [
      ...
      {
        test: /\.(jpe?g|png|gif|svg)$/,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 100 * 1024
          }
        },
        // generator: {
        //   filename: 'img/[name]_[hash:6][ext]'
        // }
      }
    ]
  }
}

关于自定义 Asset ModulesResource assets 的输出文件名的具体内容可以查阅官方文档:

webpack.js.org/guides/asse…

有了 Asset Modules 之后,我们以后就不需要再使用 file-loaderurl-loader 了,甚至都不需要安装它们了,当然,前提是从 Webpack5 开始。

以上,就是关于 Webpack5 最新的打包资源的方式。