Webpack5新特性:使用 Assets Module 处理图片和字体资源

简介: 本文介绍了 Webpack5 的 Assets Module ,是其内置的用来处理图片字体文件等资源模块的新功能。相比与过去通过 loader 的方式去处理,更加方便和简洁。

前言

Webpack 是一个 JavaScript 的模块打包器。在 Webpack 的世界,一切等待打包的源码都是模块,一个文件就是一个模块。

Webpack 基于 Nodes.js 开发,采用 CommonJS 模块化规范,所以默认只能处理 .js.json 类型的模块。而项目中经常用到的文件类型有 .csslessscss这类样式文件,也有图片资源比如 .png.jpg等,还有字体文件比如.tffwoff等,对于使用前端框架开发的项目,还有 .vue.jsx 等文件类型。然而这些类型的模块 Webpack 是不认识的,需要对应的 loader 模块加载器来处理一下,从而让 Webpack 识别和打包。

本文主要介绍 Webpack5 的一个新特性——Assets Module。它是一种新的用来处理图片和字体资源模块的方式。

Asset Modules

在 webpack5 以前,通常使用 file-loader 和 url-loader 来处理图片和字体文件等资源,形如:

{
  test: /\.(png|jpe?g|gif|webp|svg)$/,
  use: [
    {
      loader: 'url-loader',
      options: {
        limit: 4096,
        fallback: {
          loader: 'file-loader',
          options: {
            name: 'img/[name].[hash:8].[ext]'
          }
        }
      }
    }
  ]
}

而 webpack5 提供了一个新特性叫作 Asset Modules,在内部实现了对资源模块的支持。Asset Modules 提供了4种资源模块的类型,而无需再额外配置其他的 loader 来对资源模块进行处理,分别是:

  • asset/resource :构建出一个单独的文件并导出 URL。相当于以前的 file-loader
  • asset/inline :导出资源模块的Data URI 内嵌到 html 或 css 文件。相当于以前的 url-loader
  • asset/source :导出资源模块的源代码。相当于以前的 raw-loader
  • asset :在导出 Data URI 和导出一个单独文件之间自动进行选择。以前可以通过使用 url-loaderlimit 配置项来实现。

下面就这几种 Assets Module 的类型进行介绍。

准备工作

创建一个演示环境:

mkdir assets-module

cd assets-module

pnpm init

安装依赖:

pnpm add -D webpack webpack-cli css-loader style-loader

准备好的初始文件有:

image-20220803120126307

webpack 的配置文件中对于 .css 做了配置:

{
    test: /\.css$/,
    use: ['style-loader', 'css-loader'],
}

asset/resource

该配置相当于以前的 file-loader,用来将模块单独导出一个文件,并提供一个 URL 来使用该文件

在 index.html 中写一个盒子,通过样式设置背景图:

<body>
    <div class="guodegang"></div>
    
    <script src="./dist/main.js"></script>
</body>

在 index.css 中设置一个样式类:

.guodegang {
  width: 600px;
  height: 400px;
  background-size: cover;
  background-image: url(./assets/images/guodegang.png);
}

入口文件引入该样式文件:

import './index.css'

webpack 配置对图片资源的处理规则:

{
  test: /\.(png|jpe?g|gif|webp|svg)$/,
  type: 'asset/resource'
}

执行打包命令:

pnpm webpack

打包的结果是生成一个 hash 值命名的图片文件:

image-20220803120745235

浏览器打开 index.html 文件:

image-20220803120707093

asset/inline

该配置相当于以前的 url-loader将文件通过 base64 编码转为 Data URI 的格式 ,并内联到使用它的文件中。

在 index.html 中设置一个新的盒子:

<body>
    <div class="lijian"></div
        
    <script src="./dist/main.js"></script>
</body>

在 index.css 中设置一个样式类:

.lijian {
  width: 600px;
  height: 350px;
  background-size: cover;
  background-image: url(./assets/images/lijian.webp);
}

配置模块的打包规则:

{
    test: /\.(png|jpe?g|gif|webp|svg)$/,
    type: 'asset/inline'
}

执行打包命令,看看打包的结果,会发现 dist 目录下并没有生成新的文件。但是我们打开 index.html,发现图片文件其实已经被打包好了:

image-20220803121048153

这是因为 asset/inline 的配置,会将源码中引入的模块转译为 Data URI 内嵌到输出文件中。

一个问题

将文件编译为 Data URI 使用,可以节省 HTTP 请求,是一个性能优化的点。但是将图片文件经过 base64 编码转为 Data URI,体积会增加大约33%。这其中涉及到一些编码的知识,有兴趣的朋友可以亲自尝试一下。所以,对于一些比较大的文件来说,转为 Data URI 会明显增加打包后文件的体积,从而会加大对带宽资源和流量的需求。

前端性能优化中最基本的两条规则就是减少 HTTP 请求,压缩资源减少文件体积。但是这个配置项,刚好是截然相反。能减少 HTTP 请求,但会增加文件体积。

那么该如何均衡这两种方式呢?换句话说,该如何确定什么时候使用 asset/inline ,什么时候使用 asset/resource 呢?

在以前的开发中有一种雪碧图的优化方案,就是将一些小的图标放到一张文件中使用,这样很多个图标就只需要发送一次 HTTP 请求就可以了。

所以, asset/inline 这种方式,更适合于一些打包一些体积较小的文件,将其内联来减少请求的数量。对于较大的文件,还是使用 asset/resource 的方式,打包成单独的文件

那么具体该如何设置,让webpack 智能的根据文件大小来执行不同的打包方式呢?下面的 asset 就是了。

asset

使用这个配置,默认小于 8kb 的文件将被视为inline模块类型,将转为 Data URI 以内联的方式使用;大于 8kb 的文件将被视为resource 模块类型,打包成单独的文件。

{
   test: /\.(png|jpe?g|gif|webp|svg)$/,
   type: 'asset'
}

可以通过 parser.dataUrlCondition.maxSize 属性来修改默认的大小:

{
   test: /\.(png|jpe?g|gif|webp|svg)$/,
   type: 'asset',
   parser: {
     // 生成Data URI 的条件
     dataUrlCondition: {
        // 当资源模块不超过 4kb 时,生成 DataURI,超过 4kb 时,单独打包成文件
        maxSize: 4 * 1024 // 4b
     }
   }
}

一般,在开发中我们使用默认的配置就好。

aseet/source

这种用的比较少,相当于以前的 raw-loader。示例配置:

{
  test: /\.txt/,
  type: 'asset/source'
}

处理字体文件

字体文件和图片同属于资源模块,同样使用上面的配置就好:

{
   test: /\.(eot|ttf|otf|woff2?)$/,
   type: 'asset'
}

使用一下看看效果。

index.html 中使用字体图标:

<body>
    <div>
        <i class="iconfont icon-home"></i>
        <i class="iconfont icon-user"></i>
    </div>

    <script src="./dist/main.js"></script>
</body>

入口文件中引用字体图标的样式类:

import './assets/fonts/iconfont.css'

执行打包命令,看下效果:

由于字体文件比较小,不足 8kb,所以字体文件被编码为 Data URI 进行使用了。

打包文件的重命名和路径修改

默认打包后的文件,会统一放到输出目录中,文件名为 hash 值。

当资源文件过多时,比较混乱,不易管理。所以 webpack 还提供了两个配置项和一些占位符,可以实现自定义模块的输出路径和文件名:

  • output.assetModuleFilename:对所有模块生效
  • generator.filename:对具体某个类型的模块生效
  • [name]:模块的原始文件名
  • [hash]:模块文件的哈希值
  • [ext]:模块的原始扩展名

示例配置:

{
   test: /\.(png|jpe?g|gif|webp|svg)$/,
   type: 'asset',
   generator: {
     filename: 'img/[name].[hash:8][ext]'
   }
},

{
  test: /\.(eot|ttf|otf|woff2?)$/,
  type: 'asset',
  generator: {
    filename: 'fonts/[name].[hash:8][ext]'
  }
}

对于体积较大的文件,将图片文件打包进 dist/img 目录下,将字体文件打包进 dist/fonts 目录下。

再次打包看下效果:

总结

本文介绍了 Webpack5 的一个新特性 Assets Module 资源模块,主要用来代替以前 file-loader、 url-loader 和 raw-loader 来对图片、字体文件等资源模块进行处理。Webpack5 提供了4种类型资源模块,用法和区别已经在上文中演示过了,大家可根据需要灵活选用。同时,还可以根据配置自定义模块的输出路径和文件名,方便打包资源的管理。

在阅读文档和使用的过程中,个人感觉,与其说是 Assets Module 提供了四种模块类型,不如说是针对资源模块提供了4种不同的打包方式,将 type 理解为方式,而非类型,似乎更能体现 assetasset/resourceasset/inlineasset/raw 的名字上的区别。或许是我思考过度了,你认为呢?欢迎朋友们留言评论,一起讨论!

目录
相关文章
|
6月前
|
JavaScript 前端开发
webpack成长指北第9章---webpack如何对icon字体进行打包
webpack成长指北第9章---webpack如何对icon字体进行打包
126 1
|
JavaScript 前端开发
webpack基本配置,asset资源
webpack基本配置,asset资源
|
1月前
|
前端开发 UED
Webpack 中处理 CSS 和图片资源的多 Loader 配置
【10月更文挑战第12天】 处理 CSS 和图片资源是 Webpack 配置中的重要部分。通过合理选择和配置多个 Loader,可以实现对这些资源的精细处理和优化,提升项目的性能和用户体验。在实际应用中,需要不断探索和实践,根据项目的具体情况进行灵活调整和优化,以达到最佳的处理效果。通过对 Webpack 中多 Loader 处理 CSS 和图片资源的深入了解和掌握,你将能够更好地应对各种复杂的资源处理需求,为项目的成功构建和运行提供坚实的基础。
55 1
|
2月前
|
前端开发
umi webpack配置图片资源转base64
umi webpack配置图片资源转base64
|
6月前
|
缓存 资源调度 监控
Webpack 5新特性详解与性能优化实践
Webpack 5通过确定性的Chunk ID、模块ID和导出ID实现了长期缓存,这意味着相同的输入将始终产生相同的输出。这样,当你的用户再次访问更新后的网站时,浏览器可以重用旧的缓存,而不是重新下载所有资源。
85 2
|
6月前
|
JavaScript 前端开发
webpack成长指北第6章---webpack的图片引入
webpack成长指北第6章---webpack的图片引入
56 0
|
6月前
|
JSON JavaScript 前端开发
对webpack的理解——打包样式资源
对webpack的理解——打包样式资源
52 0
|
JavaScript 前端开发
[Node] Node.js Webpack打包图片-Js-Vue
[Node] Node.js Webpack打包图片-Js-Vue
|
前端开发 JavaScript
Vue--webpack打包css、image资源
Vue--webpack打包css、image资源
|
存储 缓存 JSON
webpack拓展篇(六十七):webpack5 新特性解析
webpack拓展篇(六十七):webpack5 新特性解析
400 0
webpack拓展篇(六十七):webpack5 新特性解析