加载 Sass/SCSS 文件并将他们编译为 CSS。
首先,你需要安装 sass-loader
:
npm install sass-loader sass webpack --save-dev
sass-loader
需要预先安装 Dart Sass 或 Node Sass(可以在这两个链接中找到更多的资料)。这可以控制所有依赖的版本, 并自由的选择使用的 Sass 实现。
这样可以控制所有依赖项的版本,并选择要使用的 Sass 实现。
ℹ️ 我们推荐使用 Dart Sass。
将 sass-loader
、css-loader 与 style-loader 进行链式调用,可以将样式以 style 标签的形式插入 DOM 中,或者使用 mini-css-extract-plugin 将样式输出到独立的文件中。
然后将本 loader 添加到你的 Webpack 配置中。例如:
app.js
import './style.scss';
style.scss
$body-color: red;
body {
color: $body-color;
}
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
// 将 JS 字符串生成为 style 节点
'style-loader',
// 将 CSS 转化成 CommonJS 模块
'css-loader',
// 将 Sass 编译成 CSS
'sass-loader',
],
},
],
},
};
最后通过你喜欢的方式运行 webpack
。
import
的规则Webpack 提供一种 解析文件的高级机制。
sass-loader
使用 Sass 提供的 custom importer 特性,将所有 query 传递给 Webpack 解析引擎。
因此你可以从 node_modules
中引入 Sass modules。
@import "bootstrap";
~
用法已被废弃,可以从代码中删除(我们建议这么做),但是我们会因为一些历史原因一直支持这种写法。
为什么你可以移除它呢?loader 首先会尝试以相对路径解析 @import
,如果它不能被解析,loader 将会尝试在 node_modules
中解析 @import
。
在包名前加上 ~
就会告诉 Webpack 在 modules
中进行查找。
@import "~bootstrap";
重要的是,只在前面加上 ~
,因为~/
将会解析到用户的主目录(home directory)。
因为 CSS 和 Sass 文件没有用于导入相关文件的特殊语法,所以 Webpack 需要区分 bootstrap
和 ~bootstrap
。
@import "style.scss"
和 @import "./style.scss";
两种写法是相同的。
url(...)
的问题由于 Saass 的实现没有提供 url 重写的功能,所以相关的资源都必须是相对于输出文件(ouput)而言的。
css-loader
,则所有的 url 规则都必须是相对于入口文件的(例如:main.scss
)。css-loader
,那么所有的 url 都是相对于网站的根目录的。第一种情况可能会带来一些困扰。通常情况下我们希望相对路径引用的解析是相对于声明它的 .sass
/.scss
文件(如同在 .css
文件中一样)。
幸运的是,有两种方法可以解决这个问题:
sass-loader
之前,就可以重写 url。$icon-font-path
进行设置。名称 | 类型 | 默认值 | Description |
---|---|---|---|
implementation | {Object|String} | sass | 设置使用的 Sass 的实现。 |
sassOptions | {Object|Function} | Sass 实现的默认值 | Sass 自身选项。 |
sourceMap | {Boolean} | compiler.devtool | 启用 / 禁用 source maps 的生成。 |
additionalData | {String|Function} | undefined | 在实际的输入文件之前添加 Sass /SCSS 代码。 |
webpackImporter | {Boolean} | true | 启用 / 禁用默认的 Webpack importer。 |
warnRuleAsWarning | {Boolean} | false | 将 @warn 规则视为 webpack 警告。 |
implementation
类型: Object | String
默认值: sass
特殊的 implementation
选项确定要使用的 Sass 实现。
默认情况下,loader 将会根据你的依赖解析需要使用的实现。
只需将必需的实现添加到 package.json
(sass
或 node-sass
包)中并安装依赖项即可。
示例,此时 sass-loader
将会使用 sass
(dart-sass
)实现:
package.json
{
"devDependencies": {
"sass-loader": "^7.2.0",
"sass": "^1.22.10"
}
}
示例,此时 sass-loader
将会使用 node-sass
实现:
package.json
{
"devDependencies": {
"sass-loader": "^7.2.0",
"node-sass": "^5.0.0"
}
}
需注意同时安装 node-sass
和 sass
的情况!默认情况下,sass-loader
会选择 sass
。
为了避免这种情况,你可以使用 implementation
选项。
implementation
选项可以以模块的形式接受 sass
(Dart Sass
)或 node-sass
。
例如,为了使用 Dart Sass,你应该传递:
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
// `dart-sass` 是首选
implementation: require('sass'),
},
},
],
},
],
},
};
例如,为了使用 Dart Sass,你应该传递:
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
// Prefer `dart-sass`
implementation: require.resolve('sass'),
},
},
],
},
],
},
};
需要注意的是,当使用 sass
(Dart Sass
)时,由于异步回调的开销,通常情况下同步编译的速度是异步编译速度的两倍。
为了避免这种开销,你可以使用 fibers 包从同步代码中调用异步导入程序。
如果可能,我们会为小于 v16.0.0 的 Node.js
自动注入 fibers
软件包(设置 sassOptions.fiber
)(当然需要你安装 fibers
包)。
Fibers 不兼容
Node.js
v16.0.0 以及更高的版本(查看介绍)。
package.json
{
"devDependencies": {
"sass-loader": "^7.2.0",
"sass": "^1.22.10",
"fibers": "^4.0.1"
}
}
你可以通过向 sassOptions.fiber
传递 false
参数关闭自动注入的 fibers
包。
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
implementation: require('sass'),
sassOptions: {
fiber: false,
},
},
},
],
},
],
},
};
你还可以通过一下代码传递 fiber
:
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
implementation: require('sass'),
sassOptions: {
fiber: require('fibers'),
},
},
},
],
},
],
},
};
sassOptions
类型:Object|Function
默认值:Sass 实现的默认值
ℹ️
dart-sass
的charset
选项默认为true
,我们强烈建议你将其改为false
,因为 webpack 并不支持utf-8
以外的文件。
ℹ️
indentedSyntax
选项值为true
,是对sass
的扩展。
ℹ️ 像
data
和file
这样的选项是不可用的,且会被忽略。
ℹ 我们坚决反对设置
outFile
,sourceMapContents
,sourceMapEmbed
,sourceMapRoot
这些选项,因为当sourceMap
是true
时,sass-loader
会自动设置这些选项。
ℹ️ 可以使用
this.webpackLoaderContext
属性访问自定义 importer 中的 loader 上下文。
sass
(dart-sass
)和 node-sass
之间的选项略有不同。
在使用他们之前,请查阅有关文档:
sass
选项。node-sass
选项。Object
使用对象设置 Sass 实现的启动选项。
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
sassOptions: {
indentWidth: 4,
includePaths: ['absolute/path/a', 'absolute/path/b'],
},
},
},
],
},
],
},
};
Function
允许通过 loader 上下文为 Sass 实现设置不同的选项。
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
sassOptions: (loaderContext) => {
// 有关可用属性的更多信息 https://webpack.js.org/api/loaders/
const { resourcePath, rootContext } = loaderContext;
const relativePath = path.relative(rootContext, resourcePath);
if (relativePath === 'styles/foo.scss') {
return {
includePaths: ['absolute/path/c', 'absolute/path/d'],
};
}
return {
includePaths: ['absolute/path/a', 'absolute/path/b'],
};
},
},
},
],
},
],
},
};
sourceMap
类型:Boolean
默认值:取决于 compiler.devtool
的值
开启/关闭生成 source map。
默认情况下 source maps 的生成取决于 devtool
选项。
除 eval
和 false
之外的所有值都将开启 source map 的生成。
ℹ 如果为
true
将会忽略来自sassOptions
的sourceMap
,sourceMapRoot
,sourceMapEmbed
,sourceMapContents
和omitSourceMapUrl
选项。
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
sourceMap: true,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
},
],
},
};
ℹ 在极少数情况下,
node-sass
会输出无效的 source maps(这是node-sass
的 bug)。
为了避免这种情况,你可以尝试将
node-sass
更新到最新版本,或者可以尝试将sassOptions
中的outputStyle
选项设置为compressed
。
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
sourceMap: true,
sassOptions: {
outputStyle: 'compressed',
},
},
},
],
},
],
},
};
additionalData
类型:String|Function
默认值:undefined
在实际的文件之前要添加的 Sass
/ SCSS
代码。
在这种情况下,sass-loader
将不会覆盖 data
选项,而只是将它拼接在入口文件内容之前。
当某些 Sass 变量取决于环境时,这非常有用:
String
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
additionalData: '$env: ' + process.env.NODE_ENV + ';',
},
},
],
},
],
},
};
Function
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
additionalData: (content, loaderContext) => {
// 有关可用属性的更多信息 https://webpack.js.org/api/loaders/
const { resourcePath, rootContext } = loaderContext;
const relativePath = path.relative(rootContext, resourcePath);
if (relativePath === 'styles/foo.scss') {
return '$value: 100px;' + content;
}
return '$value: 200px;' + content;
},
},
},
],
},
],
},
};
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
additionalData: async (content, loaderContext) => {
// More information about available properties https://webpack.js.org/api/loaders/
const { resourcePath, rootContext } = loaderContext;
const relativePath = path.relative(rootContext, resourcePath);
if (relativePath === 'styles/foo.scss') {
return '$value: 100px;' + content;
}
return '$value: 200px;' + content;
},
},
},
],
},
],
},
};
webpackImporter
类型:Boolean
默认值:true
开启 / 关闭默认的 Webpack importer。
在某些情况下,可以提高性能。但是请谨慎使用,因为 aliases 和以 〜
开头的 @import
规则将不起作用。
你可以传递自己的 importer
来解决这个问题(参阅 importer docs
)。
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
webpackImporter: false,
},
},
],
},
],
},
};
warnRuleAsWarning
Type: Boolean
Default: false
将 @warn
规则视为 webpack 警告。
ℹ️ 在下一个大版本发布中它将默认设置为
true
。
style.scss
$known-prefixes: webkit, moz, ms, o;
@mixin prefix($property, $value, $prefixes) {
@each $prefix in $prefixes {
@if not index($known-prefixes, $prefix) {
@warn "Unknown prefix #{$prefix}.";
}
-#{$prefix}-#{$property}: $value;
}
#{$property}: $value;
}
.tilt {
// Oops, we typo'd "webkit" as "wekbit"!
@include prefix(transform, rotate(15deg), wekbit ms);
}
给出的代码将抛出 webpack 警告而不是日志。
要忽略不必要的警告,可以使用 ignoreWarnings 配置项。
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
"style-loader",
"css-loader",
{
loader: "sass-loader",
options: {
warnRuleAsWarning: true,
},
},
],
},
],
},
};
对于生产版本,我们建议从 bundle 中提取 CSS,以便之后可以使 CSS/JS 资源并行加载。
从 bundle 中提取样式表,有 2 种实用的方式:
webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
// 在开发过程中回退到 style-loader
process.env.NODE_ENV !== 'production'
? 'style-loader'
: MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader',
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
// 与 webpackOptions.output 中的选项相似
// 所有的选项都是可选的
filename: '[name].css',
chunkFilename: '[id].css',
}),
],
};
开启/关闭 source map 的生成。
为了开启 CSS source maps,需要将 sourceMap
选项作为参数,传递给 sass-loader
和 css-loader
。
webpack.config.js
module.exports = {
devtool: "source-map", // 任何类似于 "source-map" 的选项都是支持的
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
"style-loader",
{
loader: "css-loader",
options: {
sourceMap: true,
},
},
{
loader: "sass-loader",
options: {
sourceMap: true,
},
},
],
},
],
},
};
如果你要在 Chrome 中编辑原始的 Sass 文件,建议阅读 这篇不错的博客。具体示例参考 test/sourceMap。
如果你还没有阅读过我们的贡献指南,请花一点时间阅读它。