sass-loader

免責聲明: sass-loader 是由社群成員維護的第三方套件,它可能不具備與 webpack 相同的支援、安全政策或授權,且並非由 webpack 維護。

npm node tests coverage discussion size

載入 Sass/SCSS 檔案並將其編譯為 CSS。

入門

首先,您需要安裝 sass-loader

npm install sass-loader sass webpack --save-dev

yarn add -D sass-loader sass webpack

pnpm add -D sass-loader sass webpack

sass-loader 要求您自行安裝 Dart SassNode Sass(更多文件說明如下)或 Sass Embedded

這讓您可以控制所有依賴項目的版本,並選擇要使用的 Sass 實作。

注意

我們強烈建議使用 Dart Sass

警告

Node Sass 無法與 Yarn PnP 功能搭配使用,也不支援 @use 規則

警告

Sass Embedded 仍處於實驗階段,且為 beta 版,因此某些功能可能無法使用

sass-loadercss-loaderstyle-loader 串聯,以立即將所有樣式套用至 DOM,或使用 mini-css-extract-plugin 將其萃取至一個獨立的檔案。

然後將載入器新增至您的 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: [
          // Creates `style` nodes from JS strings
          "style-loader",
          // Translates CSS into CommonJS
          "css-loader",
          // Compiles Sass to CSS
          "sass-loader",
        ],
      },
    ],
  },
};

最後透過您偏好的方式執行 webpack

production 模式中的 outputStyle(舊 API)和 style(新 API)選項

對於 production 模式,除非在 sassOptions 中另行指定,否則 outputStyle(舊 API)和 style(新 API)選項預設為 compressed

解析 import at 規則

Webpack 提供了一個 進階機制來解析檔案

sass-loader 使用 Sass 的自訂匯入功能,將所有查詢傳遞給 Webpack 解析引擎。因此,您可以從 node_modules 匯入 Sass 模組。

@import "bootstrap";

使用 ~ 已被棄用,可以從您的程式碼中移除(我們建議這麼做),但我們基於歷史原因仍支援它。為什麼您可以移除它?載入器會先嘗試將 @import 解析為相對路徑。如果無法解析,載入器會嘗試在 node_modules 中解析 @import

使用 ~ 為模組路徑加上前置字元,告訴 webpack 在 node_modules 中搜尋。

@import "~bootstrap";

重要的是,僅使用 ~ 作為前置字元,因為 ~/ 會解析為家目錄。Webpack 需要區分 bootstrap~bootstrap,因為 CSS 和 Sass 檔案沒有用於匯入相對檔案的特殊語法。撰寫 @import "style.scss"@import "./style.scss"; 相同。

url(...) 的問題

由於 Sass 實作不提供 網址改寫,所有連結的資產都必須相對於輸出。

  • 如果您將產生的 CSS 傳遞給 css-loader,所有網址都必須相對於進入檔案(例如 main.scss)。
  • 如果您只產生 CSS 而沒有傳遞給 css-loader,它必須相對於您的網路根目錄。

您會受到第一個問題的影響。自然會希望相對於指定 .sass/.scss 檔案的相對參照得到解析(就像在一般的 .css 檔案中一樣)。

感謝有兩個解決方案可以解決此問題

  • 使用 resolve-url-loader 新增遺失的 url 改寫。將其置於 loader 鏈中的 sass-loader 之前。
  • 函式庫作者通常會提供一個變數來修改資源路徑。例如,bootstrap-sass$icon-font-path

選項

implementation

類型

type implementation = object | string;

預設:sass

特殊的 implementation 選項決定要使用哪一種 Sass 實作。

預設情況下,loader 會根據您的依賴項解析實作。只要將需要的實作新增到 package.json (sassnode-sass 套件) 並安裝依賴項即可。

sass-loader loader 使用 sass (dart-sass) 實作的範例

package.json

{
  "devDependencies": {
    "sass-loader": "^7.2.0",
    "sass": "^1.22.10"
  }
}

sass-loader loader 使用 node-sass 實作的範例

package.json

{
  "devDependencies": {
    "sass-loader": "^7.2.0",
    "node-sass": "^5.0.0"
  }
}

當安裝了 node-sasssass 時,請小心處理這種情況!預設情況下,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: {
              // Prefer `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"),
            },
          },
        ],
      },
    ],
  },
};

sassOptions

類型

type sassOptions =
  | import("sass").LegacyOptions<"async">
  | ((
      content: string | Buffer,
      loaderContext: LoaderContext,
      meta: any,
    ) => import("sass").LegacyOptions<"async">);

預設值:Sass 實作的預設值

Dart SassNode Sass 實作的選項。

注意

charset 選項在 dart-sass 中預設為 true,我們強烈建議不要將值變更為 false,因為 webpack 不支援 utf-8 以外的檔案。

注意

indentedSyntax 選項在 sass 副檔名中為 true

注意

datafile 等選項不可用,且會被忽略。

ℹ 我們強烈建議不要變更 outFilesourceMapContentssourceMapEmbedsourceMapRoot 選項,因為當 sourceMap 選項為 true 時,sass-loader 會自動設定這些選項。

注意

可以在自訂匯入器內使用 this.webpackLoaderContext 屬性存取 loader context

sass (dart-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 context 設定 Sass 實作。

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              sassOptions: (content, loaderContext) => {
                // More information about available properties https://webpack.dev.org.tw/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

類型

type sourceMap = boolean;

預設值:取決於 compiler.devtool

啟用/停用原始碼地圖的產生。

預設的原始碼地圖產生取決於 devtool 選項。除了 evalfalse 值之外,所有值都會啟用原始碼地圖產生。

ℹ 如果 sourceMapsourceMapRootsourceMapEmbedsourceMapContentsomitSourceMapUrl 來自 sassOptionstrue,將會被忽略。

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 會輸出無效的原始碼對應 (這是 node-sass 的錯誤)。

為了避免這一點,你可以嘗試將 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

類型

type additionalData =
  | string
  | ((content: string | Buffer, loaderContext: LoaderContext) => string);

預設值:undefined

在實際的進入檔案之前,預先加入 Sass/SCSS 程式碼。這種情況下,sass-loader 不會覆寫 data 選項,而只是預先加入進入的內容。

當你的某些 Sass 變數取決於環境時,這特別有用

字串

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) => {
                // More information about available properties https://webpack.dev.org.tw/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.dev.org.tw/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

類型

type webpackImporter = boolean;

預設值:true

啟用/停用預設的 Webpack 匯入器。

在某些情況下,這可以提升效能。請小心使用,因為別名和以 ~ 開頭的 @import at 規則將無法運作。你可以傳遞自己的 importer 來解決這個問題 (請參閱 importer 文件).

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 warnRuleAsWarning = boolean;

預設值:true

@warn 規則視為 webpack 警告。

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,
            },
          },
        ],
      },
    ],
  },
};

api

類型

type api = "legacy" | "modern";

預設值:"legacy"

讓您在 legacymodern API 之間切換。您可以在 這裡 找到更多資訊。

警告

「現代」API 仍處於實驗階段,因此某些功能可能無法使用(已知:內建 importer 無法使用,且在初始執行時不會監控有錯誤的檔案),您可以追蹤 這裡 的資訊。

警告

sass 選項在 modernold API 中有所不同。請參閱 文件,了解如何轉移到新選項。

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              api: "modern",
              sassOptions: {
                // Your sass options
              },
            },
          },
        ],
      },
    ],
  },
};

如何啟用 @debug 輸出

預設情況下,@debug 訊息的輸出已停用。如要啟用,請將以下內容新增至 webpack.config.js

module.exports = {
  stats: {
    loggingDebug: ["sass-loader"],
  },
  // ...
};

範例

將 CSS 萃取到個別檔案

對於生產建置,建議從您的套件中萃取 CSS,以便稍後能夠平行載入 CSS/JS 資源。

有四種可能性可以從套件中萃取樣式表

1. mini-css-extract-plugin

webpack.config.js

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          // fallback to style-loader in development
          process.env.NODE_ENV !== "production"
            ? "style-loader"
            : MiniCssExtractPlugin.loader,
          "css-loader",
          "sass-loader",
        ],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: "[name].css",
      chunkFilename: "[id].css",
    }),
  ],
};

2. Asset Modules

webpack.config.js

module.exports = {
  entry: [__dirname + "/src/scss/app.scss"],
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [],
      },
      {
        test: /\.scss$/,
        exclude: /node_modules/,
        type: "asset/resource",
        generator: {
          filename: "bundle.css",
        },
        use: ["sass-loader"],
      },
    ],
  },
};

3. extract-loader(較簡單,但專門用於 css-loader 的輸出)

4. file-loader(已棄用,僅應在 Webpack v4 中使用)

webpack.config.js

module.exports = {
  entry: [__dirname + "/src/scss/app.scss"],
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [],
      },
      {
        test: /\.scss$/,
        exclude: /node_modules/,
        use: [
          {
            loader: "file-loader",
            options: { outputPath: "css/", name: "[name].min.css" },
          },
          "sass-loader",
        ],
      },
    ],
  },
};

(來源:https://stackoverflow.com/a/60029923/2969615)

原始碼對應

啟用/停用原始碼地圖的產生。

若要啟用 CSS 原始碼對應,您需要將 sourceMap 選項傳遞給 sass-loader css-loader。

webpack.config.js

module.exports = {
  devtool: "source-map", // any "source-map"-like devtool is possible
  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 以取得執行中的範例。

貢獻

如果您尚未閱讀我們的貢獻指南,請花點時間閱讀。

貢獻

授權

MIT