UNPKG

22.5 kBMarkdownView Raw
1<div align="center">
2 <img height="170"
3 src="https://worldvectorlogo.com/logos/sass-1.svg">
4 <a href="https://github.com/webpack/webpack">
5 <img width="200" height="200"
6 src="https://webpack.js.org/assets/icon-square-big.svg">
7 </a>
8</div>
9
10[![npm][npm]][npm-url]
11[![node][node]][node-url]
12[![tests][tests]][tests-url]
13[![coverage][cover]][cover-url]
14[![chat][chat]][chat-url]
15[![size][size]][size-url]
16
17# sass-loader
18
19Loads a Sass/SCSS file and compiles it to CSS.
20
21## Getting Started
22
23To begin, you'll need to install `sass-loader`:
24
25```console
26npm install sass-loader sass webpack --save-dev
27```
28
29or
30
31```console
32yarn add -D sass-loader sass webpack
33```
34
35or
36
37```console
38pnpm add -D sass-loader sass webpack
39```
40
41`sass-loader` requires you to install either [Dart Sass](https://github.com/sass/dart-sass), [Node Sass](https://github.com/sass/node-sass) on your own (more documentation can be found below) or [Sass Embedded](https://github.com/sass/embedded-host-node).
42
43This allows you to control the versions of all your dependencies, and to choose which Sass implementation to use.
44
45> **Note**
46>
47> We highly recommend using [Dart Sass](https://github.com/sass/dart-sass).
48
49> **Warning**
50>
51> [Node Sass](https://github.com/sass/node-sass) does not work with [Yarn PnP](https://classic.yarnpkg.com/en/docs/pnp/) feature and doesn't support [@use rule](https://sass-lang.com/documentation/at-rules/use).
52
53> **Warning**
54>
55> [Sass Embedded](https://github.com/sass/embedded-host-node) is experimental and in `beta`, therefore some features may not work
56
57Chain the `sass-loader` with the [css-loader](https://github.com/webpack-contrib/css-loader) and the [style-loader](https://github.com/webpack-contrib/style-loader) to immediately apply all styles to the DOM or the [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin) to extract it into a separate file.
58
59Then add the loader to your Webpack configuration. For example:
60
61**app.js**
62
63```js
64import "./style.scss";
65```
66
67**style.scss**
68
69```scss
70$body-color: red;
71
72body {
73 color: $body-color;
74}
75```
76
77**webpack.config.js**
78
79```js
80module.exports = {
81 module: {
82 rules: [
83 {
84 test: /\.s[ac]ss$/i,
85 use: [
86 // Creates `style` nodes from JS strings
87 "style-loader",
88 // Translates CSS into CommonJS
89 "css-loader",
90 // Compiles Sass to CSS
91 "sass-loader",
92 ],
93 },
94 ],
95 },
96};
97```
98
99Finally run `webpack` via your preferred method.
100
101### Resolving `import` at-rules
102
103Webpack provides an [advanced mechanism to resolve files](https://webpack.js.org/concepts/module-resolution/).
104
105The `sass-loader` uses Sass's custom importer feature to pass all queries to the Webpack resolving engine.
106Thus you can import your Sass modules from `node_modules`.
107
108```scss
109@import "bootstrap";
110```
111
112Using `~` is deprecated and can be removed from your code (**we recommend it**), but we still support it for historical reasons.
113Why 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).
114
115Prepending module paths with a `~` tells webpack to search through [`node_modules`](https://webpack.js.org/configuration/resolve/#resolvemodules).
116
117```scss
118@import "~bootstrap";
119```
120
121It's important to prepend it with only `~`, because `~/` resolves to the home directory.
122Webpack needs to distinguish between `bootstrap` and `~bootstrap` because CSS and Sass files have no special syntax for importing relative files.
123Writing `@import "style.scss"` is the same as `@import "./style.scss";`
124
125### Problems with `url(...)`
126
127Since Sass implementations don't provide [url rewriting](https://github.com/sass/libsass/issues/532), all linked assets must be relative to the output.
128
129- If you pass the generated CSS on to the `css-loader`, all urls must be relative to the entry-file (e.g. `main.scss`).
130- If you're just generating CSS without passing it to the `css-loader`, it must be relative to your web root.
131
132You will be disrupted by this first issue. 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).
133
134Thankfully there are a two solutions to this problem:
135
136- 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.
137- 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`.
138
139## Options
140
141- **[`implementation`](#implementation)**
142- **[`sassOptions`](#sassoptions)**
143- **[`sourceMap`](#sourcemap)**
144- **[`additionalData`](#additionaldata)**
145- **[`webpackImporter`](#webpackimporter)**
146- **[`warnRuleAsWarning`](#warnruleaswarning)**
147
148### `implementation`
149
150Type:
151
152```ts
153type implementation = object | string;
154```
155
156Default: `sass`
157
158The special `implementation` option determines which implementation of Sass to use.
159
160By default the loader resolve the implementation based on your dependencies.
161Just add required implementation to `package.json` (`sass` or `node-sass` package) and install dependencies.
162
163Example where the `sass-loader` loader uses the `sass` (`dart-sass`) implementation:
164
165**package.json**
166
167```json
168{
169 "devDependencies": {
170 "sass-loader": "^7.2.0",
171 "sass": "^1.22.10"
172 }
173}
174```
175
176Example where the `sass-loader` loader uses the `node-sass` implementation:
177
178**package.json**
179
180```json
181{
182 "devDependencies": {
183 "sass-loader": "^7.2.0",
184 "node-sass": "^5.0.0"
185 }
186}
187```
188
189Beware the situation when `node-sass` and `sass` were installed! By default the `sass-loader` prefers `sass`.
190In order to avoid this situation you can use the `implementation` option.
191
192The `implementation` options either accepts `sass` (`Dart Sass`) or `node-sass` as a module.
193
194#### `object`
195
196For example, to use Dart Sass, you'd pass:
197
198```js
199module.exports = {
200 module: {
201 rules: [
202 {
203 test: /\.s[ac]ss$/i,
204 use: [
205 "style-loader",
206 "css-loader",
207 {
208 loader: "sass-loader",
209 options: {
210 // Prefer `dart-sass`
211 implementation: require("sass"),
212 },
213 },
214 ],
215 },
216 ],
217 },
218};
219```
220
221#### `string`
222
223For example, to use Dart Sass, you'd pass:
224
225```js
226module.exports = {
227 module: {
228 rules: [
229 {
230 test: /\.s[ac]ss$/i,
231 use: [
232 "style-loader",
233 "css-loader",
234 {
235 loader: "sass-loader",
236 options: {
237 // Prefer `dart-sass`
238 implementation: require.resolve("sass"),
239 },
240 },
241 ],
242 },
243 ],
244 },
245};
246```
247
248Note that when using `sass` (`Dart Sass`), **synchronous compilation is twice as fast as asynchronous compilation** by default, due to the overhead of asynchronous callbacks.
249To avoid this overhead, you can use the [fibers](https://www.npmjs.com/package/fibers) package to call asynchronous importers from the synchronous code path.
250
251We automatically inject the [`fibers`](https://github.com/laverdet/node-fibers) package (setup `sassOptions.fiber`) for `Node.js` less v16.0.0 if is possible (i.e. you need install the [`fibers`](https://github.com/laverdet/node-fibers) package).
252
253> **Warning**
254>
255> Fibers is not compatible with `Node.js` v16.0.0 or later. Unfortunately, v8 commit [dacc2fee0f](https://github.com/v8/v8/commit/dacc2fee0f815823782a7e432c79c2a7767a4765) is a breaking change and workarounds are non-trivial. ([see introduction to readme](https://github.com/laverdet/node-fibers)).
256
257**package.json**
258
259```json
260{
261 "devDependencies": {
262 "sass-loader": "^7.2.0",
263 "sass": "^1.22.10",
264 "fibers": "^4.0.1"
265 }
266}
267```
268
269You can disable automatically injecting the [`fibers`](https://github.com/laverdet/node-fibers) package by passing a `false` value for the `sassOptions.fiber` option.
270
271**webpack.config.js**
272
273```js
274module.exports = {
275 module: {
276 rules: [
277 {
278 test: /\.s[ac]ss$/i,
279 use: [
280 "style-loader",
281 "css-loader",
282 {
283 loader: "sass-loader",
284 options: {
285 implementation: require("sass"),
286 sassOptions: {
287 fiber: false,
288 },
289 },
290 },
291 ],
292 },
293 ],
294 },
295};
296```
297
298You can also pass the `fiber` value using this code:
299
300**webpack.config.js**
301
302```js
303module.exports = {
304 module: {
305 rules: [
306 {
307 test: /\.s[ac]ss$/i,
308 use: [
309 "style-loader",
310 "css-loader",
311 {
312 loader: "sass-loader",
313 options: {
314 implementation: require("sass"),
315 sassOptions: {
316 fiber: require("fibers"),
317 },
318 },
319 },
320 ],
321 },
322 ],
323 },
324};
325```
326
327### `sassOptions`
328
329Type:
330
331```ts
332type sassOptions =
333 | import("sass").LegacyOptions<"async">
334 | ((
335 content: string | Buffer,
336 loaderContext: LoaderContext,
337 meta: any
338 ) => import("sass").LegacyOptions<"async">);
339```
340
341Default: defaults values for Sass implementation
342
343Options for [Dart Sass](http://sass-lang.com/dart-sass) or [Node Sass](https://github.com/sass/node-sass) implementation.
344
345> **Note**
346>
347> The `charset` option has `true` value by default for `dart-sass`, we strongly discourage change value to `false`, because webpack doesn't support files other than `utf-8`.
348
349> **Note**
350>
351> The `indentedSyntax` option has `true` value for the `sass` extension.
352
353> **Note**
354>
355> Options such as `data` and `file` are unavailable and will be ignored.
356
357> ℹ We strongly discourage change `outFile`, `sourceMapContents`, `sourceMapEmbed`, `sourceMapRoot` options because `sass-loader` automatically sets these options when the `sourceMap` option is `true`.
358
359> **Note**
360>
361> Access to the [loader context](https://webpack.js.org/api/loaders/#the-loader-context) inside the custom importer can be done using the `this.webpackLoaderContext` property.
362
363There is a slight difference between the `sass` (`dart-sass`) and `node-sass` options.
364
365Please consult documentation before using them:
366
367- [Dart Sass documentation](https://sass-lang.com/documentation/js-api/interfaces/Options) for all available `sass` options.
368- [Node Sass documentation](https://github.com/sass/node-sass/#options) for all available `node-sass` options.
369
370#### `object`
371
372Use an object for the Sass implementation setup.
373
374**webpack.config.js**
375
376```js
377module.exports = {
378 module: {
379 rules: [
380 {
381 test: /\.s[ac]ss$/i,
382 use: [
383 "style-loader",
384 "css-loader",
385 {
386 loader: "sass-loader",
387 options: {
388 sassOptions: {
389 indentWidth: 4,
390 includePaths: ["absolute/path/a", "absolute/path/b"],
391 },
392 },
393 },
394 ],
395 },
396 ],
397 },
398};
399```
400
401#### `function`
402
403Allows to setup the Sass implementation by setting different options based on the loader context.
404
405```js
406module.exports = {
407 module: {
408 rules: [
409 {
410 test: /\.s[ac]ss$/i,
411 use: [
412 "style-loader",
413 "css-loader",
414 {
415 loader: "sass-loader",
416 options: {
417 sassOptions: (loaderContext) => {
418 // More information about available properties https://webpack.js.org/api/loaders/
419 const { resourcePath, rootContext } = loaderContext;
420 const relativePath = path.relative(rootContext, resourcePath);
421
422 if (relativePath === "styles/foo.scss") {
423 return {
424 includePaths: ["absolute/path/c", "absolute/path/d"],
425 };
426 }
427
428 return {
429 includePaths: ["absolute/path/a", "absolute/path/b"],
430 };
431 },
432 },
433 },
434 ],
435 },
436 ],
437 },
438};
439```
440
441### `sourceMap`
442
443Type:
444
445```ts
446type sourceMap = boolean;
447```
448
449Default: depends on the `compiler.devtool` value
450
451Enables/Disables generation of source maps.
452
453By default generation of source maps depends on the [`devtool`](https://webpack.js.org/configuration/devtool/) option.
454All values enable source map generation except `eval` and `false` value.
455
456> ℹ If a `true` the `sourceMap`, `sourceMapRoot`, `sourceMapEmbed`, `sourceMapContents` and `omitSourceMapUrl` from `sassOptions` will be ignored.
457
458**webpack.config.js**
459
460```js
461module.exports = {
462 module: {
463 rules: [
464 {
465 test: /\.s[ac]ss$/i,
466 use: [
467 "style-loader",
468 {
469 loader: "css-loader",
470 options: {
471 sourceMap: true,
472 },
473 },
474 {
475 loader: "sass-loader",
476 options: {
477 sourceMap: true,
478 },
479 },
480 ],
481 },
482 ],
483 },
484};
485```
486
487> ℹ In some rare cases `node-sass` can output invalid source maps (it is a `node-sass` bug).
488
489> > In order to avoid this, you can try to update `node-sass` to latest version or you can try to set within `sassOptions` the `outputStyle` option to `compressed`.
490
491**webpack.config.js**
492
493```js
494module.exports = {
495 module: {
496 rules: [
497 {
498 test: /\.s[ac]ss$/i,
499 use: [
500 "style-loader",
501 "css-loader",
502 {
503 loader: "sass-loader",
504 options: {
505 sourceMap: true,
506 sassOptions: {
507 outputStyle: "compressed",
508 },
509 },
510 },
511 ],
512 },
513 ],
514 },
515};
516```
517
518### `additionalData`
519
520Type:
521
522```ts
523type additionalData =
524 | string
525 | ((content: string | Buffer, loaderContext: LoaderContext) => string);
526```
527
528Default: `undefined`
529
530Prepends `Sass`/`SCSS` code before the actual entry file.
531In this case, the `sass-loader` will not override the `data` option but just **prepend** the entry's content.
532
533This is especially useful when some of your Sass variables depend on the environment:
534
535#### `string`
536
537```js
538module.exports = {
539 module: {
540 rules: [
541 {
542 test: /\.s[ac]ss$/i,
543 use: [
544 "style-loader",
545 "css-loader",
546 {
547 loader: "sass-loader",
548 options: {
549 additionalData: "$env: " + process.env.NODE_ENV + ";",
550 },
551 },
552 ],
553 },
554 ],
555 },
556};
557```
558
559#### `function`
560
561##### Sync
562
563```js
564module.exports = {
565 module: {
566 rules: [
567 {
568 test: /\.s[ac]ss$/i,
569 use: [
570 "style-loader",
571 "css-loader",
572 {
573 loader: "sass-loader",
574 options: {
575 additionalData: (content, loaderContext) => {
576 // More information about available properties https://webpack.js.org/api/loaders/
577 const { resourcePath, rootContext } = loaderContext;
578 const relativePath = path.relative(rootContext, resourcePath);
579
580 if (relativePath === "styles/foo.scss") {
581 return "$value: 100px;" + content;
582 }
583
584 return "$value: 200px;" + content;
585 },
586 },
587 },
588 ],
589 },
590 ],
591 },
592};
593```
594
595##### Async
596
597```js
598module.exports = {
599 module: {
600 rules: [
601 {
602 test: /\.s[ac]ss$/i,
603 use: [
604 "style-loader",
605 "css-loader",
606 {
607 loader: "sass-loader",
608 options: {
609 additionalData: async (content, loaderContext) => {
610 // More information about available properties https://webpack.js.org/api/loaders/
611 const { resourcePath, rootContext } = loaderContext;
612 const relativePath = path.relative(rootContext, resourcePath);
613
614 if (relativePath === "styles/foo.scss") {
615 return "$value: 100px;" + content;
616 }
617
618 return "$value: 200px;" + content;
619 },
620 },
621 },
622 ],
623 },
624 ],
625 },
626};
627```
628
629### `webpackImporter`
630
631Type:
632
633```ts
634type webpackImporter = boolean;
635```
636
637Default: `true`
638
639Enables/Disables the default Webpack importer.
640
641This can improve performance in some cases. Use it with caution because aliases and `@import` at-rules starting with `~` will not work.
642You can pass own `importer` to solve this (see [`importer docs`](https://github.com/sass/node-sass#importer--v200---experimental)).
643
644**webpack.config.js**
645
646```js
647module.exports = {
648 module: {
649 rules: [
650 {
651 test: /\.s[ac]ss$/i,
652 use: [
653 "style-loader",
654 "css-loader",
655 {
656 loader: "sass-loader",
657 options: {
658 webpackImporter: false,
659 },
660 },
661 ],
662 },
663 ],
664 },
665};
666```
667
668### `warnRuleAsWarning`
669
670Type:
671
672```ts
673type warnRuleAsWarning = boolean;
674```
675
676Default: `false`
677
678Treats the `@warn` rule as a webpack warning.
679
680> **Note**
681>
682> It will be `true` by default in the next major release.
683
684**style.scss**
685
686```scss
687$known-prefixes: webkit, moz, ms, o;
688
689@mixin prefix($property, $value, $prefixes) {
690 @each $prefix in $prefixes {
691 @if not index($known-prefixes, $prefix) {
692 @warn "Unknown prefix #{$prefix}.";
693 }
694
695 -#{$prefix}-#{$property}: $value;
696 }
697 #{$property}: $value;
698}
699
700.tilt {
701 // Oops, we typo'd "webkit" as "wekbit"!
702 @include prefix(transform, rotate(15deg), wekbit ms);
703}
704```
705
706The presented code will throw webpack warning instead logging.
707
708To ignore unnecessary warnings you can use the [ignoreWarnings](https://webpack.js.org/configuration/other-options/#ignorewarnings) option.
709
710**webpack.config.js**
711
712```js
713module.exports = {
714 module: {
715 rules: [
716 {
717 test: /\.s[ac]ss$/i,
718 use: [
719 "style-loader",
720 "css-loader",
721 {
722 loader: "sass-loader",
723 options: {
724 warnRuleAsWarning: true,
725 },
726 },
727 ],
728 },
729 ],
730 },
731};
732```
733
734### `api`
735
736Type:
737
738```ts
739type api = "legacy" | "modern";
740```
741
742Default: `"legacy"`
743
744Allows you to switch between `legacy` and `modern` API. You can find more information [here](https://sass-lang.com/documentation/js-api).
745
746> **Warning**
747>
748> "modern" API is experimental, so some features may not work (known: built-in `importer` is not working and files with errors is not watching on initial run), you can follow this [here](https://github.com/webpack-contrib/sass-loader/issues/774).
749
750> **Warning**
751>
752> The sass options are different for `modern` and `old` APIs. Please look at [docs](https://sass-lang.com/documentation/js-api) how to migrate on new options.
753
754**webpack.config.js**
755
756```js
757module.exports = {
758 module: {
759 rules: [
760 {
761 test: /\.s[ac]ss$/i,
762 use: [
763 "style-loader",
764 "css-loader",
765 {
766 loader: "sass-loader",
767 options: {
768 api: "modern",
769 sassOptions: {
770 // Your sass options
771 },
772 },
773 },
774 ],
775 },
776 ],
777 },
778};
779```
780
781## How to enable `@debug` output
782
783Defaults, the output of `@debug` messages is disabled.
784To enable it, add to **webpack.config.js** following:
785
786```js
787module.exports = {
788 stats: {
789 loggingDebug: ["sass-loader"],
790 },
791 // ...
792};
793```
794
795## Examples
796
797### Extracts CSS into separate files
798
799For production builds it's recommended to extract the CSS from your bundle being able to use parallel loading of CSS/JS resources later on.
800
801There are two possibilities to extract a style sheet from the bundle:
802
803- [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin)
804- [extract-loader](https://github.com/peerigon/extract-loader) (simpler, but specialized on the css-loader's output)
805
806**webpack.config.js**
807
808```js
809const MiniCssExtractPlugin = require("mini-css-extract-plugin");
810
811module.exports = {
812 module: {
813 rules: [
814 {
815 test: /\.s[ac]ss$/i,
816 use: [
817 // fallback to style-loader in development
818 process.env.NODE_ENV !== "production"
819 ? "style-loader"
820 : MiniCssExtractPlugin.loader,
821 "css-loader",
822 "sass-loader",
823 ],
824 },
825 ],
826 },
827 plugins: [
828 new MiniCssExtractPlugin({
829 // Options similar to the same options in webpackOptions.output
830 // both options are optional
831 filename: "[name].css",
832 chunkFilename: "[id].css",
833 }),
834 ],
835};
836```
837
838### Source maps
839
840Enables/Disables generation of source maps.
841
842To enable CSS source maps, you'll need to pass the `sourceMap` option to the `sass-loader` _and_ the css-loader.
843
844**webpack.config.js**
845
846```javascript
847module.exports = {
848 devtool: "source-map", // any "source-map"-like devtool is possible
849 module: {
850 rules: [
851 {
852 test: /\.s[ac]ss$/i,
853 use: [
854 "style-loader",
855 {
856 loader: "css-loader",
857 options: {
858 sourceMap: true,
859 },
860 },
861 {
862 loader: "sass-loader",
863 options: {
864 sourceMap: true,
865 },
866 },
867 ],
868 },
869 ],
870 },
871};
872```
873
874If 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-contrib/sass-loader/tree/master/test) for a running example.
875
876## Contributing
877
878Please take a moment to read our contributing guidelines if you haven't yet done so.
879
880[CONTRIBUTING](./.github/CONTRIBUTING.md)
881
882## License
883
884[MIT](./LICENSE)
885
886[npm]: https://img.shields.io/npm/v/sass-loader.svg
887[npm-url]: https://npmjs.com/package/sass-loader
888[node]: https://img.shields.io/node/v/sass-loader.svg
889[node-url]: https://nodejs.org
890[tests]: https://github.com/webpack-contrib/sass-loader/workflows/sass-loader/badge.svg
891[tests-url]: https://github.com/webpack-contrib/sass-loader/actions
892[cover]: https://codecov.io/gh/webpack-contrib/sass-loader/branch/master/graph/badge.svg
893[cover-url]: https://codecov.io/gh/webpack-contrib/sass-loader
894[chat]: https://badges.gitter.im/webpack/webpack.svg
895[chat-url]: https://gitter.im/webpack/webpack
896[size]: https://packagephobia.now.sh/badge?p=sass-loader
897[size-url]: https://packagephobia.now.sh/result?p=sass-loader