<div align="center">
  <img height="170"
    src="https://worldvectorlogo.com/logos/sass-1.svg">
  <a href="https://github.com/webpack/webpack">
    <img width="200" height="200"
      src="https://webpack.js.org/assets/icon-square-big.svg">
  </a>
</div>

[![npm][npm]][npm-url]
[![node][node]][node-url]
[![tests][tests]][tests-url]
[![coverage][cover]][cover-url]
[![discussion][discussion]][discussion-url]
[![size][size]][size-url]
[![discord-invite][discord-invite]][discord-url]

# sass-loader

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

## Getting Started

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

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

or

```console
yarn add -D sass-loader sass webpack
```

or

```console
pnpm add -D sass-loader sass webpack
```

> [!NOTE]
>
> To enable CSS processing in your project, you need to install [style-loader](https://webpack.js.org/loaders/style-loader/) and [css-loader](https://webpack.js.org/loaders/css-loader/) via `npm i style-loader css-loader`.

`sass-loader` requires you to install either [Dart Sass](https://github.com/sass/dart-sass) or [Sass Embedded](https://github.com/sass/embedded-host-node) 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](https://github.com/sass/embedded-host-node) or [Dart Sass](https://github.com/sass/dart-sass).

Chain the `sass-loader` with the [css-loader](https://github.com/webpack/css-loader) and the [style-loader](https://github.com/webpack/style-loader) to immediately apply all styles to the DOM, or with the [mini-css-extract-plugin](https://github.com/webpack/mini-css-extract-plugin) to extract it into a separate file.

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

**app.js**

```js
import "./style.scss";
```

**style.scss**

```scss
$body-color: red;

body {
  color: $body-color;
}
```

**webpack.config.js**

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

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

### The `style` option in `production` mode

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

### Resolving `import` and `use` at-rules

Webpack provides an [advanced mechanism to resolve files](https://webpack.js.org/concepts/module-resolution/).

The `sass-loader` uses Sass's custom importer feature to pass all queries to the webpack resolving engine, enabling you to import your Sass modules from `node_modules`.

```scss
@import "bootstrap";
```

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 `@import` as a relative path. If it cannot be resolved, then the loader will try to resolve `@import` inside [`node_modules`](https://webpack.js.org/configuration/resolve/#resolvemodules).

Prepending module paths with a `~` tells webpack to search through [`node_modules`](https://webpack.js.org/configuration/resolve/#resolvemodules).

```scss
@import "~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 `@import "style.scss"` is the same as `@import "./style.scss";`

### Problems with `url(...)`

Since Sass implementations don't provide [url rewriting](https://github.com/sass/libsass/issues/532), all linked assets must be relative to the output.

- If you pass the generated CSS on to the `css-loader`, all URLs must be relative to the entry-file (e.g. `main.scss`).
- If you're just generating CSS without passing it to the `css-loader`, 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](https://github.com/bholloway/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](https://github.com/twbs/bootstrap-sass) for example, has an `$icon-font-path`.

## Options

- **[`implementation`](#implementation)**
- **[`sassOptions`](#sassoptions)**
- **[`sourceMap`](#sourcemap)**
- **[`additionalData`](#additionaldata)**
- **[`webpackImporter`](#webpackimporter)**
- **[`warnRuleAsWarning`](#warnruleaswarning)**
- **[`api`](#api)**

### `implementation`

Type:

```ts
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**

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

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

**package.json**

```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:

```js
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`

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

```js
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:

```ts
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](http://sass-lang.com/dart-sass) or [Sass Embedded](https://github.com/sass/embedded-host-node) 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:

- [Dart Sass documentation](https://sass-lang.com/documentation/js-api/interfaces/Options) for all available `sass` options.
- [Sass Embedded documentation](https://github.com/sass/embedded-host-node) for all available `sass-embedded` options.

#### `object`

Use an object for the Sass implementation setup.

**webpack.config.js**

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

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

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

### `sourceMap`

Type:

```ts
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`](https://webpack.js.org/configuration/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**

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

**webpack.config.js**

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

### `additionalData`

Type:

```ts
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`

```js
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

```js
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.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

```js
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`

Type:

```ts
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](https://sass-lang.com/documentation/js-api/interfaces/LegacyImporter)).

**webpack.config.js**

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

### `warnRuleAsWarning`

Type:

```ts
type warnRuleAsWarning = boolean;
```

Default: `true`

Treats the `@warn` rule as a webpack warning.

**style.scss**

```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](https://webpack.js.org/configuration/other-options/#ignorewarnings) option.

**webpack.config.js**

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

### `api`

Type:

```ts
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](https://sass-lang.com/documentation/js-api). The `modern-compiler` option enables the modern API with support for [Shared Resources](https://github.com/sass/sass/blob/main/accepted/shared-resources.d.ts.md).

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](https://sass-lang.com/documentation/js-api) to learn how to migrate.

**webpack.config.js**

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

## How to enable `@debug` output

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

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

## Examples

### Extracts CSS into separate files

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

There are four recommended ways to extract a stylesheet from a bundle:

#### 1. [mini-css-extract-plugin](https://github.com/webpack/mini-css-extract-plugin)

**webpack.config.js**

```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](https://webpack.js.org/guides/asset-modules/)

**webpack.config.js**

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

#### 3. [extract-loader](https://github.com/peerigon/extract-loader) (simpler, but specialized on the css-loader's output)

#### 4. [file-loader](https://github.com/webpack-contrib/file-loader) (deprecated--should only be used in webpack v4)

**webpack.config.js**

```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/,
        use: [
          {
            loader: "file-loader",
            options: { outputPath: "css/", name: "[name].min.css" },
          },
          "sass-loader",
        ],
      },
    ],
  },
};
```

(source: https://stackoverflow.com/a/60029923/2969615)

### Source maps

Enables/disables generation of source maps.

To enable CSS source maps, you'll need to pass the `sourceMap` option to both the `sass-loader` _and_ the `css-loader`.

**webpack.config.js**

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

If you want to edit the original Sass files inside Chrome, [there's a good blog post](https://medium.com/@toolmantim/getting-started-with-css-sourcemaps-and-in-browser-sass-editing-b4daab987fb0).
Checkout [test/sourceMap](https://github.com/webpack/sass-loader/tree/main/test) 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](https://github.com/webpack/sass-loader?tab=contributing-ov-file#contributing)

## License

[MIT](./LICENSE)

[npm]: https://img.shields.io/npm/v/sass-loader.svg
[npm-url]: https://npmjs.com/package/sass-loader
[node]: https://img.shields.io/node/v/sass-loader.svg
[node-url]: https://nodejs.org
[tests]: https://github.com/webpack/sass-loader/workflows/sass-loader/badge.svg
[tests-url]: https://github.com/webpack/sass-loader/actions
[cover]: https://codecov.io/gh/webpack/sass-loader/branch/main/graph/badge.svg
[cover-url]: https://codecov.io/gh/webpack/sass-loader
[discussion]: https://img.shields.io/github/discussions/webpack/webpack
[discussion-url]: https://github.com/webpack/webpack/discussions
[size]: https://packagephobia.now.sh/badge?p=sass-loader
[size-url]: https://packagephobia.now.sh/result?p=sass-loader
[discord-invite]: https://img.shields.io/discord/1180618526436888586?style=flat&logo=discord&logoColor=white&label=discord
[discord-url]: https://discord.gg/ARKBCXBu
