Webpack 本身不处理样式,您必须使用 loader 和插件来加载样式文件。在本章中,您将配置如何加载 CSS,并了解浏览器自动刷新的工作原理。当您对 CSS 进行更改时,不必完全刷新。相反,它仅仅是对变动的部分进行更新。
加载 CSS
要加载 CSS,您需要使用 css-loader 和 style-loader。 css-loader 遍历匹配文件中的 @import
和 url()
,并将它们视为常规ES2015 import
。如果 @import
指向外部资源,则 css-loader 会跳过它,因为 Webpack 只处理内部资源。
style-loader 通过 style
元素注入样式。它还实现了热模块替换接口,提供了愉快的开发体验。
匹配的文件可以通过文件加载器或 url-loader 之类的 loader 进行处理,更多的细节将在本书的“ 加载资源”部分讨论。
由于内联 CSS 不适合生产环境,因此使用 MiniCssExtractPlugin
生成单独的 CSS 文件是有意义的。您将在下一章中完成此操作。
首先,我们开始安装:
npm install css-loader style-loader --save-dev
现在让我们在 Webpack 中配置它们。在部分配置文件的末尾添加一个新函数:
webpack.parts.js
exports.loadCSS = ({ include, exclude } = {}) => ({
module: {
rules: [
{
test: /\.css$/,
include,
exclude,
use: ["style-loader", "css-loader"],
},
],
},
});
您还需要将这个片段连接到主配置文件中:
webpack.config.js
const commonConfig = merge([
...
parts.loadCSS(),
]);
添加的配置意味着以 .css
结尾的文件应该调用给定的 loader。test
字段 是一串正则表达式,用来描述文件名称的匹配规则。
loader 是应用于源文件的转换器,并返回转换结果。它们像 Unix 中的管道一样,可以连接使用。它们从右到左执行,这意味着 loaders: ["style-loader", "css-loader"]
可以读作 styleLoader(cssLoader(input))
。
如果要禁用 css-loader
url
解析功能,那么就在 loader 选项中设置url: false
。同样,它也适用于@import
。要禁用 import 解析功能,可以设置import: false
。
如果您不需要 HMR 功能,支持旧的 Internet Explorer 和 source maps,请考虑使用 micro-style-loader 而不是 style-loader。
初始化 CSS
现在,添加初始的 CSS 文件:
src/main.css
body {
background: cornsilk;
}
此外,您需要让 webpack 发现它。如果没有一个入口点来指向它的话,webpack 是找不到该文件的:
src/index.js
import "./main.css";
...
执行 npm start
,如果您使用的是默认端口,那么我们直接在浏览器打访问 http://localhost:8080
。现在打开 main.css 并将背景颜色更改为 lime
(background: lime
)。
CSS模块附录介绍了一种 CSS 局部作用域的方法,这样避免了所有的 CSS 样式都具备全局作用域。
加载 Less
Less 是包含函数功能的 CSS 处理器,在 Webpack 中使用 Less 不需要花费很多精力,因为 less-loader 已经处理的差不多了。你需要安装 Less,因为它是 less-loader 的依赖。
然后加入下面的配置:
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"],
},
less-loader 支持 Less 插件,source maps 等。要了解这些工作原理,您可以查看一下这个项目。
加载 Sass
Sass 是一种广泛使用的 CSS 预处理器,在 Webpack 中需要 sass-loader 使用,另外,还要安装 node-sass,sass-loader 依赖于它。
然后在 Webpack 中添加以下配置就可以了:
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
如果您想要更高的性能,特别是在开发过程中,请查看 fast-sass-loader。
加载 Stylus 和 Yeticss
Stylus 是另一款 CSS 处理器,通过 stylus-loader 可以很好地将它融入 Webpack。yeticss 是一个适用于它的模式库。
请参考以下配置:
{
...
module: {
rules: [
{
test: /\.styl$/,
use: [
"style-loader",
"css-loader",
{
loader: "stylus-loader",
options: {
use: [require("yeticss")],
},
},
],
},
],
},
},
如果要在 Stylus 中使用 yeticss ,您必须将其导入到 .styl 文件中:
@import "yeticss"
//or
@import "yeticss/components/type"
PostCSS
PostCSS 允许您通过 JavaScript 插件对 CSS 执行转换,您甚至可以找到类似 Sass 功能的插件。PostCSS 相当于 CSS 的 Babel。postcss-loader 可以将它与 Webpack 搭配使用。
下面的例子说明了如何使用 PostCSS 自动设置浏览器厂商前缀。另外,这个配置还添加了 press——一个 PostCSS 插件——允许您在 CSS 中使用类似 Sass 的标签。您可以将此技术与其他 loader 混合使用,以启动自动添加前缀。
{
test: /\.css$/,
use: [
"style-loader",
"css-loader",
{
loader: "postcss-loader",
options: {
plugins: () => ([
require("autoprefixer"),
require("precss"),
]),
},
},
],
},
记住安装导入 autoprefixer 和precss,这样它们才能正常工作。自动添加前缀章节中详细讨论了该技术。
PostCSS 支持基于 postcss.config.js 的配置。它在内部基于 cosmiconfig,因此它也支持其他格式的配置。
cssnext
cssnext 是一个 PostCSS 插件,用来体验一些未来的 CSS 特性。您可以通过 postcss-cssnext 使用它。
请参考以下配置:
{
use: {
loader: "postcss-loader",
options: {
plugins: () => [require("postcss-cssnext")()],
},
},
},
有关可用选项,请参阅官方使用说明。
cssnext 包括自动添加前缀功能!您不需要额外配置。
理解文件查找
为了充分使用 css-loader,您应该理解它如何执行查找。css-loader 默认处理相对导入,它不会触及绝对导入(url("/static/img/demo.png")
)。如果您依赖此类导入,则必须将文件复制到项目中。
copy-webpack-plugin 可以用于将文件复制到 Webpack 中,但您也可以将文件复制到Webpack 之外。前一种方法的好处是 webpack-dev-server 可以访问到它。
如果你使用 Sass 或 Less,resolve-url-loader 会派上用场,它支持了 CSS 内部资源的相对导入,避免资源定位失败的问题。
处理 css-loader 导入
如果要以特定方式处理 css-loader 导入,则应将 importLoaders
选项设置为一个数字,该数字告诉加载程序在对所找到的导入文件执行 css-loader 之前需要执行多少个 loader 。如果您通过@import
语句从 CSS 导入其他 CSS 文件,并希望通过特定的 loader 处理导入,则此技术至关重要。
请考虑从 CSS 文件导入以下内容:
@import "./variables.sass";
要处理 Sass 文件,您必须编写配置:
{
test: /\.css$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
importLoaders: 1,
},
},
"sass-loader",
],
},
如果您向链中添加了更多 loader(例如 postcss-loader),则必须相应地调整 importLoaders
选项。
从 node_modules 目录加载文件
您可以直接从 node_modules 目录加载文件。考虑 Bootstrap 及其用法,例如:
@import "~bootstrap/less/bootstrap";
波形符(~
)告诉 Webpack 它不是默认的相对导入。如果包含波浪号,则它会在 node_modules
中执行查找(默认设置,可以通过 resolve.modules 字段进行配置)。
如果您正在使用 postcss-loader,则可以跳过使用
~
,就像 postcss-loader issue tracker 讨论的内容一样。postcss-loader 可以在没有波形符号的情况下解析导入。
启用源映射
如果要为 CSS 启用源映射,则应为 css-loader 启用 sourceMap
选项,并将 output.publicPath
设置为开发服务器的绝对 URL 地址。如果链中有多个 loader,则必须分别为每个 loader 启用源映射。css-loader issue 29 进一步讨论了这个问题。
将 CSS 转换为字符串
特别是对于 Angular 2,如果你能够以字符串格式获得 CSS,将其嵌入到组件中,这将非常方便。css-to-string-loader 可以解决这个问题。
使用 Bootstrap
有几种方法可以在 webpack 中使用 Bootstrap。其中一个方法就是使用 Bootstrap npm 包,并执行如上所述的 loader 配置。
Bootstrap Sass 版本 是另一种选择。在这种情况下,您应该将 _sass-loader 的 precision
选项设置为至少 8。这是 bootstrap-sass 中发现的一个已知问题。
第三种选择是通过 bootstrap-loader。它拥有许多功能,但也可以进行定制。
总结
Webpack 可以加载各种各样的样式文件。这里介绍的方法默认情况下将样式编写到 JavaScript 包中。
回顾一下:
- css-loader 抓取样式中的
@import
和url()
,style-loader 将其转换为 JavaScript 并实现了 Webpack 的热模块替换接口。 - Webpack 通过 loader 可以编译各种格式的 CSS 文件,这些包括Sass、Less 和 Stylus。
- PostCSS 允许您通过其插件系统转换 CSS。cssnext 是 PostCSS 插件集合中的一个案例,它实现了很多 CSS 未来特性。
- 默认情况下,css-loader 不会触及绝对导入。它允许通过
importLoaders
选项自定义加载行为。您可以通过在导入前添加~
字符来对 node_modules 目录执行查找。 - 要使用 source maps,您必须在你使用的每一个 css loader 中启用
sourceMap
(除了style-loader
);另外,您还应该将output.publicPath
设置为开发服务器的绝对 URL 地址。 - 在 Webpack 中使用 Bootstrap 需要特别小心。您可以使用一般的 loader,也可以基于 bootstrap-loader 来进行定制。
虽然这里介绍的加载方法足以用于开发,但它并不适合生产环境。你将在下一章发现这个问题背后的原因,并且学会通过将 CSS 从源码中抽离来解决这个问题。