03 【资源处理】
03 【资源处理】
Section titled “03 【资源处理】”在上一章,我们讲解了四种资源模块引入外部资源。除了资源模块,我们还可以通过 loader引入其他类型的文件。
什么是loader
webpack 只能理解 JavaScript 和JSON文件,这是 webpack 开箱可用的自带能力。 loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块,以供 应用程序使用,以及被添加到依赖图中。
在 webpack 的配置中,loader 有两个属性:
test属性,识别出哪些文件会被转换。use属性,定义出在进行转换时,应该使用哪个 loader。
1.HTML资源
Section titled “1.HTML资源”在index.html中是采用手动修改路径,然后才引入的,这样并不方便。我们想要实现的是webpack打包完成后自动帮助我们引入相关的资源。
于是就可以使用社区插件中的HtmlWebpackPlugin插件。
自动引入资源
1、下载 html-webpack-plugin 插件
2、在 webpack.config.js 文件中引入插件并调用
使用,当直接new HtmlWebpackPlugin()的时候,会在dist文件夹下生成一个index.html,但是它只有一些基础的配置。如果想要自行配置,则需要一个自己给定的模板index.html,然后增加一些配置,配置的参考文档:https://github.com/jantimon/html-webpack-plugin#options
该插件将为你生成一个 HTML5 文件, 在 body 中使用 script 标签引入你所有 webpack 生成的 bundle。 只需添加该插件到你的 webpack 配置中
-
不传参的情况:
new HTMLWebpackPlugin():会在配置的output文件夹创建一个空的html, 自动引入打包输出的所有资源,包括js, css…; -
设置参数template:复制设置的
'./src/index.html'文件到配置的output文件夹,并自动引入打包输出的所有资源。
模板index.html
如果你有多个 webpack 入口,他们都会在已生成 HTML 文件中的 <script> 标签内引入。
如果在 webpack 的输出中有任何 CSS 资源(例如,使用 MiniCssExtractPlugin 提取的 CSS),那么这些资源也会在 HTML 文件 <head> 元素中的 <link> 标签内引入。
打包:

查看 app.html 内容:
这次打包应用到了我们的模板文件 index.html , 并且生成了新的文件 app.html , 文 件里自动引用的 bundle.js 也从 迁移到了里。
Webpack 会在输出目录中新创建一个 HTML 文件,在原始的 HTML 文件中无需引入 JS 文件,通过 Webpack 编译后的 HTML 文件会自动引入。
官方说明:https://webpack.docschina.org/plugins/html-webpack-plugin/
配置选项:https://github.com/jantimon/html-webpack-plugin#options
2.样式资源
Section titled “2.样式资源”Webpack 本身是不能识别样式资源的,所以我们需要借助 Loader 来帮助 Webpack 解析样式资源
我们找 Loader 都应该去官方文档中找到对应的 Loader,然后使用
官方文档找不到的话,可以从社区 Github 中搜索查询
.css文件: style-loader, css-loader;
css-loader:将css文件转换成commonjs模块加载到js中,css代码被转换成了样式字符串。(转换后得到的commonjs模块可以理解为:用js给元素动态添加样式的那种代码);style-loader:创建style标签,将css-loader生成的样式资源插入进去,添加到head中,使样式生效。
.less文件: style-loader, css-loader, less-loader;
less-loader:将less文件编译成css文件;- 注:要想
less-loader生效,还需要下载less(npm install less -D)。
.scss/.sass文件: style-loader, css-loader, sass-loader;
sass-loader:将sass或scss文件编译成css文件;- 注:要想
sass-loader生效,还需要下载node-sass(npm install node-sass -D)。
2.1 css
Section titled “2.1 css”下载包
注意:需要下载两个 loader
功能介绍
css-loader:负责将 Css 文件编译成 Webpack 能识别的模块style-loader:会动态创建一个 Style 标签,里面放置 Webpack 中 Css 模块内容
此时样式就会以 Style 标签的形式在页面上生效
配置
模块 loader 可以链式调用。链中的每个 loader 都将对资源进行转换。链会逆序执 行。第一个 loader 将其结果(被转换后的资源)传递给下一个 loader,依此类推。 最后,webpack 期望链中的最后的 loader 返回 JavaScript。
应保证 loader 的先后顺序: 'style-loader' 在前,而 'css-loader' 在后。如果 不遵守此约定,webpack 可能会抛出错误。webpack 根据正则表达式,来确定应该 查找哪些文件,并将其提供给指定的 loader。在这个示例中,所有以 .css 结尾的 文件,都将被提供给 style-loader 和css-loader。
这使你可以在依赖于此样式的 js 文件中 import './style.css' 。现在,在此模块执行过程中,含有 CSS 字符串的 <style>标签,将被插入到html文件的<head>中。
通过在项目中添加一个新的style.css文件,并将其import到我 们的 index.js 中:

07-manage-assets/src/style.css
在入口文件index.js里导入.css文件:

你应该看到页面背景颜色是浅黄色。要查看 webpack 做了什么,请检查页面(不要 查看页面源代码,它不会显示结果,因为<style> 标签是由 JavaScript 动态创建 的),并查看页面的 head 标签,包含 style 块元素,也就是我们在 index.js中 import 的 css 文件中的样式。
2.2 less&sass
Section titled “2.2 less&sass”下载样式处理解析器
sass-loader:负责将 Sass 文件编译成 css 文件sass:sass-loader依赖sass进行编译
在配置文件中添加解析器
在项目 src 目录下创建 style.less 文件:
在 index.js 文件中导入 less 文件

由预览的效果可见,页面的文字都添加了“红色”的样式。
不同的样式文件会新建一个
style标签
2.3 抽离CSS
Section titled “2.3 抽离CSS”Css 文件目前被打包到 js 文件中,当 js 文件加载时,会创建一个 style 标签来生成样式,这样对于网站来说,会出现闪屏现象,用户体验不好,我们应该是单独的 Css 文件,通过 link 标签加载性能才好。
在多数情况下,我们也可以进行压缩CSS,以便在生产环境中节省加载时间,同时还 可以将CSS文件抽离成一个单独的文件。实现这个功能,需要 mini-css-extractplugin 这个插件来帮忙。安装插件:
下载包
本插件会将取代style-loader, 将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载。
本插件基于 webpack v5 的新特性构建,并且需要 webpack 5 才能正常工作。
之后将 loader 与plugin添加到你的 webpack 配置文件中:
配置
⚠️ 注意,如果你从 webpack 入口处导入 CSS 或者在 初始 chunk 中引入 style,
mini-css-extract-plugin则不会将这些 CSS 加载到页面中。请使用html-webpack-plugin自动生成link标签或者在创建index.html文件时使用link标签。
查看打包完成后的目录和文件:

07-manage-assets/dist/app.html
如果是生成模式,将自动压缩css文件,无需额外配置。
官方文档:https://webpack.docschina.org/plugins/mini-css-extract-plugin
2.4 压缩css(生产模式)
Section titled “2.4 压缩css(生产模式)”下载包
在配置文件中进行配置
压缩 CSS 代码,仅在生产模式下有效
官方文档:https://webpack.docschina.org/plugins/css-minimizer-webpack-plugin/
3.图片资源
Section titled “3.图片资源”过去在 Webpack4 时,我们处理图片资源通过 file-loader 和 url-loader 进行处理
现在 Webpack5 已经将两个 Loader 功能内置到 Webpack 里了,我们只需要简单配置即可处理图片资源
配置
对图片资源进行优化
将小于某个大小的图片转化成 data URI 形式(Base64 格式)
- 优点:减少请求数量
- 缺点:体积变得更大
此时输出的图片文件就只有两张,有一张图片以 data URI 形式内置到 js 中了 (注意:需要将上次打包生成的文件清空,再重新打包才有效果)
添加图片资源
- src/images/1.jpeg
- src/images/2.png
- src/images/3.gif
使用图片资源
- src/less/index.less
07-manage-assets/src/index.js
启动服务,打开浏览器:

我们看到,通过样式把背景图片加到了页面中。
4.字体资源
Section titled “4.字体资源”同样可以使用webpack内置的asset module模块来加载引入字体文件。 这里我使用阿里矢量图标库的字体图标来演示。
下载字体图标文件
- 打开阿里巴巴矢量图标库open in new window
- 选择想要的图标添加到购物车,统一下载到本地
解压之后,是这么一大坨东西,而我要修改的其实仅仅是这个文件:

具体的使用方法可以查看这个地址:https://www.iconfont.cn/help/detail?spm=a313x.7781069.1998910419.d8cf4382a&helptype=code
添加字体图标资源
-
src/fonts/iconfont.ttf
-
src/fonts/iconfont.woff
-
src/fonts/iconfont.woff2
-
src/css/iconfont.css
- 注意字体文件路径需要修改
-
src/index.js
index.html
配置
运行指令

5.数据资源
Section titled “5.数据资源”此外,可以加载的有用资源还有数据,如 JSON 文件,CSV、TSV 和 XML。类似于 NodeJS,JSON 支持实际上是内置的,也就是说 import Data from './data.json' 默认将正常运行。
要导入 CSV、TSV 和 XML,你可以使用 csv-loader 和 xml-loader。让我们处理加载这三类文件:
安装包
添加配置:
现在,你可以 import 这四种类型的数据(JSON, CSV, TSV, XML)中的任何一种,所 导入的 Data 变量,将包含可直接使用的已解析 JSON:
创建两个文件:
07-manage-assets/src/assets/data.xml
07-manage-assets/src/assets/data.csv
在入口文件里加载数据模块,并在控制台上打印导入内容:
07-manage-assets/src/index.js

由此可见, data.xml 文件转化为一个JS对象, data.cvs 转化为一个数组。
6.自定义 JSON 模块 parser
Section titled “6.自定义 JSON 模块 parser”通过使用 自定义 parser 替代特定的 webpack loader,可以将任何 toml 、 yaml 或 json5 文件作为 JSON 模块导入。
假设你在 src 文件夹下有一个 data.toml 、一个 data.yaml 以及一个 data.json5 文件
下载包
配置
在主文件中引入模块,并打印内容:
现在, toml 、 yaml 和 json5 几个类型的文件都正常输出了结果。
7.js规范化
Section titled “7.js规范化”可组装的 JavaScript 和 JSX 检查工具。
这句话意思就是:它是用来检测 js 和 jsx 语法的工具,可以配置各项功能
我们使用 Eslint,关键是写 Eslint 配置文件,里面写上各种 rules 规则,将来运行 Eslint 时就会以写的规则对代码进行检查
7.1 配置文件
Section titled “7.1 配置文件”配置文件由很多种写法:
-
.eslintrc.*:新建文件,位于项目根目录-
.eslintrc -
.eslintrc.js -
.eslintrc.json -
区别在于配置格式不一样
-
-
package.json中eslintConfig:不需要创建文件,在原有文件基础上写
ESLint 会查找和自动读取它们,所以以上配置文件只需要存在一个即可
7.2 具体配置
Section titled “7.2 具体配置”我们以 .eslintrc.js 配置文件为例:
- parserOptions 解析选项
-
rules 具体规则
"off"或0- 关闭规则"warn"或1- 开启规则,使用警告级别的错误:warn(不会导致程序退出)"error"或2- 开启规则,使用错误级别的错误:error(当被触发的时候,程序会退出)
更多规则详见:规则文档open in new window
-
extends 继承
开发中一点点写 rules 规则太费劲了,所以有更好的办法,继承现有的规则。
现有以下较为有名的规则:
- Eslint 官方的规则open in new window:
eslint:recommended - Vue Cli 官方的规则open in new window:
plugin:vue/essential - React Cli 官方的规则open in new window:
react-app
7.3 在 Webpack 中使用
Section titled “7.3 在 Webpack 中使用”-
下载包
-
定义 Eslint 配置文件
.eslintrc.js
也可以 npx eslint —init 生成
Airbnb: https://github.com/airbnb/javascript Standard: https://github.com/standard/standard Google: https://github.com/google/eslint-config-google XO: https://github.com/xojs/eslint-config-xo
-
修改 js 文件代码
index.js -
配置
执行
npx eslint ./src/,可以看到会输出一些error或者waring
我们期望
eslint能够实时提示报错而不必等待执行命令。 这个功能可以通过给自己的IDE(代码编辑器)安装对应的eslint插件来实现。webpack.config.js -
运行指令
7.4 VSCode Eslint 插件
Section titled “7.4 VSCode Eslint 插件”打开 VSCode,下载 Eslint 插件,即可不用编译就能看到错误,可以提前解决
但是此时就会对项目所有文件默认进行 Eslint 检查了,我们 dist 目录下的打包后文件就会报错。但是我们只需要检查 src 下面的文件,不需要检查 dist 下面的文件。
所以可以使用 Eslint 忽略文件解决。在项目根目录新建下面文件:
.eslintignore
vscode设置eslint保存文件时自动修复eslint错误_五虎战画戟的博客-CSDN博客
启动 vscode 打开项目,
windows : ctrl + shift + p 打开 搜索面板
MacBook : command + shift + p 打开 搜索面板
输入 settings.json,选择 .vscode 下的 settings.json
加入以下代码:
这个规则是在保存时按照你的项目中 eslint 配置 fix
*注意你~/Library/Application Support/Code/User/settings.json 中的规则尽量不要与项目中的规则产生冲突 *
7.5 overlay
Section titled “7.5 overlay”devServer.client.overlay 控制当出现编译错误或警告时,在浏览器中是否显示全屏覆盖。默认显示boolean = true object: { errors boolean = true, warnings boolean = true }
关闭浏览器全屏覆盖提示
webpack.config.js
如果你只想显示错误信息: webpack.config.js
8.js兼容处理
Section titled “8.js兼容处理”8.1 什么是JS兼容性处理?
Section titled “8.1 什么是JS兼容性处理?”其实就是把ES6及以上(后边简写为ES6+)新增的语法、API处理成ES5及以下的版本,解决某些浏览器(ie)上的兼容性报错问题。
8.2 babel的介绍
Section titled “8.2 babel的介绍”babel的出现,就是用于解决这样的问题,它是一个编译器,可以把不同标准书写的语言,编译为统一的、能被各种浏览器识别的语言 。

由于语言的转换工作灵活多样,babel的做法和postcss、webpack差不多,它本身仅提供一些分析功能,真正的转换需要依托于插件完成 。

8.3 babel的安装
Section titled “8.3 babel的安装”babel可以和构建工具联合使用,也可以独立使用
如果要独立的使用babel,需要安装下面两个库:
- babel-loader : 在 webpack 里应用 babel 解析 ES6 的桥梁
- @babel/core : babel 核心模块
- @babel/preset-env : 简单理解:就是一组 Babel 插件, 扩展 Babel 功能
@babel/preset-env: 一个智能预设,允许您使用最新的 JavaScript。@babel/preset-react:一个用来编译 React jsx 语法的预设@babel/preset-typescript:一个用来编译 TypeScript 语法的预设
regeneratorRuntime
这里有时还会有一些特殊的语法 例如 async await等,这样的语法就不好转换,因此还需要一个新的
库来处理,就需要 regenerator-runtime 来进行处理转换。
8.4 webpack配置
Section titled “8.4 webpack配置”配置文件
配置文件由很多种写法:
-
babel.config.*:新建文件,位于项目根目录
babel.config.jsbabel.config.json
-
.babelrc.*:新建文件,位于项目根目录
.babelrc.babelrc.js.babelrc.json
-
package.json中babel:不需要创建文件,在原有文件基础上写
Babel 会查找和自动读取它们,所以以上配置文件只需要存在一个即可
babel.config.js
webpack.config.js

然后运行就可以了,会把对应的es6语法转换成es5语法。
9.代码分离
Section titled “9.代码分离”我们的 js 都是打包输出到一个文件中的,当内容越来越多的时候,会导致单个文件体积十分巨大,所以我们就需要对代码进行分割,将一个巨大的文件,分割成多个中小型文件,然后可以按需加载或并行加载这些文件
代码分离是 webpack 中最引人注目的特性之一。此特性能够把代码分离到不同的 bundle 中,然后可以按需加载或并行加载这些文件。代码分离可以用于获取更小的bundle,以及控制资源加载优先级,如果使用合理,会极大缩减加载时间。
常用的代码分离方法有三种:
- 入口起点 :使用 entry 配置手动地分离代码。
- 动态导入 :通过模块的内联函数调用来分离代码
- 防止重复 :使用 SplitChunksPlugin 去重和分离 chunk。
9.1 入口起点( 不推荐 )
Section titled “9.1 入口起点( 不推荐 )”使用 entry 配置手动分离代码,如果多个入口共享的文件,会分别在每个包里重复打包。
这种方式的确存在一些隐患:
- 如果入口
chunk之间包含一些重复的模块,那些重复模块都会被引入到各个bundle中。 - 这种方法不够灵活,并且不能动态地将核心应用程序逻辑中的代码拆分出来。
9.2 防止重复
Section titled “9.2 防止重复”配置 entry 提取公用依赖
webpack.config.js
执行webpack命令,可以看到打包结果
已经提取出来shared.bundle.js,即为提取打包了lodash公用模块
index.bundle.js other.bundle.js体积也变小
查看dist/index.html可以看到三个文件都被加载了
SplitChunksPlugin
SplitChunksPlugin 插件可以能自动的帮助我们做公共模块的抽离。让我们使用这个插件,将之前的示例中重 复的 lodash 模块去除:
webpack 中 splitChunks 的默认配置
chunks
该参数有四种取值
async:动态导入的文件其静态依赖会根据规则分离initial:入口文件的静态依赖会根据规则分离all:所有的都会根据规则分离chunk => Boolean:返回 true 表示根据规则分离,false 则不分离
更多配置查看: SplitChunksPlugin
可以通过 import 方法对文件名进行自定义
9.3 动态导入
Section titled “9.3 动态导入”当涉及到动态代码拆分时,webpack 提供了两个类似的技术。
- 第一种,也是推荐选择的方式是,使用符合 ECMAScript 提案 的
import()语法 来实现动态导入。 - 第二种,则是 webpack 的遗留功能,使用 webpack 特定的 require.ensure 。
这里让我们尝试使用第一种方式,使用import()来进行动态导入
我们分别在 index.html、other.js、index.js 中添加如下代码

可以看到,打包文件多生成了一个叫 0.js 的文件,并且 html 中并没有引入该文件,点击按钮再看看会发生什么

生成了一个 script 标签,并加载了 0.js 文件,这就是动态导入。对于这个文件名称,不是很直观,我们使用魔法注释修改一下
最终打包生成的文件名就叫 other.js,如果希望加上 hash 值,可以在配置文件里添加一个参数
9.4 懒加载
Section titled “9.4 懒加载”懒加载或者按需加载,是一种很好的优化网页或应用的方式。这种方式实际上是先把你的代码在一些逻辑断点处分离开,然后在一些代码块中完成某些操作后,立即引用或即将引用另外一些新的代码块。这样加快了应用的初始加载速度,减轻了它的总体体积,因为某些代码块可能永远不会被加载。
math.js
src/index.js
效果:
点击按钮后才加载math.bundle.js并执行了函数打印输出结果

第一次加载完页面, math.bundle.js 不会加载,当点击按钮后,才加载 math.bundle.js 文件。
问题:
这样做可能会让用户的交互长时间没有响应的。原因就是待到交互时才进行模块的加载,可能时间会比较长 。由此,我们引入prefetch ,即预取。
9.5 预获取、预加载
Section titled “9.5 预获取、预加载”Webpack v4.6.0+ 增加了对预获取和预加载的支持。
在声明 import 时,使用下面这些内置指令,可以让 webpack 输出 “resource hint(资源提示)”,来告知浏览器:
- prefetch(预获取) :将来某些导航下可能需要的资源(当页面所有内容都加载完毕后,在网络空闲的时候,加载资源)
- preload(预加载) :当前导航下可能需要资源
prefetch
src/index.js
添加第二句魔法注释:webpackPrefetch: true
告诉 webpack 执行预获取。这会生成 并追加到页面头部,指示着浏览器在闲置时间预取 math.js 文件。
效果 可以看到math.bundle.js已经预先获取了
加载完成之后,浏览器又会去自动加载

我们发现,在还没有点击按钮时, math.bundle.js 就已经下载下来了。同时,在 app.html 里webpack自动添加了一句:

点击按钮,会立即调用已经下载好的 math.bundle.js 文件中的 add 方法:
preload
preload和prefetch在用法上相差不大,效果上的差别如下(引自官方文档):
- preload chunk 会在父 chunk 加载时,以并行方式开始加载。prefetch chunk 会在父 chunk 加载结束后开始加载。
- preload chunk 具有中等优先级,并立即下载。prefetch chunk 在浏览器闲置时下载。
- preload chunk 会在父 chunk 中立即请求,用于当下时刻。prefetch chunk 会用于未来的某个时刻。 浏览器支持程度不同。
以上,我们使用 webpack 来打包我们的模块化后的应用程序,webpack 会生成一个可部署的 /dist 目录,然后把打包后的内容放置在此目录中。只要 /dist 目录中的内容部署到服务器上,客户端(通常是浏览器)就能够访问网站此服务器的网站及其资源。而最后一步获取资源是比较耗费时间的,这就是为什么浏览器使用一种名为 缓存 的技术。可以通过命中缓存,以降低网络流量,使网站加载速度更快,然而,如果我们在部署新版本时不更改资源的文件名,浏览器可能会认为它没有被更新,就会使用它的缓存版本。由于缓存的存在,当你需要获取新的代码时,就会显得很棘手。
此指南的重点在于通过必要的配置,以确保 webpack 编译生成的文件能够被客户端缓存,而在文件内容变化后,能够请求到新的文件。
10.1 输出文件的文件名
Section titled “10.1 输出文件的文件名”通过使用 output.filename 进行文件名替换,可以确保浏览器获取到修改后的文件。[hash] 替换可以用于在文件名中包含一个构建相关(build-specific)的 hash,但是更好的方式是使用 [chunkhash] 替换,在文件名中包含一个 chunk 相关(chunk-specific)的哈希。
让我们使用起步 中的示例,以及管理输出 中的 plugins 来作为项目的基础,所以我们不必手动处理维护 index.html 文件:
project
webpack.config.js
执行打包编译:

可以看到,bundle 的名称是它内容(通过 hash)的映射。如果我们不做修改,然后再次运行构建,文件名会保持不变。
10.2 缓存第三方库
Section titled “10.2 缓存第三方库”将第三方库(library)(例如 lodash 或 react)提取到单独的 vendor chunk 文件中,是比较推荐的做法,这是因为,它们很少像本地的源代码那样频繁修改。因此通过实现以上步骤,利用客户端的长效缓存机制,可以通过命中缓存来消除请求,并减少向服务器获取资源,同时还能保证客户端代码和服务器端代码版本一致。 我们在 optimization.splitChunks 添加如下 cacheGroups 参数并构建:
执行编译:

截止目前,我们已经把 JS 文件、样式文件及图片等资源文件分别放到了 scripts、styles、images三个文件夹中。
11.js压缩
Section titled “11.js压缩”安装插件 terser-webpack-plugin
配置
这个插件,当mode是production的时候,执行这个配置打包成js压缩的形式,而开发环境时,则是打包成原始的js。 插件的使用文档:https://webpack.docschina.org/plugins/terser-webpack-plugin/






