Webpack sass-loader
加载 Sass/SCSS 文件并将他们编译为 CSS。
快速开始
首先,你需要安装 sass-loader:
npm install sass-loader sass webpack --save-dev
sass-loader 需要预先安装 Dart Sass 或 Node Sass(可以在这两个链接中找到更多的资料)。这可以控制所有依赖的版本, 并自由的选择使用的 Sass 实现。
这样可以控制所有依赖项的版本,并选择要使用的 Sass 实现。
ℹ️ 我们推荐使用 Dart Sass。
⚠ Node Sass 不能与 Yarn PnP 特性一起正常工作,并且不支持 @use rule。
将 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(...) 的问题
由于 Sass 的实现没有提供 url 重写的功能,所以相关的资源都必须是相对于输出文件(ouput)而言的。
- 如果生成的 CSS 传递给了 css-loader,则所有的 url 规则都必须是相对于入口文件的(例如:main.scss)。
- 如果仅仅生成了 CSS 文件,没有将其传递给 css-loader,那么所有的 url 都是相对于网站的根目录的。
第一种情况可能会带来一些困扰。通常情况下我们希望相对路径引用的解析是相对于声明它的 .sass/.scss 文件(如同在 .css 文件中一样)。
幸运的是,有两种方法可以解决这个问题:
- 将 resolve-url-loader 设置于 loader 链中的 sass-loader 之前,就可以重写 url。
- Library 作者一般都会提供变量,用来设置资源路径。比如 bootstrap-sass 可以通过 $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。
Object
例如,为了使用 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'),
},
},
],
},
],
},
};
String
例如,为了使用 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 或者 Node 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 之间的选项略有不同。
在使用他们之前,请查阅有关文档:
- Dart Sass 文档 提供了所有可用的 sass 选项。
- Node 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
Sync
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;
},
},
},
],
},
],
},
};
Async
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 种实用的方式:
- mini-css-extract-plugin
- extract-loader (简单,专门针对 css-loader 的输出)
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 maps
开启/关闭 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,
},
},
],
},
],
},
};
贡献
如果你还没有阅读过我们的贡献指南,请花一点时间阅读它。
License
更多建议: