
二、webpack-loader的使用
一、css-loader
从代码案例开始
1 | import "./css/index.css"; |
设置样式:
1 | .content { |
此时进行打包:
1 | ERROR in ./src/css/index.css 1:0 |
上面的错误信息告诉我们需要一个 loader 来加载这个 css 文件,但是 loader 是什么呢?
- loader 可以用于对模块的源代码进行转换;
- 我们可以将 css 文件也看成是一个模块,我们是通过 import 来加载这个模块的;
- 在加载这个模块时,webpack 其实并不知道如何对其进行加载,我们必须制定对应的 loader 来完成这个功能
- 那么我们需要一个什么样的 loader 呢?
- 对于加载 css 文件来说,我们需要一个可以读取 css 文件的 loader;
- 这个 loader 最常用的是 css-loader;
- css-loader 的安装: npm install css-loader -D
loader 使用方案
- 内联方式;
- CLI 方式(webpack5 中不再使用);
- 配置方式;
内联方式:使用较少,因为不方便管理; 在引入的样式前加上使用的 loader,并且使用!分割
1 | import "css-loader!../css/index.css"; |
CLI 方式 :在 webpack5 的文档中已经没有了–module-bind; 实际应用中也比较少使用,因为不方便管理
配置方式 - 重点
配置方式表示的意思是在我们的 webpack.config.js 文件中写明配置信息:
- module.rules 中允许我们配置多个 loader(因为我们也会继续使用其他的 loader,来完成其他文件的加载);
- 这种方式可以更好的表示 loader 的配置,也方便后期的维护,同时也让你对各个 Loader 有一个全局的概览;
module.rules 的配置如下:
- rules 属性对应的值是一个数组:[Rule] 数组中存放的是一个个的 Rule,Rule 是一个对象,对象中可以设置多个属性:
- test 属性:用于对 resource(资源)进行匹配的,通常会设置成正则表达式;
- use 属性:对应的值时一个数组:[UseEntry] UseEntry 是一个对象,可以通过对象的属性来设置一些其他属性
- loader:必须有一个 loader 属性,对应的值是一个字符串;
- options:可选的属性,值是一个字符串或者对象,值会被传入到 loader 中
- query:目前已经使用 options 来替代;
传递字符串(如:use: [ ‘style-loader’ ])是 loader 属性的简写方式(如:use: [ { loader: ‘style-loader’} ])
loader 属性: Rule.use: [ { loader } ] 的简写。
代码:
1 | const path = require("path"); |
二、style-loader
此时会发现这个 css 在我们的代码中并没有生效(页面没有效果)。 这是为什么呢?
- 因为 css-loader 只是负责将.css 文件进行解析,并不会将解析之后的 css 插入到页面中;
- 如果我们希望再完成插入 style 的操作,那么我们还需要另外一个 loader,就是 style-loader;
- 安装 style-loader: npm install style-loader -D
1 | use: [ |
loader 的执行顺序是从右向左(或者说从下到上,或者说从后到前的),
所以我们需要将 style-loader 写到 css-loader 的前面;
重新执行编译 npm run build,可以发现打包后的 css 已经生效了:
当前目前我们的 css 是通过页内样式的方式添加进来的,放到了 header 里
后续我们也会讲如何将 css 抽取到单独的文件中,并且进行压缩等操作;
三、less-loader
在我们开发中,我们可能会使用 less、sass、stylus 的预处理器来编写 css 样式,效率会更高。
那么,如何可以让我们的环境支持这些预处理器呢?
首先我们需要确定,less、sass 等编写的 css 需要通过工具转换成普通的 css;
比如我们编写如下的 less 样式:
1 | @fontSize: 26px; |
可以使用 less 工具来完成它的编译转换:
执行如下命令:
npm install less -D
npx less ./src/css/title.less > title.css
在引入相应 css 文件即可
但是有很多 less 文件呢?还是得使用 less-loader
npm i less less-loader -D
1 | { |
此时就可以正常显示了。
四、浏览器兼容性
开发中,浏览器的兼容性问题,我们应该如何去解决和处理?
- 这里说的兼容性问题不是指屏幕大小的变化适配;
- 而是针对不同的浏览器支持的特性:比如 css 特性、js 语法,之间的兼容性;
市面上有大量的浏览器:
- 有 Chrome、Safari、IE、Edge、Chrome for Android、UC Browser、QQ Browser 等等
- 它们的市场占率是多少?要不要兼容它们呢?
其实在很多的脚手架配置中,都能看到类似于这样的配置信息:
这里的百分之一,就是指市场占有率
1 | >1% |
哪里可以查询到浏览器的市场占有率呢?
最好用的网站,也是我们工具通常会查询的一个网站就是 caniuse:https://caniuse.com/usage-table
browserslist 工具
有一个问题,我们如何可以在 css 兼容性和 js 兼容性下共享我们配置的兼容性条件呢?
- 就是当我们设置了一个条件: > 1%;
- 表达的意思是 css 要兼容市场占有率大于 1%的浏览器,js 也要兼容市场占有率大于 1%的浏览器
如果我们是通过工具来达到这种兼容性的,比如后面我们会讲到的 postcss-prest-env、babel、autoprefixer 等
如何可以让他们共享(知道)我们的配置呢? 这个问题的答案就是 Browserslist;
Browserslist 是什么?
Browserslist 是一个在不同的前端工具之间,共享目标浏览器和 Node.js 版本的配置的工具:
Autoprefixer
Babel
postcss-preset-env
eslint-plugin-compat
stylelint-no-unsupported-browser-features
postcss-normalize
obsolete-webpack-plugin
浏览器查询过程
我们可以编写类似于这样的配置:
1 | >1% |
之后,这些工具会根据我们的配置来获取相关的浏览器信息,以方便决定是否需要进行兼容性的支持:
条件查询使用的是 caniuse-lite 的工具,这个工具的数据来自于 caniuse 的网站上;
Browserslist 编写规则一:
那么在开发中,我们可以编写的条件都有哪些呢?(加粗部分是最常用的)
defaults:
- Browserslist 的默认浏览器(> 0.5%, last 2 versions, Firefox ESR, not dead)。
5%:
- 通过全局使用情况统计信息选择的浏览器版本。 >=,<和<=。
1 | 5% in US:使用美国使用情况统计信息。它接受两个字母的国家/地区代码。 |
last 2 versions:
- 每个浏览器的最后 2 个版本。
- last 2 Chrome versions:最近 2 个版本的 Chrome 浏览器。
- last 2 major versions 或 last 2 iOS major versions:最近 2 个主要版本的所有次要/补丁版本。
dead:
- 24 个月内没有官方支持或更新的浏览器。
- 现在是 IE 10,IE_Mob 11,BlackBerry 10,BlackBerry 7, Samsung 4 和 OperaMobile 12.1。
Browserslist 编写规则二:
node 10 和 node 10.4:选择最新的 Node.js10.x.x 或 10.4.x 版本。
current node:Browserslist 现在使用的 Node.js 版本。
maintained node versions:所有 Node.js 版本,仍由 Node.js Foundation 维护。
iOS 7:直接使用 iOS 浏览器版本 7。
Firefox > 20:Firefox 的版本高于 20 >=,<并且<=也可以使用。它也可以与 Node.js 一起使用。
ie 6-8:选择一个包含范围的版本。
Firefox ESR:最新的[Firefox ESR]版本。
PhantomJS 2.1 和 PhantomJS 1.9:选择类似于 PhantomJS 运行时的 Safari 版本。
extends browserslist-config-mycompany:从 browserslist-config-mycompanynpm 包中查询 。
supports es6-module:支持特定功能的浏览器。 es6-module 这是“我可以使用” 页面 feat 的 URL 上的参数。有关所有可用功能的列表,请参见 。caniuselite/data/features
browserslist config:在 Browserslist 配置中定义的浏览器。在差异服务中很有用,可用于修改用户的配置,例如 browserslist config and supports es6-module。
since 2015 或 last 2 years:自 2015 年以来发布的所有版本(since 2015-03 以及 since 2015-03-10)。
unreleased versions 或 unreleased Chrome versions:Alpha 和 Beta 版本。
not ie <= 8:排除先前查询选择的浏览器。
命令行使用 browserslist
我们可以直接通过命令来查询某些条件所匹配到的浏览器:
npx browserslist “>1%, last 2 version, not dead”
1 | bb 10 |
配置 browserslist
方案一:在 package.json 中配置
1 | "browserslist":[ |
方案二:单独的一个配置文件.browserslistrc 文件
如果没有配置,那么也会有一个默认配置:
我们编写了多个条件之后,多个条件之间是什么关系呢?
五、postcss
PostCSS 是一个通过 JavaScript 来转换样式的工具;
这个工具可以帮助我们进行一些 CSS 的转换和适配,
比如自动添加浏览器前缀、css 样式的重置;
但是实现这些工具,我们需要借助于 PostCSS 对应的插件;
如何使用 PostCSS 呢?主要就是两个步骤:
- 第一步:查找 PostCSS 在构建工具中的扩展,比如 webpack 中的 postcss-loader;
- 第二步:选择可以添加你需要的 PostCSS 相关的插件;
总结:postcss 本身功能较少,实现相关的功能需要借助相关的插件。
命令行使用 postcss
能不能也直接在终端使用 PostCSS 呢? 也是可以的,但是我们需要单独安装一个工具 postcss-cli;
可以安装一下它们:postcss、postcss-cli
npm i postcss postcss-cli -D
编写一个需要添加前缀的 css:
1 | :fullscreen { |
https://autoprefixer.github.io/ 我们可以在上面的网站中查询一些添加 css 属性的样式;
执行命令
1 | npx postcs -o res.css ./src/css/test.css |
- -o 指定输出文件名称
- ./src/css/test:因为 postcss 在 node_modules 目录下。src 与 node_modules 同级,所以./
执行完 res.css 文件并没有加上浏览器前缀,因为默认 postcss 没有这个功能,需要插件协助。
1 | npm i autoprefixer -D |
指定使用插件 autoprefixer
1 | npx postcss --use autoprefixer -o end.css ./src/css/style.css |
此时的 res.css 文件:
六、postcss-loader
真实开发中必然不会直接使用命令行工具来对 css 进行处理,而是可以借助于构建工具:
在 webpack 中使用 postcss 就是使用 postcss-loader 来处理的
- 安装 postcss-loader
- 修改加载 css 的 loader
- 注意:因为 postcss 需要有对应的插件才会起效果,所以我们需要配置它的 plugin;
npm i postcss-loader
1 | use: [ |
postcss-preset-env
在配置 postcss-loader 时,我们配置插件并不需要使用 autoprefixer。
我们可以使用另外一个插件:postcss-preset-env
- ppostcss-preset-env 也是一个 postcss 的插件;
- 它可以帮助我们将一些现代的 CSS 特性,转成大多数浏览器认识的 CSS,并且会根据目标浏览器或者运行时环境添加所需的 polyfill;
- 也包括会自动帮助我们添加 autoprefixer(所以相当于已经内置了 autoprefixer
首先,我们需要安装 postcss-preset-env:
之后,我们直接修改掉之前的 autoprefixer 即可
1 | { |
使用十六进制的颜色时设置了 8 位;但是某些浏览器可能不认识这种语法,我们最好可以转成 RGBA 的形式; 但是 autoprefixer 是不会帮助我们转换的; p 而 postcss-preset-env 就可以完成这样的功能;
1 | .content { |
注意:
我们在使用某些 postcss 插件时,也可以直接传入字符串
1 | { |
可以单独配置 postcss
根目录下创建 postcss.config.js
1 | module.exports = { |
importLoaders
我们 css 文件中导入 css 文件
index.css 文件中:
1 | @import './component.css' |
那么 loader 在解析 index.css 的时候
postcss-loader 会处理 index.css 文件的样式
然后交给 css-loader 处理,css-loader 发现@import ‘./component.css’会导入并处理相关文件
但这个文件就不会被 postcss-loader 处理了
这就是一个问题,怎么处理呢?
1 | { loader: 'css-loader', options: { importLoaders: 1 } }, |
代表遇到@import 导入其他 css 文件时,上一个 loader 先处理一下,也就是 postcss-loader
这个数字视情况而定,需要几个就写几。
七、file-loader
要处理 jpg、png 等格式的图片,我们也需要有对应的 loader:file-loader
file-loader 的作用就是帮助我们处理 import/require()方式引入的一个文件资源,并且会将它放到我们输出的文件夹中
当然我们待会儿可以学习如何修改它的名字和所在文件夹
安装 file-loader
npm install file-loader -D
编写代码:
1 | /创建一个img标签 |
1 | .bg-color { |
配置处理图片的 Rule:
1 | { |
正常是可以显示的,但报了一个错误,后续再解决吧
文件名称命名规则
有时候我们处理后的文件名称按照一定的规则进行显示:
比如保留原来的文件名、扩展名,同时为了防止重复,包含一个 hash 值等;
- 这个时候我们可以使用 PlaceHolders 来完成
- webpack 给我们提供了大量的 PlaceHolders 来显示不同的内容: https://webpack.js.org/loaders/file-loader/#placeholders
- 我们可以在文档中查阅自己需要的 placeholder
介绍几个最常用的 placeholder:
- [ext]: 处理文件的扩展名;
- [name]:处理文件的名称;
- [hash]:文件的内容,使用 MD4 的散列函数处理,生成的一个 128 位的 hash 值(32 个十六进制)
- [contentHash]:在 file-loader 中和[hash]结果是一致的(在 webpack 的一些其他地方不一样,后面会讲到)
- [hash:length]:截图 hash 的长度,默认 32 个字符太长了
- [path]:文件相对于 webpack 配置文件的路径;
设置文件名称
那么我们可以按照如下的格式编写
这个也是 vue 的写法
1 | { |
刚才通过 img/ 已经设置了文件夹,这个也是 vue、react 脚手架中常见的设置方式:
其实按照这种设置方式就可以了
当然我们也可以通过 outputPath 来设置输出的文件夹
1 | outputPath: "img"; |
八、url-loader
url-loader 和 file-loader 的工作方式是相似的,但是可以将较小的文件,转成 base64 的 URI。
安装 url-loader:
npm install url-loader -D
- 显示结果是一样的,并且图片可以正常显示
- 但是在 build 文件夹中,我们会看不到图片文件
- 这是因为我的两张图片的大小分别是 38kb 和 295kb
- 默认情况下 url-loader 会将所有的图片文件转成 base64 编码
1 | { |
limit
开发中我们往往是小的图片需要转换,但是大的图片直接使用图片即可
- 这是因为小的图片转换 base64 之后可以和页面一起被请求,减少不必要的请求过程
- 而大的图片也进行转换,反而会影响页面的请求速度
那么,我们如何可以限制哪些大小的图片转换和不转换呢
- purl-loader 有一个 options 属性 limit,可以用于设置转换的限制;
- 下面的代码 38kb 的图片会进行 base64 编码,而 295kb 的不会;
1 | { |
100 * 1024 即 100kb。
九、 asset module type
当前使用的 webpack 版本是 webpack5:
- 在 webpack5 之前,加载这些资源我们需要使用一些 loader,比如 raw-loader 、url-loader、file-loader
- 在 webpack5 之后,可以直接使用资源模块类型(asset module type),来替代上面的这些 loader
资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader
- passet/resource 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现
- passet/inline 导出一个资源的 data URI。之前通过使用 url-loader 实现
- passet/source 导出资源的源代码。之前通过使用 raw-loader 实现
- passet 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现
1 | { |
file-loader url-loader 可以卸载了
如何可以自定义文件的输出路径和文件名呢?
- 方式一:修改 output,添加 assetModuleFilename 属性
1 | assetModuleFilename: 'img/[name].[hash:6][ext]', |
[ext]自带.不用再另加
- 方式二:在 Rule 中,添加一个 generator 属性,并且设置 filename
1 | { |
url-loader 的 limit 效果
我们需要两个步骤来实现:
- 步骤一:将 type 修改为 asset
- 步骤二:添加一个 parser 属性,并且制定 dataUrl 的条件,添加 maxSize 属性
1 | { |
小的文件已经转成 base64 编码了