sfcode An Online Competing and Development Environment

README

# 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

`sass-loader` requires you to install either Dart Sass or Node Sass 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.

> ℹ️ We recommend using Dart Sass.

> ⚠ Node Sass does not work with Yarn PnP feature.

Chain the `sass-loader` with the css-loader and the style-loader to immediately apply all styles to the DOM or the 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,
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.

### Resolving <tt>import</tt> at-rules

Webpack provides an advanced mechanism to resolve files.

The `sass-loader` uses Sass's custom importer feature to pass all queries to the Webpack resolving engine. Thus you can import your Sass modules from `node_modules`. Just prepend them with a `~` to tell Webpack that this is not a relative import:

@import '~bootstrap';

It's important to only prepend it with `~`, 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 <tt>url(...)</tt>

Since Sass implementations don't provide url rewriting, 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`, it must be relative to your web root.

You 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).

Thankfully there are a 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

Name | Type | Default | Description
--- | --- | --- | ---
**`implementation`** | `{Object}` | `sass` | Setup Sass implementation to use.
**`sassOptions`** | `{Object\|Function}` | defaults values for Sass implementation | Options for Sass.
**`sourceMap`** | `{Boolean}` | `compiler.devtool` | Enables/Disables generation of source maps.
**`additionalData`** | `{String\|Function}` | `undefined` | Prepends/Appends `Sass`/`SCSS` code before the actual entry file.
**`webpackImporter`** | `{Boolean}` | `true` | Enables/Disables the default Webpack importer.

### <tt>implementation</tt>

Type: `Object` Default: `sass`

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

By default the loader resolve the implementation based on your dependencies. Just add required implementation to `package.json` (`sass` or `node-sass` package) and install dependencies.

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

package.json

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

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

package.json

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

Beware the situation when `node-sass` and `sass` were installed! By default the `sass-loader` prefers `sass`. In order to avoid this situation you can use the `implementation` option.

The `implementation` options either accepts `sass` (`Dart Sass`) or `node-sass` as a module.

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

module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
// Prefer `dart-sass`
implementation: require('sass'),
},
},
],
},
],
},
};

Note that when using `sass` (`Dart Sass`), synchronous compilation is twice as fast as asynchronous compilation by default, due to the overhead of asynchronous callbacks. To avoid this overhead, you can use the fibers package to call asynchronous importers from the synchronous code path.

We automatically inject the `fibers` package (setup `sassOptions.fiber`) if is possible (i.e. you need install the `fibers` package).

package.json

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

You can disable automatically injecting the `fibers` package by passing a `false` value for the `sassOptions.fiber` option.

webpack.config.js

module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
implementation: require('sass'),
sassOptions: {
fiber: false,
},
},
},
],
},
],
},
};

You can also pass the `fiber` value using this code:

webpack.config.js

module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
implementation: require('sass'),
sassOptions: {
fiber: require('fibers'),
},
},
},
],
},
],
},
};

### <tt>sassOptions</tt>

Type: `Object|Function` Default: defaults values for Sass implementation

Options for Dart Sass or Node Sass implementation.

> ℹ️ The `indentedSyntax` option has `true` value for the `sass` extension.

> ℹ️ Options such as `data` and `file` are unavailable and will be ignored.

> ℹ We recommend not to set the `outFile`, `sourceMapContents`, `sourceMapEmbed`, `sourceMapRoot` options because `sass-loader` automatically sets these options when the `sourceMap` option is `true`.

> ℹ️ Access to the loader context inside the custom importer can be done using the `this.webpackLoaderContext` property.

There is a slight difference between the `sass` (`dart-sass`) and `node-sass` options.

Please consult documentation before using them:

- Dart Sass documentation for all available `sass` options.
- Node Sass documentation for all available `node-sass` options.

#### <tt>Object</tt>

Use and object for the Sass implementation setup.

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

#### <tt>Function</tt>

Allows to setup the Sass implementation by setting different options based on the loader context.

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 {
includePaths: ['absolute/path/c', 'absolute/path/d'],
};
}
return {
includePaths: ['absolute/path/a', 'absolute/path/b'],
};
},
},
},
],
},
],
},
};

### <tt>sourceMap</tt>

Type: `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` value.

> ℹ If a `true` the `sourceMap`, `sourceMapRoot`, `sourceMapEmbed`, `sourceMapContents` and `omitSourceMapUrl` from `sassOptions` will be ignored.

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

> ℹ In some rare cases `node-sass` can output invalid source maps (it is a `node-sass` bug).

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

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

### <tt>additionalData</tt>

Type: `String|Function` 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:

#### <tt>String</tt>

module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
additionalData: '$env: ' + process.env.NODE_ENV + ';',
},
},
],
},
],
},
};

#### <tt>Function</tt>

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

### <tt>webpackImporter</tt>

Type: `Boolean` Default: `true`

Enables/Disables the default Webpack importer.

This can improve performance in some cases. Use it with caution because aliases and `@import` at-rules starting with `~` will not work. You can pass own `importer` to solve this (see `importer docs`).

webpack.config.js

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

## Examples

### Extracts CSS into separate files

For production builds it's recommended to extract the CSS from your bundle being able to use parallel loading of CSS/JS resources later on.

There are two possibilities to extract a style sheet from the bundle:

- mini-css-extract-plugin (use this, when using webpack 4 configuration. Works in all use-cases)
- extract-loader (simpler, but specialized on the css-loader's output)

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

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

## Contributing

Please take a moment to read our contributing guidelines if you haven't yet done so.

./.github/CONTRIBUTING.md "CONTRIBUTING"

## License

MIT