type
status
date
slug
summary
tags
category
icon
password

一、前言

上一篇讲解了 webpack5 的基础配置。这一篇文章将会介绍如何利用 webpack 中的 Loaders 对静态资源做处理,Loaders 是 webpack 的核心概念之一。
静态资源主要包括以下几方面的内容:
  • 样式文件(CSS)
  • 图片(Images)
  • 字体(Fonts)
  • 数据文件(Data)
  • ...
文件结构:
assets 文件夹中存放了若干静态文件(例如:字体、图标、图片、文本、样式以及 JS 文件),中间根据文件的不同,又分了几个文件夹。这里为了方便起见,文件名均已作简化处理。
index.js
引入了各种文件模块并放入变量中,每一个模块在打包以后都有值,可以正常使用。

二、Loaders — 加载器

webpack enables use of loaders to preprocess files. This allows you to bundle any static resource way beyond JavaScript. You can easily write your own loaders using Node.js.
简单来说,loaders 可以帮我们预处理任何静态文件并打包
例如:图片文件,样式文件、html 文件,甚至是一些数据文件:txt 文件、xml 文件……
那么,如何配置呢?

三、Asset Modules — 静态资源模块

根据 Webpack5 的文档,它简化了之前版本对于文件方面的配置,提供了 Asset Modules (静态资源模块),替代了之前常用的 raw-loader、url-loader、file-loader
也就是说不用再安装这几个 loader 了,直接通过一行type: 'asset' 搞定,书写更加方便!(注意 module 中 type 的设置!)
每次打包后,文件都会根据 output 的配置放进输出文件夹,但是对于压缩处理的文件则不会被打包到文件夹,只会以base64 编码格式或者 URI 编码等格式存在于 bundle.js 的源码中。
  • 源码中的 base64
    • notion image
  • 源码中的 URI
    • notion image
默认情况下,当文件小于 8 kb 则会采用 base64 编码,那么上面出现的 URI 编码怎么设置的呢?

1. 特殊处理

某些文件需要特殊处理。例如,SVG 文件转换为 URI 编码后,与 base64 相比,体积会更小;
处理 txt、xml 文件 type: 'asset/source' 更好,它会导出资源的源码,这样就能看到全貌,而非 base64 格式的编码字符串。
最小化 SVG 文件需要安装一个第三方库:mini-svg-data-uri.
安装之后,重新配置如下:
至此,打包完成。现在,看看这些文件模块究竟被打包成什么数据了,在 index.js 文件中添加如下代码:
浏览器页面展示如下:
notion image
可以看到 SVG 文件 ( icon-svg ) 是被处理成 URI 编码的!

2. 配置静态文件名

默认情况下,打包以后的文件是散在 dist 文件夹中的,难以区分和维护。
现在,需要将他们分门别类地放进对应的文件夹中,就需要对文件名做统一的管理。
webpack.config.js
第 23 - 25 行,用于单独配置静态文件名;
第 12 行,assetModuleFilename: 'assets/[name][ext]', 用于设置全局的静态文件路径及文件名。如果文件模块没有单独进行配置,就按照这个来设置文件名。
其中,[name] 表示原来的文件名,[hash] 表示散列值,[ext] 表示文件后缀。这些都属于占位符(placeholders),在 webpack4 中有提到:https://v4.webpack.js.org/loaders/file-loader/#placeholders

3. asset 类型

当 type 设置为'asset',就会按照以下的策略去打包文件:
  • 如果一个模块大小超过 8 kb(这个值是默认的),就使用 asset/resource,被打包进输出文件夹中。(类似于 file-loader)
  • 否则,就使用 asset/inline,内联到打包文件中。(类似于 url-loader)
区别在于:前者会被单独放进输出文件夹中,后者被处理成 base64 编码字符串内敛进打包出的 JS 文件中。
后者的好处在于减少一次 http 请求,但是过长的字符串也会加重 js 的体积导致加载变慢,因此需要根据实际情况来确定到底采用哪一种方式去处理文件。
注意,当被作为后者处理时,是可以设置编码方式的,例如上面提到的特殊处理。
手动通过 Rule.parser.dataUrlCondition.maxSize 去设置两者的界限:
另外,除了asset/resourceasset/inline,还有一个上文提到的,用于处理 txt、xml 文件的asset/source,它相当于 webpack4 的 raw-loader。

三、样式文件的处理

1. style-loader & css-loader

style-loader 和 css-loader 是相辅相成的。
  • style-loader:将 <style> 标签插入到 DOM 中。
  • css-loader:解析通过 @import、url()、import/require() 这些方式引入的样式文件。
安装 loaders:
webpack.config.js
注意两个 loader 的位置,要反过来写。
index.js
reset.css
解释:reset.css 中引入了字体图标(来自 iconfont),index.js 中通过import的方式引入了这个 css 文件,并使用了这个字体图标。
其中,
import './assets/styles/reset.css'
onst reset = require('./assets/styles/reset.css');
这两段语句背后的 CSS 代码就是通过 css-loader 去解析的。
控制台展示如下:
notion image
上图中,在 CSS 样式被 css-loader 解析完成后, <style> 标签通过 style-loader 插入到 DOM 中。

2. sass-loader

  • sass-loader:加载一个 Sass/SCSS 文件,并编译成 CSS。
安装:
webpack.config.js
index.js
global.scss
控制台展示如下:
notion image
上图第二个 <style> 标签内的样式代码就是 global.scss 中转译成 css,并通过 style-loader 插入到 DOM 中的。

3. postcss-loader

PostCSS is a tool for transforming styles with JS plugins. These plugins can lint your CSS, support variables and mixins, transpile future CSS syntax, inline images, and more.

a) 安装

安装:
webpack.config.js
注意,postcss-loader 要放在最后。

b) 配置

AutoprefixerPostCSS plugin to parse CSS and add vendor prefixes to CSS rules using values from Can I Use.PostCSS Preset EnvPostCSS Preset Env lets you convert modern CSS into something most browsers can understand, determining the polyfills you need based on your targeted browsers or runtime environments.PostCSS SCSS SyntaxA SCSS parser for PostCSS.This module does not compile SCSS. It simply parses mixins as custom at-rules & variables as properties, so that PostCSS plugins can then transform SCSS source code alongside CSS.
插件需要安装一下:
在根目录下,新建:postcss.config.js
webpack.config.js 不需要修改。

四、补充:css-loader 的 options

不同的 loader 都会有各自的 options,css-loaders 有两个实用的 options。
  • importLoaders:The option importLoaders allows you to configure how many loaders before css-loader should be applied to @imported resources and CSS modules/ICSS imports. 简单来说,就是允许你在执行 css-loader 前,让某些资源要经过前面的 loaders 去处理的个数。
  • modules:Allows to enable/disable CSS Modules or ICSS and setup configuration. 允许你开启 CSS Module
webpack.config.js
注意,上面 importLoaders 设置为 2,表示匹配到样式文件时,都会去执行一开始的两个 loader,也就是 'sass-loader' 以及 'postcss-loader'.
至于 modules 设置为 true,则保证了样式模块的独立性,不会被互相覆盖。具体看下面的例子:

a) 不设置 modules 选项

src/assets/styles/global.scss
src/assets/js/createImg.js
src/index.js
在这种情况下,import './assets/styles/global.scss'这一句对全局的文件都有效果,因此它的后一句 import createImg from './assets/js/createImg.js'; 就会受到影响。影响的结果就是,createImg.js 文件中的第 7 行代码的样式添加,添加的就是 global.scss 中的第 15 行的选择器 'avatar' 的样式。
打包后,结果如图所示:
notion image

b) 将 modules 设置为 true

设置完后,代码不变的情况下,打包完成后,查看结果如图所示:
notion image
前后两张秋田犬均变成了超大的图,原因是样式没有作用到图片上。
当应用 CSS Module 时,要通过以下的方式添加样式:
(注意:这里仅对 index.js 中的代码作修改,使之恢复,而 createImg.js 模块中的代码不变,从而形成对比。)
src/index.js
打包后,结果如图所示:
notion image
通过对比,就可以发现,通过模块方式设置的秋田犬的样式是有的,而第一张则没有。
这种利用 CSS Module 的方式来添加样式的方法,解决了全局覆盖同名样式(一般是类名和 id)的尴尬情况。
阅读参考:

小结

以上,是本篇的所有内容。在 Webpack5 中,对于静态资源的处理,我们只要简单地设置 type 就能处理文件,非常方便。但是有些特殊情况还是需要去单独处理的,例如资源输出的路径及文件名的设置、URI 编码格式的设置、转 base64 的文件大小限制的设置。样式文件中,为了防止全局的样式污染,可以开启 CSS Module 来避免。
 
以上,如有谬误,还请斧正,希望这篇文章对你有所帮助,感谢您的阅读~
 
Webpack5 系列(三):开发环境的设置Webpack5 系列(一):基础篇
Eric 见嘉
Eric 见嘉
Less is more.
公告
type
status
date
slug
summary
tags
category
icon
password
💭
合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。

关于我
土木转行的前端开发工程师,陆续分享技术干货。
联系我
微信公众号:见嘉 Being Dev