MIT License

项目介绍

webpack/sass-loader 是一个托管在 GitHub 上的开源项目,主要使用 JavaScript 编写,采用 MIT License 许可证,目前获得 3.9k 个 Star、405 次 Fork。

仓库全名
webpack/sass-loader
开源许可证
MIT License
Star 数
3.9k
Fork 数
405

README 摘要

src="https://worldvectorlogo.com/logos/sass-1.svg"> src="https://webpack.js.org/assets/icon-square-big.svg"> sass-loader Loads a Sass/SCSS file and compiles it to CSS. Getting Started To begin, you'll need to install sass-loader: or or [!NOTE] Webpack has built-in CSS support, so no extra loaders are required to process the CSS generated by sass-loader - just set the module type to css/auto. This is the recommended…

完整内容见 GitHub 原始 README 或本页 。

常见问题

sass-loader 用什么语言开发?

主要使用 JavaScript 编写,采用 MIT License 许可证,目前有 3.9k 个 Star。

sass-loader 可以免费商用吗?

仓库采用 MIT License 许可证,可免费使用与修改,商业使用请遵守许可证条款(例如保留版权声明与许可声明)。

如何获取 sass-loader 的源码?

可以直接克隆仓库:git clone https://github.com/webpack/sass-loader.git,默认分支为 main;安装与运行步骤见仓库 README。

sass-loader 最近还在维护吗?

仓库最近一次更新为 1 周前,当前没有未关闭的 Issue;Star 数为 3.9k,可作为社区活跃度的参考。

关于

GitHub 原始描述(英文)

Compiles Sass to CSS

描述取自 GitHub 官方 API,保持仓库作者书写的原文。

简要分析

热度分
4749
价值分
2459
活跃状态
活跃

语言占比

CSS
JavaScript
SCSS
Sass

Release

README

npm node tests coverage discussion size discord-invite

sass-loader

Loads a Sass/SCSS file and compiles it to CSS.

Getting Started

To begin, you’ll need to install sass-loader:

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

or

yarn add -D sass-loader sass webpack

or

pnpm add -D sass-loader sass webpack
Note 注意

Webpack has built-in CSS support, so no extra loaders are required to process the CSS generated by sass-loader - just set the module type to css/auto. This is the recommended setup, and needs webpack 5.87.0 or later.

Since webpack 5.109.0 the built-in support is on by default (experiments.css defaults to "auto"), but "auto" switches it off when another module.rules entry handles .css files, so the examples below keep experiments.css: true. If such a rule still uses css-loader, give it type: "javascript/auto" so built-in CSS leaves those files to it.

The deprecated loader-based setup still works: install style-loader and css-loader via npm i style-loader css-loader and chain them with sass-loader instead, or follow the Native CSS migration guide to move off them.

sass-loader requires you to install either Dart Sass or Sass Embedded on your own (more documentation can be found below).

This allows you to control the versions of all your dependencies and to choose which Sass implementation to use.

Note 注意

We highly recommend using Sass Embedded or Dart Sass.

Use the sass-loader with the built-in CSS support of webpack (the css/auto module type) to let webpack handle the generated CSS - it extracts styles into a separate file. Its output is a .css file the page has to link: let webpack build the page — an HTML entry or output.html: true (webpack 5.108.0 or later; before 5.109.0 also set experiments.html: true) adds the <link> for you — set exportType: "style" (webpack 5.106.0 or later) to inject the styles from JavaScript instead, or link the emitted file yourself.

Alternatively, you can chain the sass-loader with the deprecated css-loader and the style-loader to immediately apply all styles to the DOM, or with the deprecated mini-css-extract-plugin to extract it into a separate file.

Then add the loader to your webpack configuration. For example:

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,
        // Lets webpack handle the generated CSS using its built-in CSS support,
        // `css/auto` also enables CSS modules for `*.module.scss` files
        type: "css/auto",
        use: [
          // Compiles Sass to CSS
          "sass-loader",
        ],
      },
    ],
  },
  experiments: {
    // Enables the built-in CSS support of webpack
    css: true,
  },
};

Finally run webpack via your preferred method (e.g., via CLI or an npm script).

Note 注意

All examples below use the built-in CSS support of webpack. If you still use the deprecated css-loader and style-loader (or mini-css-extract-plugin) instead, remove the type and experiments options and put them before the sass-loader in the use array:

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

The style option in production mode

For production mode, the style option defaults to compressed unless otherwise specified in sassOptions.

Resolving import, use and forward at-rules

Webpack provides an advanced mechanism to resolve files.

The sass-loader uses Sass’s custom importer feature to pass every @use, @import and @forward request to the webpack resolving engine, so your webpack resolve configuration applies to stylesheets, and you can load Sass modules from node_modules:

@use "bootstrap";
How a request is resolved

For @use "theme" inside src/app.scss, the loader asks webpack for the following and takes the first hit:

  1. the partial src/_theme.sass, src/_theme.scss, src/_theme.css
  2. src/theme.sass, src/theme.scss, src/theme.css
  3. theme as written, so aliases and package requests resolve

Directories resolve through their _index/index file. For @import only, the import-only files _theme.import.scss and theme.import.scss are tried before everything else.

Relative requests win over module ones, so @use "theme" behaves like @use "./theme" when both could match. Keeping both _theme.scss and theme.scss in one directory is ambiguous and Sass reports an error for it, so the order within a directory rarely matters.

What your resolve configuration controls
  • alias - applied to every request, and tried before node_modules
  • modules - extra directories to look in, e.g. src
  • byDependency.sass - requests are resolved with dependencyType: "sass", so this targets stylesheets only
  • plugins, symlinks, roots and the rest of the resolver options

webpack.config.js

module.exports = {
  resolve: {
    alias: { "@styles": path.resolve(__dirname, "src/styles") },
    modules: [path.resolve(__dirname, "src"), "node_modules"],
  },
};

style.scss

@use "@styles/theme" as *; // resolved by `resolve.alias`
@use "abstracts" as *; // resolved by `resolve.modules` to `src/abstracts/_index.scss`

Some options are fixed to match Sass’s own algorithm and can’t be changed through resolve: the extensions are .sass, .scss and .css (so resolve.extensions doesn’t apply here), mainFiles prefer _index/index, mainFields prefer sass and style over main, and conditionNames prefer the sass and style export conditions. Your own mainFields and conditionNames are kept after those.

Packages

A package request resolves through the sass and style conditions of its exports field, falling back to the sass, style and main fields. The pkg: URL scheme is supported as well:

@use "pkg:bootstrap";
When webpack can’t resolve a request

The importer hands the request back to Sass, which then applies its own resolution - sassOptions.loadPaths, the SASS_PATH environment variable and any custom importer you configured.

Plain CSS files

Sass compiles @import "theme.css" to a plain CSS @import, so the loader leaves it in the output untouched - whatever handles the CSS afterwards (the built-in CSS support of webpack, css-loader, or the browser) decides what happens with it. @use "theme.css" includes the file’s content instead, and is resolved like any other request:

@import "theme.css"; // stays `@import "theme.css";` in the output
@use "theme.css"; // inlines the content of the file
The ~ prefix

Using ~ is deprecated and should be removed from your code, but we still support it for historical reasons.

Why can you remove it? The loader will first try to resolve @use as a relative path. If it cannot be resolved, then the loader will try to resolve it inside node_modules.

Prepending module paths with a ~ tells webpack to search through node_modules.

@use "~bootstrap";

It’s important to prepend the path with only ~, because ~/ resolves to the home directory.

Webpack needs to distinguish between bootstrap and ~bootstrap because CSS and Sass files have no special syntax for importing relative files.

Writing @use "style.scss" is the same as @use "./style.scss";

Problems with url(...)

Since Sass implementations don’t provide url rewriting, all linked assets must be relative to the output.

  • If webpack handles the generated CSS (i.e. the built-in CSS support or the css-loader), all URLs must be relative to the entry-file (e.g. main.scss).
  • If you’re just generating CSS without letting webpack handle it, URLs must be relative to your web root.

You might be surprised by this first issue, as it is natural to expect relative references to be resolved against the .sass/.scss file in which they are specified (like in regular .css files).

Thankfully there are two solutions to this problem:

  • Add the missing URL rewriting using the resolve-url-loader. Place it before sass-loader in the loader chain.

  • Library authors usually provide a variable to modify the asset path. bootstrap-sass for example, has an $icon-font-path.

Options

implementation

Type:

type implementation = object | string;

Default: sass

The special implementation option determines which implementation of Sass to use.

By default, the loader resolves the implementation based on your dependencies. Just add the desired implementation to your package.json (sass or sass-embedded package) and install dependencies.

Example where the sass-loader uses the sass (dart-sass) implementation:

package.json

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

Example where the sass-loader uses the sass-embedded implementation:

package.json

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

Using optionalDependencies means that sass-loader can fallback to sass when running on an operating system not supported by sass-embedded

Be aware of the order that sass-loader will resolve the implementation:

  1. sass-embedded
  2. sass

You can specify a specific implementation by using the implementation option, which accepts one of the above values.

object

For example, to always use Dart Sass, you’d pass:

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        type: "css/auto",
        use: [
          {
            loader: "sass-loader",
            options: {
              // Prefer `dart-sass`, even if `sass-embedded` is available
              implementation: require("sass"),
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};
string

For example, to use Dart Sass, you’d pass:

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        type: "css/auto",
        use: [
          {
            loader: "sass-loader",
            options: {
              // Prefer `dart-sass`, even if `sass-embedded` is available
              implementation: require.resolve("sass"),
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

sassOptions

Type:

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

Default: defaults values for Sass implementation

Options for Dart Sass or Sass Embedded implementation.

Note 注意

The charset option is true by default for dart-sass. We strongly discourage setting this to false because webpack doesn’t support files other than utf-8.

Note 注意

The syntax option is scss for the scss extension, indented for the sass extension, and css for the css extension.

Note 注意

Options such as data and url are unavailable and will be ignored.

ℹ We strongly discourage changing the sourceMap option because sass-loader sets it automatically when the sourceMap option is true.

Please consult their respective documentation before using them:

object

Use an object for the Sass implementation setup.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        type: "css/auto",
        use: [
          {
            loader: "sass-loader",
            options: {
              sassOptions: {
                style: "compressed",
                loadPaths: ["absolute/path/a", "absolute/path/b"],
              },
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};
function

Allows configuring the Sass implementation with different options based on the loader context.

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        type: "css/auto",
        use: [
          {
            loader: "sass-loader",
            options: {
              sassOptions: (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 {
                    loadPaths: ["absolute/path/c", "absolute/path/d"],
                  };
                }

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

sourceMap

Type:

type sourceMap = boolean;

Default: depends on the compiler.devtool value

Enables/disables generation of source maps.

By default generation of source maps depends on the devtool option. All values enable source map generation except eval and false.

ℹ If true, the sourceMap option from sassOptions will be ignored.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        type: "css/auto",
        use: [
          {
            loader: "sass-loader",
            options: {
              sourceMap: true,
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        type: "css/auto",
        use: [
          {
            loader: "sass-loader",
            options: {
              sourceMap: true,
              sassOptions: {
                style: "compressed",
              },
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

additionalData

Type:

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

Default: undefined

Prepends Sass/SCSS code before the actual entry file. In this case, the sass-loader will not override the data option but just prepend the entry’s content.

This is especially useful when some of your Sass variables depend on the environment:

string
module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        type: "css/auto",
        use: [
          {
            loader: "sass-loader",
            options: {
              additionalData: `$env: ${process.env.NODE_ENV};`,
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};
function
Sync
module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        type: "css/auto",
        use: [
          {
            loader: "sass-loader",
            options: {
              additionalData: (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}`;
              },
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};
Async
module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        type: "css/auto",
        use: [
          {
            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}`;
              },
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

webpackImporter

Type:

type webpackImporter = boolean;

Default: true

Enables/disables the default webpack importer.

This can improve performance in some cases, though use it with caution because aliases and @import at-rules starting with ~ will not work. You can pass your own importer to solve this (see Sass importer documentation).

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        type: "css/auto",
        use: [
          {
            loader: "sass-loader",
            options: {
              webpackImporter: false,
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

warnRuleAsWarning

Type:

type warnRuleAsWarning = boolean;

Default: true

Treats the @warn rule as a webpack warning.

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);
}

The presented code will throw a webpack warning instead of logging.

To ignore unnecessary warnings you can use the ignoreWarnings option.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        type: "css/auto",
        use: [
          {
            loader: "sass-loader",
            options: {
              warnRuleAsWarning: true,
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

api

Type:

type api = "auto" | "modern" | "modern-compiler";

Default: "auto" for sass (dart-sass) and sass-embedded

Allows you to switch between the modern and modern-compiler APIs. You can find more information here. The modern-compiler option enables the modern API with support for Shared Resources.

When "auto" is used, the loader picks "modern-compiler" whenever the implementation exposes initAsyncCompiler (i.e. recent versions of sass and sass-embedded) and falls back to "modern" otherwise. Combined with sass-embedded, this yields the best build performance out of the box.

Note 注意

Using modern-compiler and sass-embedded together significantly improves performance and decreases build time. They are now selected automatically by the default "auto" API.

Note 注意

The legacy Sass JS API is no longer supported. If you were using api: "legacy", please migrate to the modern API. See the Sass JS API docs to learn how to migrate.

webpack.config.js

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

How to enable @debug output

By default, the output of @debug messages is disabled. Add the following to webpack.config.js to enable them:

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

Examples

Extracts CSS into separate files

For production builds, extract the CSS from your bundle to enable parallel loading of CSS/JS resources.

With the built-in CSS support of webpack this needs no plugin: the CSS that sass-loader produces is extracted into separate files out of the box — every entry point and every lazily loaded chunk gets its own .css file — and it is minified in production mode. Name the files with output.cssFilename and output.cssChunkFilename:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        type: "css/auto",
        use: ["sass-loader"],
      },
    ],
  },
  output: {
    // Both options are optional
    cssFilename: "[name].[contenthash].css",
    cssChunkFilename: "[id].[contenthash].css",
  },
  experiments: {
    // Only required before webpack 5.109.0, where the built-in CSS support is opt-in
    css: true,
  },
};

To control how stylesheets are grouped into files (one file for every page, a separate vendor stylesheet, …), use optimization.splitChunks.

Compiling a standalone stylesheet

To emit the compiled Sass as a file without importing it from JavaScript, use Asset Modules. Webpack then writes sass-loader’s output as-is: url() and @import are not resolved or rewritten, and CSS Modules are not applied.

webpack.config.js

const path = require("node:path");

module.exports = {
  entry: [path.resolve(__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"],
      },
    ],
  },
};
Legacy: mini-css-extract-plugin (deprecated)

Setups that still use the deprecated css-loader extract CSS with the deprecated mini-css-extract-plugin. Follow the Native CSS migration guide to replace both with the configuration above.

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

Source maps

Enables/disables generation of source maps.

To enable CSS source maps, you’ll need to pass the sourceMap option to the sass-loader (and to the css-loader too, when you use it).

webpack.config.js

module.exports = {
  devtool: "source-map", // any "source-map"-like devtool is possible
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        type: "css/auto",
        use: [
          {
            loader: "sass-loader",
            options: {
              sourceMap: true,
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

If you want to edit the original Sass files inside Chrome, there’s a good blog post. Checkout test/sourceMap for a working example.

Contributing

We welcome all contributions! If you’re new here, please take a moment to review our contributing guidelines before submitting issues or pull requests.

CONTRIBUTING

License

MIT

评论

暂无评论