加載 Sass/SCSS 文件并將他們編譯為 CSS。
首先,你需要安裝 sass-loader:
npm install sass-loader sass webpack --save-dev
sass-loader 需要預先安裝 Dart Sass 或 Node Sass(可以在這兩個鏈接中找到更多的資料)。這可以控制所有依賴的版本, 并自由的選擇使用的 Sass 實現(xiàn)。
這樣可以控制所有依賴項的版本,并選擇要使用的 Sass 實現(xiàn)。
?? 我們推薦使用 Dart Sass。
? Node Sass 不能與 Yarn PnP 特性一起正常工作,并且不支持 @use rule。
將 sass-loader 、css-loader 與 style-loader 進行鏈式調(diào)用,可以將樣式以 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 節(jié)點
'style-loader',
// 將 CSS 轉(zhuǎn)化成 CommonJS 模塊
'css-loader',
// 將 Sass 編譯成 CSS
'sass-loader',
],
},
],
},
};
最后通過你喜歡的方式運行 webpack。
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 文件沒有用于導入相關(guān)文件的特殊語法,所以 Webpack 需要區(qū)分 bootstrap 和 ~bootstrap。 @import "style.scss" 和 @import "./style.scss"; 兩種寫法是相同的。
由于 Sass 的實現(xiàn)沒有提供 url 重寫的功能,所以相關(guān)的資源都必須是相對于輸出文件(ouput)而言的。
第一種情況可能會帶來一些困擾。通常情況下我們希望相對路徑引用的解析是相對于聲明它的 .sass/.scss 文件(如同在 .css 文件中一樣)。
幸運的是,有兩種方法可以解決這個問題:
名稱 | 類型 | 默認值 | Description |
---|---|---|---|
implementation
|
{Object|String}
|
sass
|
設置使用的 Sass 的實現(xiàn)。 |
sassOptions
|
{Object|Function}
|
Sass 實現(xiàn)的默認值 | Sass 自身選項。 |
sourceMap
|
{Boolean}
|
compiler.devtool
|
啟用 / 禁用 source maps 的生成。 |
additionalData
|
{String|Function}
|
undefined
|
在實際的輸入文件之前添加 Sass /SCSS 代碼。 |
webpackImporter
|
{Boolean}
|
true
|
啟用 / 禁用默認的 Webpack importer。 |
warnRuleAsWarning
|
{Boolean}
|
false
|
將 @warn 規(guī)則視為 webpack 警告。 |
類型: ?Object | String
? 默認值: sass
特殊的 implementation 選項確定要使用的 Sass 實現(xiàn)。
默認情況下,loader 將會根據(jù)你的依賴解析需要使用的實現(xiàn)。 只需將必需的實現(xiàn)添加到 package.json(sass 或 node-sass 包)中并安裝依賴項即可。
示例,此時 sass-loader 將會使用 sass (dart-sass)實現(xiàn):
package.json
{
"devDependencies": {
"sass-loader": "^7.2.0",
"sass": "^1.22.10"
}
}
示例,此時 sass-loader 將會使用 node-sass 實現(xiàn):
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)時,由于異步回調(diào)的開銷,通常情況下同步編譯的速度是異步編譯速度的兩倍。 為了避免這種開銷,你可以使用 fibers 包從同步代碼中調(diào)用異步導入程序。
如果可能,我們會為小于 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 參數(shù)關(guān)閉自動注入的 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'),
},
},
},
],
},
],
},
};
類型:?Object|Function
? 默認值:Sass 實現(xiàn)的默認值
Dart Sass 或者 Node Sass 實現(xiàn)的選項。
?? 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 之間的選項略有不同。
在使用他們之前,請查閱有關(guān)文檔:
使用對象設置 Sass 實現(xiàn)的啟動選項。
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'],
},
},
},
],
},
],
},
};
允許通過 loader 上下文為 Sass 實現(xiàn)設置不同的選項。
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
sassOptions: (loaderContext) => {
// 有關(guān)可用屬性的更多信息 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'],
};
},
},
},
],
},
],
},
};
類型:?Boolean
? 默認值:取決于 compiler.devtool 的值
開啟/關(guān)閉生成 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,
},
},
],
},
],
},
};
? 在極少數(shù)情況下,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',
},
},
},
],
},
],
},
};
類型:?String|Function
? 默認值:undefined
在實際的文件之前要添加的 Sass / SCSS 代碼。 在這種情況下,sass-loader 將不會覆蓋 data 選項,而只是將它拼接在入口文件內(nèi)容之前。
當某些 Sass 變量取決于環(huán)境時,這非常有用:
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
additionalData: '$env: ' + process.env.NODE_ENV + ';',
},
},
],
},
],
},
};
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
additionalData: (content, loaderContext) => {
// 有關(guān)可用屬性的更多信息 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;
},
},
},
],
},
],
},
};
類型:?Boolean
? 默認值:true
開啟 / 關(guān)閉默認的 Webpack importer。
在某些情況下,可以提高性能。但是請謹慎使用,因為 aliases 和以 ? 開頭的 @import 規(guī)則將不起作用。 你可以傳遞自己的 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,
},
},
],
},
],
},
};
Type: Boolean Default: false
將 @warn 規(guī)則視為 webpack 警告。
?? 在下一個大版本發(fā)布中它將默認設置為 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,
},
},
],
},
],
},
};
對于生產(chǎn)版本,我們建議從 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: [
// 在開發(fā)過程中回退到 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',
}),
],
};
開啟/關(guān)閉 source map 的生成。
為了開啟 CSS source maps,需要將 sourceMap 選項作為參數(shù),傳遞給 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,
},
},
],
},
],
},
};
如果你還沒有閱讀過我們的貢獻指南,請花一點時間閱讀它。
更多建議: