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

[!注意]

要在你的项目中启用 CSS 处理,你需要通过 npm i style-loader css-loader 安装 style-loadercss-loader

sass-loader 要求你自己安装 Dart SassNode Sass(更多文档可在下方找到)或 Sass Embedded

这使你能够控制所有依赖的版本,并选择要使用的 Sass 实现。

[!注意]

我们强烈建议使用 Sass EmbeddedDart Sass

[!警告]

Node Sass 不支持 Yarn PnP 且不支持 @use 规则

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

最后,通过你喜欢的方式(例如,通过 CLI 或 npm 脚本)运行 webpack

`production` 模式下的 style(新 API,默认自 16 版本起)和 outputStyle(旧 API)选项

对于 production 模式,style(新 API,默认自 16 版本起)和 outputStyle(旧 API)选项默认为 compressed,除非在 sassOptions 中另有指定。

解析 importuse at-rules

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 实现不提供 URL 重写,所有链接的资产必须相对于输出。

  • 如果你将生成的 CSS 传递给 css-loader,所有 URL 必须相对于入口文件(例如 main.scss)。
  • 如果你只是生成 CSS 而不将其传递给 css-loader,URL 必须相对于你的 Web 根目录。

你可能会对第一个问题感到惊讶,因为通常会期望相对引用根据它们所在的 `.sass`/.scss 文件解析(就像常规 `.css` 文件一样)。

幸运的是,这个问题有两个解决方案

  • 使用 resolve-url-loader 添加缺失的 URL 重写。将其放置在加载器链中的 sass-loader 之前。

  • 库作者通常会提供一个变量来修改资产路径。例如,bootstrap-sass 有一个 $icon-font-path

选项

implementation

类型

type implementation = object | string;

默认值:sass

特殊的 implementation 选项决定使用哪个 Sass 实现。

默认情况下,加载器根据你的依赖解析实现。只需将所需的实现添加到你的 package.jsonsasssass-embeddednode-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"
  }
}

sass-loader 使用 sass-embedded 实现的示例

package.json

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

[!注意]

使用 optionalDependencies 意味着当在 sass-embedded 不支持的操作系统上运行时,sass-loader 可以回退到 sass

请注意 sass-loader 解析实现的顺序

  1. sass-embedded
  2. sass
  3. node-sass

你可以通过使用 implementation 选项来指定特定的实现,该选项接受上述值之一。

object

例如,要始终使用 Dart Sass,你可以传入

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              // Prefer `dart-sass`, even if `sass-embedded` is available
              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`, even if `sass-embedded` is available
              implementation: require.resolve("sass"),
            },
          },
        ],
      },
    ],
  },
};

sassOptions

类型

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

默认值:Sass 实现的默认值

[Dart Sass](https://sass-lang.cn/dart-sass) 或 [Node Sass](https://github.com/sass/node-sass) 实现的选项。

[!注意]

对于 dart-sasscharset 选项默认为 true。我们强烈不建议将其设置为 false,因为 webpack 不支持 utf-8 以外的文件。

[!注意]

syntax(新 API,默认自 16 版本起)和 indentedSyntax(旧 API)选项对于 scss 扩展是 scss,对于 sass 扩展是 indented,对于 css 扩展是 css

[!注意]

datafile 等选项不可用,将被忽略。

ℹ 我们强烈不建议更改 sourceMap(新 API,默认自 16 版本起)、outFile(旧 API)、sourceMapContents(旧 API)、sourceMapEmbed(旧 API)和 sourceMapRoot(旧 API)选项,因为当 sourceMap 选项为 true 时,sass-loader 会自动设置这些选项。

[!注意]

在自定义导入器内部访问加载器上下文 可以通过 this.webpackLoaderContext 属性完成。

sass (`dart-sass`) 和 node-sass 的选项略有不同。

使用前请查阅它们各自的文档

  • [Dart Sass 文档](https://sass-lang.cn/documentation/js-api/interfaces/Options)以获取所有可用的 sass 选项。
  • [Sass Embedded 文档](https://github.com/sass/embedded-host-node)以获取所有可用的 sass 选项。
  • [Node Sass 文档](https://github.com/sass/node-sass/#options)以获取所有可用的 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: {
                style: `compressed`,
                loadPaths: ["absolute/path/a", "absolute/path/b"],
              },
            },
          },
        ],
      },
    ],
  },
};

function

允许根据加载器上下文使用不同的选项配置 Sass 实现。

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              sassOptions: (loaderContext) => {
                // More information about available properties https://webpack.js.cn/api/loaders/
                const { resourcePath, rootContext } = loaderContext;
                const relativePath = path.relative(rootContext, resourcePath);

                if (relativePath === "styles/foo.scss") {
                  return {
                    loadPaths: ["absolute/path/c", "absolute/path/d"],
                  };
                }

                return {
                  loadPaths: ["absolute/path/a", "absolute/path/b"],
                };
              },
            },
          },
        ],
      },
    ],
  },
};

sourceMap

类型

type sourceMap = boolean;

默认值:取决于 compiler.devtool 的值

启用/禁用源映射生成。

默认情况下,源映射的生成取决于 devtool 选项。除 evalfalse 外,所有值都启用源映射生成。

ℹ 如果为 truesassOptions 中的 sourceMap(新 API,默认自 16 版本起)、outFile(旧 API)、sourceMapContents(旧 API)、sourceMapEmbed(旧 API)和 sourceMapRoot(旧 API)将被忽略。

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 的 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

类型

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

默认值: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) => {
                // More information about available properties https://webpack.js.cn/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.cn/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-rules 将不起作用。你可以传入你自己的 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" | "modern-compiler";

默认值:对于 sass (`dart-sass`) 和 sass-embedded"modern",对于 node-sass"legacy"

允许你在 legacymodern API 之间切换。你可以在这里找到更多信息。modern-compiler 选项启用支持共享资源的现代 API。

[!注意]

同时使用 modern-compilersass-embedded 可以显著提高性能并缩短构建时间。我们强烈建议使用它们。我们将在未来的主要版本中默认启用它们。

[!警告]

legacymodern API 的 Sass 选项有所不同。请查阅文档以了解如何迁移到现代选项。

webpack.config.js

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

如何启用 @debug 输出

默认情况下,@debug 消息的输出是禁用的。将以下内容添加到 webpack.config.js 以启用它们

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

示例

将 CSS 提取到单独的文件中

对于生产构建,建议从你的 bundle 中提取 CSS,以实现 CSS/JS 资源的并行加载。

有四种推荐的方法可以从 bundle 中提取样式表

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