likes
comments
collection
share

Webpack5 Asset Module 使用小结

作者站长头像
站长
· 阅读数 15

我们常用 raw-loaderurl-loaderfile-loader 来处理图片、字体等资源文件,Webpack5 为我们提供了一种更简单、更方便的方式来替换上述 loader,这既是本文我们将要介绍的 Asset Module(即资源模块)。

分类

Webpack5 为我们提供了 asset/resourceasset/inlineasset/sourceasset 四种资源类型,具体介绍如下所示:

  • asset/resource:将资源文件输出到指定的输出目录,作用等同于 file—loader
  • asset/inline:将资源文件内容以指定的格式进行编码(一般为 base64),然后以 data URI 的形式嵌入到生成的 bundle 中,作用等同于 url-loader
  • asset/source:将资源文件的内容以字符串的形式嵌入到生成的 bundle 中,作用相当于 raw-loader
  • asset:作用等同于设置了 limit 属性的 url-loader,即资源文件的大小如果小于 limit 的值(默认值为 8kb),则采用 asset/inline 模式,否则采用 asset/resource 模式。

使用

基本使用

Asset Module 的使用非常简单,只需将之前的配置:

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif)$/i,
        use: [
          {
            loader: 'file-loader',
          },
        ],
      },
    ],
  },
};

调整为以下配置即可:

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif)$/i,
        type: 'asset' // 可用值:asset/resource、asset/inline、asset/source、asset
      },
    ],
  },
};

内联使用

除了通过配置文件,我们也可通过内联语法来使用相关 loader,比如:

// src/index.js
import avatar from 'file-loader!./avatar.png';

上例中,Webpack 将调用 file-loader 来处理资源 ./avatar.png,那么在 Webpoack5 的 Asset Module 中又该如何进行内联操作呢?先看下面的例子:

// src/index.js
import avatar from './avatar.png?image';

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        type: 'asset/resource',
        resourceQuery: /image/,
      },
    ],
  },
};

通过例子可知,Webpack5 的 Asset Module 内联语法涉及以下两个步骤:

  • 资源引用时加上 query 参数(比如上例中的 ?image);
  • 在配置文件中添加 resourceQuery 配置项。

其中 resourceQuery 的常用格式为:

  • 字符串:上例的配置为 ?image

  • 正则表达式:上例的配置为 /image/

  • 对象

    • { and: [] }:必须匹配数组中的所有条件;
    • { or: [] }:只需匹配数组中的任一条件;
    • { not: [] }:必须排除数组中的所有条件。

常用配置

assetModuleFilename

默认情况下,在处理 resource 类型的资源时,相关资源会被输出到 output.path 目录下(文件命名规则为 [hash][ext][query]),我们可通过设置 output.assetModuleFilename 来改变其输出目录:

// webpack.config.js
module.exports = {
  output: {
    path: path.resolve(__dirname, 'dist'),
    assetModuleFilename: './static/images/[hash][ext][query]',
  },
};

这里需要注意的是,assetModuleFilename 的值须为相对路径,如值为绝对路径,将抛出以下异常:

Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
 - configuration.output.assetModuleFilename: A relative path is expected. However, the provided value "/home/nanjingboy/test-webpack/static/images/[hash][ext][query]" is an absolute path!

该配置仅适用于 assetasset/resource 资源类型。

generator

在配置 module.rules 时,可配置 generator 来对资源的处理进行进一步控制,该配置有以下几个属性:

  • filename

    • 作用等同于上文所说的 output.assetModuleFilename,值也必须为相对路径
    • 如果同时指定了该属性和 output.assetModuleFilename,将忽略 output.assetModuleFilename 的值;
  • dataUrl

    • 在处理 inline 类型的资源时,该资源默认对资源进行 base64编码,可通过该属性来改变其编码方式;
    • 该属性值为函数,其签名为 (content: string) => string
    • 该属性仅适用于 assetasset/inline 资源类型。

上述配置的示例如下:

// webpack.config.js
module.exports = {
  modules: {
    rules: [
      {
        test: /\.(png|jpe?g|gif)$/i,
        type: 'asset',
        generator: {
          filename: './static/images/[hash][ext][query]',
          dataUrl: content => {
            return encode(content.toString());
          },
        },
      },
    ],
  },
};

parser.dataUrlCondition

在配置 module.rules 时,可通过 parser.dataUrlCondition 来决定是按照规则 asset/inline,还是按照规则 asset/resource 来处理资源,该配置有以下两种用法:

  • 指定 maxSize 属性:

    • typeasset 时,如果资源大小小于 8kb,按照 asset/inline 的规则处理资源,否则按照 asset/resource 的规则处理资源;
    • 可通过指定该属性来改变其界限值(单位为 byte);
    • 该属性仅适用于 asset 资源类型。
    // webpack.config.js
    module.exports = {
      modules: {
        rules: [
          {
            test: /\.(png|jpe?g|gif)$/i,
            type: 'asset',
            parser: {
              dataUrlCondition: {
                maxSize: 4 * 1024 // 4kb,单位为 byte,默认值为 8kb
              },
            },
          },
        ],
      },
    };
    
  • 指定一个函数:

    • 该函数返回 boolean 类型(true 使用 asset/inline 规则,false 使用 asset/resource 规则):
    • 该属性仅适用于 asset 资源类型。
    // webpack.config.js
    module.exports = {
      modules: {
        rules: [
          {
            test: /\.(png|jpe?g|gif)$/i,
            type: 'asset',
            parser: {
              dataUrlCondition: (source, { filename, module }) => {
                // doSomething....
                return true;
              },
            },
          },
        ],
      },
    };
    

总结

本文我们对 Webpack5 Asset Module(即资源模块)的使用进行了简短介绍,如有疏漏之处还望诸位海涵,祝大家快乐编码每一天。