webpack入门之css处理(css预处理器和css后置处理器)
本文 webpack 版本 ^5.73.0、webpack-cli 版本 ^4.10.0
简介
说到前端构建就肯定离不开css的处理。在前端日新月异的潮流下,css也不再是单纯的css了,涌现了很多css周边技术,比如我们常听到的css预处理器(PreCss)和css后置处理器(PostCss)。那这两个东西又是啥呢?他们的区别又是什么呢?以及在webpack中又怎么去处理它呢?
带着疑问,我们今天就来一探究竟
看完本文你将学到:
- 知道什么是css预处理器
- css预处理器都有哪些
- css预处理器有哪些作用
- css预处理器怎么编译成css
- 知道什么是css后置处理器
- css后置处理器有哪些作用
- css后置处理器是怎么处理css的
- 怎么使用webpack来处理css预处理器和css后置处理器
- 编译适配目标浏览器的配置 browserslist
css预处理器PreCss
为什么会出现CSS预编译器这个东西呢?这就要谈到CSS的不足了:
- 没有变量(新的规范已经支持了)。
- 不支持嵌套。
- 编程能力较弱,代码复用性差。
- 没有模块化。
为了弥补这些不足之处,CSS预编译器应运而生。而谈到CSS预编译器,就离不开这三剑客Sass、Less、Stylus。
历史上,最先登场的是Sass,因为出现最早,所以也是最完善的,有各种丰富的功能;Less的出现伴随着Bootstrap的流行,因此也获得大量用户;最后是Stylus,由TJ大神开发(敬大神),由于其简洁的语法,更像是一门编程语言,写起来非常Cool。所以下面我们来做一个简单的对比。
scss
Sass3.0版本开始使用的是标准的CSS语法,基本与SCSS一样。默认Sass使用.scss扩展名。
// scss新版语法规则
.container {
background: #f6f6f6;
min-height: 100%;
}
同时,Sass也支持老的语法,这种跟常规的CSS略有不同,更为严格,任何的缩进和字符的错误都会造成样式的编译错误,Sass可以省略{}和;,而且文件使用.sass扩展名,语法如下:
.container
background: #f6f6f6
min-height: 100%
更多特性可自行查看sass中文文档学习。
less
Less是CSS的一种扩展形式,在CSS语法基础上添加了很多额外功能。从语法规则来讲,Less和Scss一样,都是用CSS的标准语法,只是Less的源文件扩展名是.less,举个栗子🌰:
.block {
height: 30px;
padding-bottom: 10px;
color: #666;
font-weight: normal;
}
更多特性可自行查看less中文文档学习。
stylus
Stylus语法多变一些,文件扩展名是.styl,Stylus既接受标准的CSS语法,也可以跟Sass老的语法规则一样,使用缩进控制,如下所示:
// 类似于CSS标准语法
.head {
color: #ebebeb;
background-color: #666;
}
// 省略大括号
.head
color: #ebebeb;
background-color: #666;
// 省略大括号和分号
.head
color: #ebebeb
background-color: #666
更多特性可自行查看less中文文档学习。
普通构建
说了这么多css预处理器,预处理器代码能在浏览器运行吗?这些语法能被浏览器直接识别吗?
当然是不能的,所以在正式上线之前我们都需要进行编译,也就是把这些.scss、.less、.styl文件转变成浏览器能识别的.css文件。
那我们怎么进行编译呢?这就需要用到对应的工具了。
sass
编译sass首先需要安装sass。
npm install -g sass
然后我们创建styles.scss文件

安装完后它会提供一个sass命令,使用该命令就可以将.scss文件编译成.css文件了。
sass styles.scss styles.css
我们来看下编译后的效果

less
编译less首先需要安装less。
npm install -g less
然后我们创建styles.less文件

安装完后它会提供一个lessc命令,使用该命令就可以将.less文件编译成.css文件了。
lessc styles.less styles.css
我们来看下编译后的效果

stylus
编译stylus首先需要安装stylus。
npm install -g stylus
然后我们创建styles.styl文件

安装完后它会提供一个stylus命令,使用该命令就可以将.styl文件编译成.css文件了。
stylus styles.styl -o styles.css
我们来看下编译后的效果

上面的编译笔者都是全局安装的,当然你也可以局部安装。
我们可以看到,css预处理器虽然好用,但是每次上线都需要我们手动打包成css,然后再发布是不是有点麻烦。有没有什么更好更高效的办法呢?
当然是有的,我们可以借助webpack,在上线前统一编译即可。下面笔者就来说说使用webpack来编译这三个css预处理器。
使用webpack构建
创建项目
首先我们创建一个文件夹,然后初始化package.json文件。
// 创建webpacktest文件夹
mkdir webpacktest
// 进入webpacktest文件夹
cd webpacktest
// 创建package.json
npm init
创建scss、less、stylus源文件
接下来我们创建scss、less、stylus源文件,在根目录下创建src文件夹,在里面分别创建index.scss、index.less、index.styl

然后在里面分别添加内容
index.less

index.scss

index.styl

并在入口文件index.js里面引入我们的样式文件

安装webpack 和 webpack-cli
接下来我们本地安装webpack 和 webpack-cli
npm i webpack webpack-cli -D
安装处理scss、less、stylus的loader
因为webpack默认只能处理js,如果需要处理其他语言的话需要安装对应的loader,这里我们需要分别安装处理scss、less、stylus文件的less、less-loader、node-sass、sass-loader、stylus、stylus-loader
npm i less less-loader node-sass sass-loader stylus stylus-loader -D
安装处理css的loader
当然,css也是需要处理的,所以也需要对应的loader。
npm i css-loader style-loader -D
配置webpack.config.js
然后我们在根目录下创建webpack.config.js文件,并做如下配置
module.exports = {
mode: "development",
module: {
rules: [
// Less 配置
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"],
},
// Sass 配置
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
// stylus 配置
{
test: /\.styl$/,
use: ["style-loader", "css-loader", "stylus-loader"],
},
],
},
};
loader的配置是有顺序要求的,它的执行顺序是从右到左的。比如use: ['style-loader', 'css-loader'],它先用css-loader处理CSS的模块化,然后style-loader把css-loader解析后的样式代码内联插入到HTML中的style标签内。
配置编译脚本
然后我们在package.json里面创建运行webpack的脚本
"scripts": {
"webpack1": "webpack"
},
运行脚本
然后我们运行npm run webpack1,webpack会读取webpack.config.js文件,进行打包。
默认会读取根目录的src文件夹,默认将打包结果放到根目录dist文件夹下。
运行打包命令后我们可以看到,在根目录下生成了dist文件夹,并输出了main.js

看效果
编译后的文件是很混乱的,不容易看懂,所以我们需要测试刚才的样式是否成功。
我们首先在根目录下创建index.html,并引入构建好的main.js文件,然后创建三个div,分别引用刚才的样式。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>webpack</title>
</head>
<body>
<div class="box1">less test</div>
<div class="box2">scss test</div>
<div class="box3">stylus test</div>
<script src="./dist/main.js"></script>
</body>
</html>
然后在浏览器运行,我们来看看效果

nice! 至此使用webpack构建less、scss、stylus就完成啦。
将css抽离成单独的css文件
前面说到,style-loader的作用是将处理好后的CSS样式代码放到HTML的style标签中。

那么,如果我需要将处理后的CSS文件单独编译成一个.css文件,引入到HTML中,webpack需要怎么做呢?
我们可以使用mini-css-extract-plugin插件提取css代码为单独的CSS文件,然后在HTML中通过link标签引入CSS文件。
npm install mini-css-extract-plugin -D
然后我们使用MiniCssExtractPlugin.loader来替换style-loader
// 1.引入
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
mode: "development",
module: {
rules: [
// Less 配置
{
test: /\.less$/,
// use: ["style-loader", "css-loader", "less-loader"],
// 3. 替换style-loader
use: [MiniCssExtractPlugin.loader, "css-loader", "less-loader"],
},
// Sass 配置
{
test: /\.scss$/,
// use: ["style-loader", "css-loader", "sass-loader"],
// 3. 替换style-loader
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
// stylus 配置
{
test: /\.styl$/,
// use: ["style-loader", "css-loader", "stylus-loader"],
// 3. 替换style-loader
use: [MiniCssExtractPlugin.loader, "css-loader", "stylus-loader"],
},
],
},
// 2. 实例化插件
plugins: [new MiniCssExtractPlugin()],
};
然后我们重新构建,可以发现,编译后的css会单独形成一个main.css文件。

最后我们在index.html文件中手动引入main.css就可以了。
<link rel="stylesheet" href="./dist/main.css" />
可能有些小伙伴觉得,自己每次手动引入js和css太麻烦,有没有自动引入的方式呢?这就需要用到html-webpack-plugin插件啦
自动引入js和css文件
首先安装
npm install html-webpack-plugin -D
然后在webpack.config.js使用该插件。
// 1.引入
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// 1.引入
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
mode: "development",
// ...
// 2. 实例化插件
plugins: [
new HtmlWebpackPlugin({
// 模板html文件的位置,我们这里是在根目录下
template: "./index.html",
}),
new MiniCssExtractPlugin(),
],
};
然后我们重新编译,可以看到在dist文件夹下多了index.html文件

并且该文件自动引入了我们构建后的js和css文件

自动清空打包目录
每次打包的时候,打包目录都会遗留上次打包的文件,为了保持打包目录的纯净,我们需要在打包前将打包目录清空
这里我们可以使用插件 clean-webpack-plugin 来实现。
老规矩,首先安装
npm install clean-webpack-plugin -D
然后在webpack.config.js使用该插件。
// 1.引入
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// 1.引入
const HtmlWebpackPlugin = require("html-webpack-plugin");
// 1.引入
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
mode: "development",
// 使用CleanWebpackPlugin需要显示定义出口,不然无效
output: {
filename: "[name].js",
path: path.resolve(__dirname, "./dist"),
},
// ...
// 2. 实例化插件
plugins: [
new HtmlWebpackPlugin({
// 模板html文件的位置,我们这里是在根目录下
template: "./index.html",
}),
new MiniCssExtractPlugin(),
new CleanWebpackPlugin(),
],
};
然后我们再次打包,可以发现,它会先将dist目录删除,然后重新生成dist目录。
css的前置处理器我们大致讲完了,接下来我们再来说说css的后置处理器。
css后置处理器PostCss
对于 PostCSS 官方的解释是: PostCSS 是一个允许使用 JS 插件转换样式的工具。 这些插件可以检查(lint)你的 CSS,支持 CSS Variables 和 Mixins, 编译尚未被浏览器广泛支持的先进的 CSS 语法,内联图片,以及其它很多优秀的功能。
笔者简单理解postcss 是 css 的 transpiler(转换编译器,简称转译器),它对于 css 就像 babel 对于 js 一样,能够做 css 代码的分析和转换。同时,它也提供了插件机制来做自定义的转换。
普通构建
我们这里拿autoprefixer插件来做例子来讲解。
创建项目
首先我们创建一个文件夹,然后初始化package.json文件。
// 创建webpacktest文件夹
mkdir postcsstest
// 进入postcsstest文件夹
cd postcsstest
// 创建package.json
npm init
创建源文件
因为我们要测试autoprefixer,所以我们需要找一个需要带浏览器前缀的样式。这个修改placeholder颜色的样式刚刚好。

安装 postcss、postcss-cli
单独使用postcss我们需要安装postcss、postcss-cli。这样我们就可以在命令行使用postcss命令了。
npm i postcss postcss-cli -D
安装插件
npm i autoprefixer -D
创建 postcss.config.js
postcss.config.js是postcss的配置文件,我们postcss的配置都需要在这里定义。
前面我们安装了autoprefixer插件,这里我们再来配置下。
// postcss.config.js
// 引入
const autoprefixer = require("autoprefixer");
module.exports = {
// 使用
plugins: [autoprefixer],
};
配置编译脚本
然后我们在package.json里面创建运行postcss的脚本
"scripts": {
"pc1": "postcss src/post1.css -o dist/post1.css"
},
运行脚本
我们运行上面配置好的脚本来编译下,npm run pc1。当我们在命令行运行该命令时,其实真实运行的是postcss src/post1.css -o dist/post1.css,这样他会处理我们前面的post1.css。
看效果
我们来看下dist/post1.css,我们可以看到,它自动生成了-moz前缀的样式。

这里我们只拿autoprefixer作了讲解,其实截止到目前,PostCSS 有 200 多个插件。你可以在 插件列表找到它们。这些插件我们可以在不同需求下选择使用。
使用postcss-cli构建虽然可以,但是不推荐这么使用。一般我们都是使用webpack进行前端统一构建,所以下面笔者来说说使用webpack来构建我们的postcss
使用webpack构建
这里我们就不再单独创建项目了,我们基于前面预处理器的webpacktest项目。
创建源文件
我们把前面创建好的post1.css文件复制过来,并在入口文件index.js里面引入

安装 postcss-loader
在webpack里面使用postcss,我们只需要安装postcss-loader就可以了。
npm i postcss-loader -D
安装插件
npm i autoprefixer -D
创建 postcss.config.js
postcss.config.js是postcss的配置文件,我们postcss的配置都需要在这里定义。
前面我们安装了autoprefixer插件,这里我们再来配置下。
// postcss.config.js
// 引入
const autoprefixer = require("autoprefixer");
module.exports = {
// 使用
plugins: [autoprefixer],
};
配置webpack.config.js
我们在rules里面添加css的处理规则。并配置上postcss-loader。
module.exports = {
mode: "development",
module: {
rules: [
// css 配置
{
test: /\.css$/,
use: ["style-loader", "css-loader", "postcss-loader"],
},
// ...
],
},
};
修改index.html
我们在模板index.html里面添加一个input

运行脚本
接下来我们编译下,npm run webpack1。webpack会读取webpack.config.js文件,进行打包。
看效果
我们来看看编译后的代码,发现它也自动生成了-moz前缀的样式。

在页面上可以看到,我们input的placeholder的颜色被我们改成红色了。

好奇
为什么每次只生成了火狐浏览器的前缀-moz呢?不是还有ie浏览器前缀-ms,chrome浏览器前缀-webkit吗?
按理来说不应该是生成下面这些样式吗

这里就需要了解另外一个知识点了,那就是browserslist。
那这个browserslist到底是什么东西呢?
简单理解,browserslist 实际上就是声明了⼀段浏览器的集合,我们的⼯具可以根据这段集合描述,针对性的输出兼容性代码。
.browserslistrc文件的默认值是
> 0.5%
last 2 versions
Firefox ESR
not dead
所以,当我们不配置browserslist的话,它的配置就是上面的默认配置,所以并不会生成所有浏览器的前缀,只会针对性的输出。
如果想输出全部怎么办呢?我们可以做一个小测试,我们把not dead注释掉,再编译。

可以看到,编译后的文件里面有所有浏览器的前缀了。

我们除了定义.browserslistrc文件来配置browserslist外,我们还可以直接配置在package.json文件中,通过browserslist键来配置。
// package.json
{
"browserslist": [
"last 1 version",
"> 1%",
"IE 10"
]
}
现在对browserslist有了一个大概的了解了吧。
总结
好啦,看了上面的例子,小伙伴们应该很清楚css预处理器(PreCss)和css后置处理器(PostCss)了吧。
总的来说,css预处理器是用来弥补css不足的,它提供了变量、嵌套、复用、模块等方案,让我们的开发效率和开发体验大大提升。缺点是浏览器不能直接识别,每次上线前需要我们单独进行编译。
css后置处理器是用来处理css的,postcss 是 css 到 css 的转译器,它分为 parse、transform、generate 3个阶段。各种转换插件都是工作在 transform 阶段,基于 AST 做分析和转换。

系列文章
后记
感谢小伙伴们的耐心观看,本文为笔者个人学习笔记,如有谬误,还请告知,万分感谢!如果本文对你有所帮助,还请点个关注点个赞~,您的支持是笔者不断更新的动力!
转载自:https://juejin.cn/post/7125605683633848356