构建现代CSS工程环境
前言
在开发Web应用时,我们不仅使用 HTML 标签构建页面结构、编写大量的 JavaScript 代码控制页面逻辑,还需要 CSS 来控制页面的样式。但我们都知道 CSS 一直专注于页面样式的表现力,而缺乏工程化能力、逻辑判断能力,所以我们在开发现代大型 Web 应用时,通常会使用 Webpack 结合其他预处理器,如:Less/Sass/Stylus等预处理器编写样式代码。 本章主要介绍 Webpack 中如何使用 CSS 代码处理工具,包括:
- 如何使用
css-loader
、style-loader
、mini-css-extract-plugin
处理原生 CSS 文件? - 如何使用 Less/Sass/Stylus 预处理器?
- 如何使用 PostCSS ?
处理原生 CSS 文件
Webpack 如果没做任何额外的配置是不能处理 CSS 文件的,如果导入了 .css
文件,编译过程则会报错:

所以我们在Webpack中处理CSS文件通常都需要用到:
css-loader
:这个 Loader 会将 CSS 等价编译成 JavaScript 代码,使得 Webpack 可以像处理 JavaScript 代码一样处理 CSS 内容与资源依赖。style-loader
:这个 Loader 会将 CSS 的内容以<style>
标签的形式,注入到页面中使得样式生效。mini-css-extract-plugin
:这个插件会将 CSS 的内容单独拆分为.css
文件,在页面中以<link>
标签的方式引入 CSS 使得样式生效 。
一般我们使用css-loader
先将 CSS 内容进行处理,在开发环境中使用style-loader
注入CSS内容使样式生效,在生产环境中使用mini-css-extract-plugin
将 CSS 内容拆分为单独的 CSS 文件再以 <link>
标签的方式插入到页面中。
需要注意的是,style-loader
和 mini-css-extract-plugin
不能同时使用,需要通过环境变量判断当前环境并使用恰当的 loader 。如下:
const path = require('path');
const MiniCSSExtractPlugin = require('mini-css-extract-plugin');
const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// ...
module: {
rules: [
{
test: /\.css$/,
use: [
(process.env.NODE_ENV === 'production' ? MiniCSSExtractPlugin.loader : 'style-loader'),
'css-loader'
]
}
]
},
plugins: [
new MiniCSSExtractPlugin(),
new HTMLWebpackPlugin()
]
}
可以看到我们在定义 .css
文件的解析规则时,use
使用的是数组,这等同于 style-loader(css-loader(css))
调用,所以数组内 loader
的顺序不能错。
通常在实际开发中,我们很少直接使用 CSS 进行大型 Web 应用的开发,而是配合各种方便的 CSS 预处理器,比如 Less
、Sass
和Stylus
,而使用预处理后,我们也只需要在 Webpack 中引入对应的 loader 即可。
使用预处理器
拿 Less 举例,我们需要先安装 less
和 less-loader
yarn add -D less less-loader
然后我们去修改 Webpack 配置如下:
{
test: /\.less$/,
use: [
(process.env.NODE_ENV === 'production' ? MiniCSSExtractPlugin.loader : 'style-loader'),
'css-loader',
'less-loader'
]
}
其余两种常用的 Sass 和 Stylus 引入方式和 Less 基本一样,都是下载各自的 loader 然后再修改 Webpack 配置即可。
Sass:
yarn add -D sass sass-loader
// sass
{
test: /\.less$/,
use: [
(process.env.NODE_ENV === 'production' ? MiniCSSExtractPlugin.loader : 'style-loader'),
'css-loader',
'sass-loader'
]
}
Stylus:
yarn add -D stylus stylus-loader
// sass
{
test: /\.less$/,
use: [
(process.env.NODE_ENV === 'production' ? MiniCSSExtractPlugin.loader : 'style-loader'),
'css-loader',
'stylus-loader'
]
}
使用 PostCSS
和上面提到的 Less/Sass/Stylus 一系列预处理器类似,PostCSS 也可以在原生 CSS 的基础上增加更多的可读性、兼容性、模块化以及格式校验等功能,但它和预处理器不同的是,预处理专门定义了一套超集语法,而 PostCSS 和 Babel 类似,只是将你的 CSS 代码进行转换为 AST,然后使用插件做处理的流程框架。 举个例子,Less/Sass/Stylus 等预处理器和 CSS 的关系就像是 TypeScript 和 JavaScript,而 PostCSS 和 CSS 的关系就像是 Babel 和 JavaScript。 好消息是,正如上面的类比一样,PostCSS 可以和预处理器同时存在,并不是互斥关系,也就是说你可以在使用预处理器的基础上再使用 PostCSS。
yarn add -D postcss postcss-loader
修改 Webpack 配置如下:
module.exports = {
module: {
rules: [
{
test: /\.less$/,
use: [
(process.env.NODE_ENV === 'production' ? MiniCSSExtractPlugin.loader : 'style-loader'),
{
loader: 'css-loader',
options: {
// 在处理到使用 @import 语法时 先用 css-loader 的前 n 个 loader 处理
// n = importLoaders
importLoaders: 1
}
},
'postcss-loader',
'less-loader'
]
}
]
},
此时这样只是相当于安装了一个"空壳",正如上面所说,需要使用 PostCSS 插件来处理。下面我们安装一个 autoprefixer
插件,该插件可以自动添加各浏览器厂商前缀。

yarn add -D autoprefixer
项目根目录下添加 postcss.config.js
文件进行插件引用配置。
module.exports = {
plugins: [
require("autoprefixer")
]
}
至此,我们已经完成了现在 CSS 工程环境搭建的全部过程。
总结
最后总结一下,因为我们的原生 CSS 不能直接被 Webpack 所识别,所以我们先使用 css-loader + style-loader
或 css-loader + mini-css-extract-plugin
处理原生 CSS 文件,而因为原生 CSS 存在一些缺陷,后续我们又使用了 Less/Sass/Stylus 预处理器以及 PostCSS 以帮助我们写出更清晰简洁,复用性更高的代码。