Printable

babel-loader

This README is for babel-loader v8/v9/v10 with Babel v7 If you are using legacy Babel v6, see the 7.x branch docs

NPM Status codecov

This package allows transpiling JavaScript files using Babel together with webpack or Rspack.

Note: Issues with the output should be reported on the Babel Issues tracker.

Install

babel-loadersupported webpack versionssupported Babel versionssupported Node.js versions
8.x4.x or 5.x7.x>= 8.9
9.x5.x^7.12.0>= 14.15.0
10.x^5.61.0^7.12.0 || ^8.0.0-alpha^18.20.0 || ^20.10.0 || >=22.0.0`
npm install -D babel-loader @babel/core @babel/preset-env webpack

Usage

webpack documentation: Loaders

Within your webpack configuration object, you'll need to add the babel-loader to the list of modules, like so:

module: {
  rules: [
    {
      test: /\.(?:js|mjs|cjs)$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          targets: "defaults",
          presets: [
            ['@babel/preset-env']
          ]
        }
      }
    }
  ]
}

Options

See the babel options.

You can pass options to the loader by using the options property:

module: {
  rules: [
    {
      test: /\.(?:js|mjs|cjs)$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          targets: "defaults",
          presets: [
            ['@babel/preset-env']
          ],
          plugins: ['@babel/plugin-proposal-decorators', { version: "2023-11" }]
        }
      }
    }
  ]
}

The options passed here will be merged with Babel config files, e.g. babel.config.js or .babelrc.

This loader also supports the following loader-specific option:

  • cacheDirectory: Default false. When set, the given directory will be used to cache the results of the loader. Future webpack builds will attempt to read from the cache to avoid needing to run the potentially expensive Babel recompilation process on each run. If the value is set to true in options ({cacheDirectory: true}), the loader will use the default cache directory in node_modules/.cache/babel-loader or fallback to the default OS temporary file directory if no node_modules folder could be found in any root directory.

  • cacheIdentifier: Default is a string composed by the @babel/core's version and the babel-loader's version. The final cache id will be determined by the input file path, the merged Babel config via Babel.loadPartialConfigAsync and the cacheIdentifier. The merged Babel config will be determined by the babel.config.js or .babelrc file if they exist, or the value of the environment variable BABEL_ENV and NODE_ENV. cacheIdentifier can be set to a custom value to force cache busting if the identifier changes.

  • cacheCompression: Default true. When set, each Babel transform output will be compressed with Gzip. If you want to opt-out of cache compression, set it to false -- your project may benefit from this if it transpiles thousands of files.

  • customize: Default null. The path of a module that exports a custom callback like the one that you'd pass to .custom(). Since you already have to make a new file to use this, it is recommended that you instead use .custom to create a wrapper loader. Only use this if you must continue using babel-loader directly, but still want to customize.

  • metadataSubscribers: Default []. Takes an array of context function names. E.g. if you passed ['myMetadataPlugin'], you'd assign a subscriber function to context.myMetadataPlugin within your webpack plugin's hooks & that function will be called with metadata. See https://github.com/babel/babel-loader/blob/main/test/metadata.test.js for an example.

Troubleshooting

Enable debug mode logging

Specify the webpack option stats.loggingDebug to output verbose debug logs.

// webpack.config.js
module.exports = {
  // ...
  stats: {
    loggingDebug: ["babel-loader"]
  }
}

babel-loader is slow!

Make sure you are transforming as few files as possible. Because you are probably matching /\.m?js$/, you might be transforming the node_modules folder or other unwanted source.

To exclude node_modules, see the exclude option in the loaders config as documented above.

You can also speed up babel-loader by as much as 2x by using the cacheDirectory option. This will cache transformations to the filesystem.

Some files in my node_modules are not transpiled for IE 11

Although we typically recommend not compiling node_modules, you may need to when using libraries that do not support IE 11 or any legacy targets.

For this, you can either use a combination of test and not, or pass a function to your exclude option. You can also use negative lookahead regex as suggested here.

{
    test: /\.(?:js|mjs|cjs)$/,
    exclude: {
      and: [/node_modules/], // Exclude libraries in node_modules ...
      not: [
        // Except for a few of them that needs to be transpiled because they use modern syntax
        /unfetch/,
        /d3-array|d3-scale/,
        /@hapi[\\/]joi-date/,
      ]
    },
    use: {
      loader: 'babel-loader',
      options: {
        presets: [
          ['@babel/preset-env', { targets: "ie 11" }]
        ]
      }
    }
  }

Babel is injecting helpers into each file and bloating my code!

Babel uses very small helpers for common functions such as _extend. By default, this will be added to every file that requires it.

You can instead require the Babel runtime as a separate module to avoid the duplication.

The following configuration disables automatic per-file runtime injection in Babel, requiring @babel/plugin-transform-runtime instead and making all helper references use it.

See the docs for more information.

NOTE: You must run npm install -D @babel/plugin-transform-runtime to include this in your project and @babel/runtime itself as a dependency with npm install @babel/runtime.

rules: [
  // the 'transform-runtime' plugin tells Babel to
  // require the runtime instead of inlining it.
  {
    test: /\.(?:js|mjs|cjs)$/,
    exclude: /node_modules/,
    use: {
      loader: 'babel-loader',
      options: {
        presets: [
          ['@babel/preset-env', { targets: "defaults" }]
        ],
        plugins: ['@babel/plugin-transform-runtime']
      }
    }
  }
]

NOTE: transform-runtime & custom polyfills (e.g. Promise library)

Since @babel/plugin-transform-runtime includes a polyfill that includes a custom regenerator-runtime and core-js, the following usual shimming method using webpack.ProvidePlugin will not work:

// ...
        new webpack.ProvidePlugin({
            'Promise': 'bluebird'
        }),
// ...

The following approach will not work either:

require('@babel/runtime/core-js/promise').default = require('bluebird');

var promise = new Promise;

which outputs to (using runtime):

'use strict';

var _Promise = require('@babel/runtime/core-js/promise')['default'];

require('@babel/runtime/core-js/promise')['default'] = require('bluebird');

var promise = new _Promise();

The previous Promise library is referenced and used before it is overridden.

One approach is to have a "bootstrap" step in your application that would first override the default globals before your application:

// bootstrap.js

require('@babel/runtime/core-js/promise').default = require('bluebird');

// ...

require('./app');

The Node.js API for babel has been moved to babel-core.

If you receive this message, it means that you have the npm package babel installed and are using the short notation of the loader in the webpack config (which is not valid anymore as of webpack 2.x):

  {
    test: /\.(?:js|mjs|cjs)$/,
    loader: 'babel',
  }

webpack then tries to load the babel package instead of the babel-loader.

To fix this, you should uninstall the npm package babel, as it is deprecated in Babel v6. (Instead, install @babel/cli or @babel/core.) In the case one of your dependencies is installing babel and you cannot uninstall it yourself, use the complete name of the loader in the webpack config:

  {
    test: /\.(?:js|mjs|cjs)$/,
    loader: 'babel-loader',
  }

Exclude libraries that should not be transpiled

core-js and webpack/buildin will cause errors if they are transpiled by Babel.

You will need to exclude them form babel-loader.

{
  "loader": "babel-loader",
  "options": {
    "exclude": [
      // \\ for Windows, / for macOS and Linux
      /node_modules[\\/]core-js/,
      /node_modules[\\/]webpack[\\/]buildin/,
    ],
    "presets": [
      "@babel/preset-env"
    ]
  }
}

Top level function (IIFE) is still arrow (on Webpack 5)

That function is injected by Webpack itself after running babel-loader. By default Webpack asumes that your target environment supports some ES2015 features, but you can overwrite this behavior using the output.environment Webpack option (documentation).

To avoid the top-level arrow function, you can use output.environment.arrowFunction:

// webpack.config.js
module.exports = {
  // ...
  output: {
    // ...
    environment: {
      // ...
      arrowFunction: false, // <-- this line does the trick
    },
  },
};

Customize config based on webpack target

Webpack supports bundling multiple targets. For cases where you may want different Babel configurations for each target (like web and node), this loader provides a target property via Babel's caller API.

For example, to change the environment targets passed to @babel/preset-env based on the webpack target:

// babel.config.js

module.exports = api => {
  return {
    presets: [
      [
        "@babel/preset-env",
        {
          useBuiltIns: "entry",
          // caller.target will be the same as the target option from webpack
          targets: api.caller(caller => caller && caller.target === "node")
            ? { node: "current" }
            : { chrome: "58", ie: "11" }
        }
      ]
    ]
  }
}

Customized Loader

babel-loader exposes a loader-builder utility that allows users to add custom handling of Babel's configuration for each file that it processes.

.custom accepts a callback that will be called with the loader's instance of babel so that tooling can ensure that it using exactly the same @babel/core instance as the loader itself.

In cases where you want to customize without actually having a file to call .custom, you may also pass the customize option with a string pointing at a file that exports your custom callback function.

Example

// Export from "./my-custom-loader.js" or whatever you want.
module.exports = require("babel-loader").custom(babel => {
  // Extract the custom options in the custom plugin
  function myPlugin(api, { opt1, opt2 }) {
    return {
      visitor: {},
    };
  }

  return {
    // Passed the loader options.
    customOptions({ opt1, opt2, ...loader }) {
      return {
        // Pull out any custom options that the loader might have.
        custom: { opt1, opt2 },

        // Pass the options back with the two custom options removed.
        loader,
      };
    },

    // Passed Babel's 'PartialConfig' object.
    config(cfg, { customOptions }) {
      if (cfg.hasFilesystemConfig()) {
        // Use the normal config
        return cfg.options;
      }

      return {
        ...cfg.options,
        plugins: [
          ...(cfg.options.plugins || []),

          // Include a custom plugin in the options and passing it the customOptions object.
          [myPlugin, customOptions],
        ],
      };
    },

    result(result) {
      return {
        ...result,
        code: result.code + "\n// Generated by some custom loader",
      };
    },
  };
});
// And in your Webpack config
module.exports = {
  // ..
  module: {
    rules: [{
      // ...
      loader: path.join(__dirname, 'my-custom-loader.js'),
      // ...
    }]
  }
};

customOptions(options: Object): { custom: Object, loader: Object }

Given the loader's options, split custom options out of babel-loader's options.

config(cfg: PartialConfig, options: { source, customOptions }): Object

Given Babel's PartialConfig object, return the options object that should be passed to babel.transform.

result(result: Result): Result

Given Babel's result object, allow loaders to make additional tweaks to it.

License

MIT

coffee-loader

npm node tests coverage discussion size

Compile CoffeeScript to JavaScript.

Getting Started

To begin, you'll need to install coffeescript and coffee-loader:

npm install --save-dev coffeescript coffee-loader

or

yarn add -D coffeescript coffee-loader

or

pnpm add -D coffeescript coffee-loader

Then add the loader to your webpack.config.js. For example:

file.coffee

# Assignment:
number   = 42
opposite = true

# Conditions:
number = -42 if opposite

# Functions:
square = (x) -> x * x

# Arrays:
list = [1, 2, 3, 4, 5]

# Objects:
math =
  root:   Math.sqrt
  square: square
  cube:   (x) -> x * square x

# Splats:
race = (winner, runners...) ->
  print winner, runners

# Existence:
alert "I knew it!" if elvis?

# Array comprehensions:
cubes = (math.cube num for num in list)

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.coffee$/,
        loader: "coffee-loader",
      },
    ],
  },
};

Alternative usage:

import coffee from "coffee-loader!./file.coffee";

Finally, run webpack using the method you normally use (e.g., via CLI or an npm script).

Options

Type: Object Default: { bare: true }

You can find all available CoffeeScript options here.

For documentation on the transpile option, see this section.

[!NOTE]

The sourceMap option takes a value from the compiler.devtool value by default.

[!NOTE]

The filename option takes a value from webpack loader API, but it's value will be ignored.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.coffee$/,
        loader: "coffee-loader",
        options: {
          bare: false,
          transpile: {
            presets: ["@babel/env"],
          },
        },
      },
    ],
  },
};

Examples

CoffeeScript and Babel

From CoffeeScript 2 documentation:

[!NOTE]

CoffeeScript 2 generates JavaScript using the latest, modern syntax. The runtime or browsers where you want your code to run might not support all of that syntax. In that case, modern JavaScript needs to be converted into an older JavaScript that will run in older versions of Node or older browsers; for example: { a } = obj into a = obj.a. This conversion is done using transpilers like Babel, Bublé or Traceur Compiler.

You'll need to install @babel/core and @babel/preset-env and then create a configuration file:

npm install --save-dev @babel/core @babel/preset-env
echo '{ "presets": ["@babel/env"] }' > .babelrc

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.coffee$/,
        loader: "coffee-loader",
        options: {
          transpile: {
            presets: ["@babel/env"],
          },
        },
      },
    ],
  },
};

Literate CoffeeScript

To use Literate CoffeeScript you should setup:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.coffee$/,
        loader: "coffee-loader",
        options: {
          literate: true,
        },
      },
    ],
  },
};

Contributing

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

CONTRIBUTING

License

MIT

less-loader

npm node tests cover discussion size

A Less loader for webpack that compiles Less files into CSS.

Getting Started

To begin, you'll need to install less and less-loader:

npm install less less-loader --save-dev

or

yarn add -D less less-loader

or

pnpm add -D less less-loader

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

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        // Uses the built-in CSS support of webpack, i.e. `.module.less` files
        // are treated as CSS modules, other files are treated as plain CSS
        type: "css/auto",
        // Compiles Less to CSS
        use: ["less-loader"],
      },
    ],
  },
  experiments: {
    // Enables the built-in CSS support of webpack
    css: true,
  },
};

[!NOTE]

The built-in CSS support of webpack requires experiments.css to be enabled. Alternatively you can still chain the loader with css-loader and style-loader (or the mini-css-extract-plugin), see Using css-loader and style-loader.

Finally, run webpack using the method you normally use (e.g., via CLI or an npm script).

Options

lessOptions

Type:

type lessOptions = import('less').options | ((loaderContext: LoaderContext) => import('less').options})

Default: { relativeUrls: true }

You can pass any Less specific options to the less-loader through the lessOptions property in the loader options. See the Less documentation for all available options in dash-case.

Since we're passing these options to Less programmatically, you need to pass them in camelCase here:

object

Use an object to pass options directly to Less.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        type: "css/auto",
        use: [
          {
            loader: "less-loader",
            options: {
              lessOptions: {
                strictMath: true,
              },
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

function

Allows setting the Less options dynamically based on the loader context.

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        type: "css/auto",
        use: [
          {
            loader: "less-loader",
            options: {
              lessOptions: (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.less") {
                  return {
                    paths: ["absolute/path/c", "absolute/path/d"],
                  };
                }

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

additionalData

Type:

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

Default: undefined

Prepends or Appends Less code to the actual entry file. In this case, the less-loader will not override the source but just prepend the entry's content.

This is especially useful when some of your Less variables depend on the environment.

Since you're injecting code, this will break the source mappings in your entry file. Often there's a simpler solution than this, like multiple Less entry files.

string

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        type: "css/auto",
        use: [
          {
            loader: "less-loader",
            options: {
              additionalData: `@env: ${process.env.NODE_ENV};`,
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

function

Sync
module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        type: "css/auto",
        use: [
          {
            loader: "less-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.less") {
                  return `@value: 100px;${content}`;
                }

                return `@value: 200px;${content}`;
              },
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};
Async
module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        type: "css/auto",
        use: [
          {
            loader: "less-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.less") {
                  return `@value: 100px;${content}`;
                }

                return `@value: 200px;${content}`;
              },
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

sourceMap

Type:

type sourceMap = boolean;

Default: depends on the compiler.devtool value

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

webpack.config.js

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

webpackImporter

Type:

type webpackImporter = boolean | "only";

Default: true

Enables or disables the default webpack importer.

This can improve performance in some cases. Use it with caution because aliases and @import from node_modules will not work.

webpack.config.js

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

implementation

Type:

type implementation = object | string;

less-loader compatible with both Less 3 and 4 versions

The special implementation option determines which implementation of Less to use. Overrides the locally installed peerDependency version of less.

This option is only really useful for downstream tooling authors to ease the Less 3-to-4 transition.

object

Example using a Less instance:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        type: "css/auto",
        use: [
          {
            loader: "less-loader",
            options: {
              implementation: require("less"),
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

string

Example using a resolved Less module path:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        type: "css/auto",
        use: [
          {
            loader: "less-loader",
            options: {
              implementation: require.resolve("less"),
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

lessLogAsWarnOrErr

Type:

type lessLogAsWarnOrErr = boolean;

Default: true

Less warnings and errors will be treated as webpack warnings and errors, instead of being logged silently.

warning.less

div {
  &:extend(.body1);
}

If lessLogAsWarnOrErr is set to false it will be just a log and webpack will compile successfully, but if you leave the default value (or set this option to true) webpack will compile fail with a warning(or error), and can break the build if configured accordingly.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        type: "css/auto",
        use: [
          {
            loader: "less-loader",
            options: {
              lessLogAsWarnOrErr: true,
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

Examples

Normal usage

Set the module type to css/auto and enable experiments.css to let webpack handle the generated CSS with its built-in CSS support, without any extra loaders or plugins.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        type: "css/auto", // Handles the generated CSS using the built-in CSS support of webpack
        use: ["less-loader"], // Compiles Less to CSS
      },
    ],
  },
  experiments: {
    css: true,
  },
};

The css/auto module type treats *.module.less files as CSS modules and any other file as plain CSS. Use type: "css" to always treat the file as plain CSS, or type: "css/module" to always treat it as a CSS module.

Unfortunately, Less doesn't map all options 1-by-1 to camelCase. When in doubt, check their executable and search for the dash-case option.

Using css-loader and style-loader

The built-in CSS support of webpack is not mandatory, you can still chain the less-loader with css-loader and style-loader to immediately apply all styles to the DOM.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        use: [
          {
            loader: "style-loader", // Creates style nodes from JS strings
          },
          {
            loader: "css-loader", // Translates CSS into CommonJS
          },
          {
            loader: "less-loader", // Compiles Less to CSS
          },
        ],
      },
    ],
  },
};

Note that in this case the type and experiments.css options should not be set for this rule, and options like sourceMap have to be enabled for the css-loader too.

Source maps

To enable sourcemaps for CSS, you'll need to pass the sourceMap property in the loader's options. If this is not passed, the loader will respect the setting for webpack source maps, set in devtool.

webpack.config.js

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

If you want to edit the original Less files inside Chrome, there's a good blog post. The blog post is about Sass but it also works for Less.

In production

The built-in CSS support of webpack always extracts style sheets into dedicated files, so your styles are not dependent on JavaScript, which improves performance and cacheability. The name of the generated files can be configured using the output.cssFilename and output.cssChunkFilename options.

When you chain the loader with css-loader and style-loader instead, it's recommended to extract the style sheets into a dedicated file in production using the MiniCssExtractPlugin.

Imports

First we try to use built-in less resolve logic, then webpack resolve logic.

Webpack Resolver

webpack provides an advanced mechanism to resolve files. less-loader applies a Less plugin that passes all queries to the webpack resolver if less could not resolve @import. Thus you can import your Less modules from node_modules.

@import "bootstrap/less/bootstrap";

Using ~ prefix (e.g., @import "~bootstrap/less/bootstrap";) is deprecated and can be removed from your code (we recommend it), but we still support it for historical reasons. Why you can removed it? The loader will first try to resolve @import as relative, if it cannot be resolved, the loader will try to resolve @import inside node_modules.

Default resolver options can be modified by resolve.byDependency:

webpack.config.js

module.exports = {
  devtool: "source-map", // any "source-map"-like devtool is possible
  module: {
    rules: [
      {
        test: /\.less$/i,
        type: "css/auto",
        use: ["less-loader"],
      },
    ],
  },
  experiments: {
    css: true,
  },
  resolve: {
    byDependency: {
      // More options can be found here https://webpack.js.org/configuration/resolve/
      less: {
        mainFiles: ["custom"],
      },
    },
  },
};

Less Resolver

If you specify the paths option, modules will be searched in the given paths. This is less default behavior. paths should be an array with absolute paths:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        type: "css/auto",
        use: [
          {
            loader: "less-loader",
            options: {
              lessOptions: {
                paths: [path.resolve(__dirname, "node_modules")],
              },
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

Plugins

In order to use Less plugins, simply set the plugins option like this:

webpack.config.js

const CleanCSSPlugin = require('less-plugin-clean-css');

module.exports = {
  ...
    {
      loader: 'less-loader',
      options: {
        lessOptions: {
          plugins: [
            new CleanCSSPlugin({ advanced: true }),
          ],
        },
      },
    },
  ...
};

[!NOTE]

Access to the loader context inside a custom plugin can be done using the pluginManager.webpackLoaderContext property.

module.exports = {
  install(less, pluginManager, functions) {
    functions.add(
      "pi",
      () =>
        // Loader context is available in `pluginManager.webpackLoaderContext`

        Math.PI,
    );
  },
};

Extracting style sheets

Bundling CSS with webpack has some nice advantages like referencing images and fonts with hashed urls or Hot Module Replacement(HMR) in development.

In production, on the other hand, it's not a good idea to apply your style sheets depending on JS execution. Rendering may be delayed or even a FOUC might be visible. Thus it's often still better to have them as separate files in your final production build.

The built-in CSS support of webpack does this out of the box: every entry point and chunk gets its own style sheet, no extra plugin required. When you chain the loader with the css-loader instead, use the MiniCssExtractPlugin to extract a style sheet from the bundle.

CSS modules

With the built-in CSS support of webpack, *.module.less files are treated as CSS modules when the module type is css/auto, and all files are treated as CSS modules when the module type is css/module:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        type: "css/auto",
        use: ["less-loader"],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

index.js

import * as styles from "./style.module.less";

document.body.className = styles.box;

There is a known problem when using Less with CSS modules regarding relative file paths in url(...) statements. See this issue for an explanation.

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

postcss-loader

npm node tests coverage size

Webpack discussion: discussion

PostCSS chat: chat-postcss

A loader to process CSS using PostCSS.

Getting Started

You need webpack v5 to use the latest version. For Webpack v4, you have to install postcss-loader v4.

To begin, you'll need to install postcss-loader and postcss:

npm install --save-dev postcss-loader postcss

or

yarn add -D postcss-loader postcss

or

pnpm add -D postcss-loader postcss

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

In the following configuration the plugin postcss-preset-env is used, which is not installed by default.

The examples below use the built-in CSS support of webpack (available in webpack >= 5.87.0), so no css-loader and style-loader are required. If you prefer to handle CSS using css-loader and style-loader, keep them in the list of loaders and use postcss-loader before them.

file.js

import css from "file.css";

webpack.config.js

module.exports = {
  experiments: {
    // Enable the built-in CSS support of webpack
    css: true,
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        // `css/auto` treats `*.module.css` files as CSS modules and all other files as regular CSS
        type: "css/auto",
        use: [
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [
                  [
                    "postcss-preset-env",
                    {
                      // Options
                    },
                  ],
                ],
              },
            },
          },
        ],
      },
    ],
  },
};

Alternative use with config files:

postcss.config.js

module.exports = {
  plugins: [
    [
      "postcss-preset-env",
      {
        // Options
      },
    ],
  ],
};

The loader automatically searches for configuration files.

webpack.config.js

module.exports = {
  experiments: {
    css: true,
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        type: "css/auto",
        use: ["postcss-loader"],
      },
    ],
  },
};

Finally, run webpack using the method you normally use (e.g., via CLI or an npm script).

Options

execute

Type:

type execute = boolean;

Default: undefined

Enable PostCSS parser support for CSS-in-JS. If you use JS styles the postcss-js parser, add the execute option.

webpack.config.js

module.exports = {
  experiments: {
    css: true,
  },
  module: {
    rules: [
      {
        test: /\.style.js$/,
        type: "css/auto",
        use: [
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: { parser: "postcss-js" },
              execute: true,
            },
          },
        ],
      },
    ],
  },
};

postcssOptions

See the file https://github.com/webpack/postcss-loader/blob/main/src/config.d.ts.

Type:

import { type Config as PostCSSConfig } from "postcss-load-config";
import { type LoaderContext } from "webpack";

type PostCSSLoaderContext = LoaderContext<PostCSSConfig>;

interface PostCSSLoaderAPI {
  mode: PostCSSLoaderContext["mode"];
  file: PostCSSLoaderContext["resourcePath"];
  webpackLoaderContext: PostCSSLoaderContext;
  env: PostCSSLoaderContext["mode"];
  options: PostCSSConfig;
}

export type PostCSSLoaderOptions =
  | PostCSSConfig
  | ((api: PostCSSLoaderAPI) => PostCSSConfig);

Default: undefined

Allows you to set PostCSS options and plugins.

All PostCSS options are supported. There is the special config option for config files. How it works and how it can be configured is described below.

We recommend do not specify from, to and map options, because this can lead to wrong path in source maps. If you need source maps please use the sourcemap option instead.

For large projects, to optimize performance of the loader, it is better to provide postcssOptions in loader config and specify config: false. This approach removes the need to lookup and load external config files multiple times during compilation.

object

Setup plugins:

webpack.config.js (recommended)

const myOtherPostcssPlugin = require("postcss-my-plugin");

module.exports = {
  module: {
    rules: [
      {
        test: /\.sss$/i,
        loader: "postcss-loader",
        options: {
          postcssOptions: {
            plugins: [
              "postcss-import",
              ["postcss-short", { prefix: "x" }],
              require.resolve("my-postcss-plugin"),
              myOtherPostcssPlugin({ myOption: true }),
              // Deprecated and will be removed in the next major release
              { "postcss-nested": { preserveEmpty: true } },
            ],
          },
        },
      },
    ],
  },
};

webpack.config.js (deprecated, will be removed in the next major release)

module.exports = {
  module: {
    rules: [
      {
        test: /\.sss$/i,
        loader: "postcss-loader",
        options: {
          postcssOptions: {
            plugins: { "postcss-import": {}, "postcss-short": { prefix: "x" } },
          },
        },
      },
    ],
  },
};

Setup syntax:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.sss$/i,
        loader: "postcss-loader",
        options: {
          postcssOptions: {
            // Can be `string`
            syntax: "sugarss",
            // Can be `object`
            syntax: require("sugarss"),
          },
        },
      },
    ],
  },
};

Setup parser:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.sss$/i,
        loader: "postcss-loader",
        options: {
          postcssOptions: {
            // Can be `string`
            parser: "sugarss",
            // Can be `object`
            parser: require("sugarss"),
            // Can be `function`
            parser: require("sugarss").parse,
          },
        },
      },
    ],
  },
};

Setup stringifier:

webpack.config.js

const Midas = require("midas");
const midas = new Midas();

module.exports = {
  module: {
    rules: [
      {
        test: /\.sss$/i,
        loader: "postcss-loader",
        options: {
          postcssOptions: {
            // Can be `string`
            stringifier: "sugarss",
            // Can be `object`
            stringifier: require("sugarss"),
            // Can be `function`
            stringifier: midas.stringifier,
          },
        },
      },
    ],
  },
};

function

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.(css|sss)$/i,
        loader: "postcss-loader",
        options: {
          postcssOptions: (loaderContext) => {
            if (/\.sss$/.test(loaderContext.resourcePath)) {
              return {
                parser: "sugarss",
                plugins: [
                  ["postcss-short", { prefix: "x" }],
                  "postcss-preset-env",
                ],
              };
            }

            return {
              plugins: [
                ["postcss-short", { prefix: "x" }],
                "postcss-preset-env",
              ],
            };
          },
        },
      },
    ],
  },
};

config

Type:

type config = boolean | string;

Default: true

Allows you to set options using config files. Options specified in the config file are combined with options passed to the loader, the loader options overwrite options from config.

Config Files

The loader will search up the directory tree for configuration in the following places:

  • A postcss property in package.json
  • A .postcssrc file in JSON or YAML format
  • A .postcssrc.json, .postcssrc.yaml, .postcssrc.yml, .postcssrc.js, or .postcssrc.cjs file
  • A postcss.config.js or postcss.config.cjs CommonJS module exporting an object (recommended)
Examples of Config Files

Using object notation:

postcss.config.js (recommend)

module.exports = {
  // You can specify any options from https://postcss.org/api/#processoptions here
  // parser: 'sugarss',
  plugins: [
    // Plugins for PostCSS
    ["postcss-short", { prefix: "x" }],
    "postcss-preset-env",
  ],
};

Using function notation:

postcss.config.js (recommend)

module.exports = (api) => {
  // `api.file` - path to the file
  // `api.mode` - `mode` value of webpack, please read https://webpack.js.org/configuration/mode/
  // `api.webpackLoaderContext` - loader context for complex use cases
  // `api.env` - alias `api.mode` for compatibility with `postcss-cli`
  // `api.options` - the `postcssOptions` options

  if (/\.sss$/.test(api.file)) {
    return {
      // You can specify any options from https://postcss.org/api/#processoptions here
      parser: "sugarss",
      plugins: [
        // Plugins for PostCSS
        ["postcss-short", { prefix: "x" }],
        "postcss-preset-env",
      ],
    };
  }

  return {
    // You can specify any options from https://postcss.org/api/#processoptions here
    plugins: [
      // Plugins for PostCSS
      ["postcss-short", { prefix: "x" }],
      "postcss-preset-env",
    ],
  };
};

postcss.config.js (deprecated, will be removed in the next major release)

module.exports = {
  // You can specify any options from https://postcss.org/api/#processoptions here
  // parser: 'sugarss',
  plugins: {
    // Plugins for PostCSS
    "postcss-short": { prefix: "x" },
    "postcss-preset-env": {},
  },
};
Config Cascade

You can use different postcss.config.js files in different directories. Config lookup starts from path.dirname(file) and walks the file tree upwards until a config file is found.

|– components
| |– component
| | |– index.js
| | |– index.png
| | |– style.css (1)
| | |– postcss.config.js (1)
| |– component
| | |– index.js
| | |– image.png
| | |– style.css (2)
|
|– postcss.config.js (1 && 2 (recommended))
|– webpack.config.js
|
|– package.json

After setting up your postcss.config.js, add postcss-loader to your webpack.config.js. You can use it standalone or in conjunction with the built-in CSS support of webpack (recommended).

Use postcss-loader after other preprocessor loaders like e.g sass|less|stylus-loader, if you use any (since webpack loaders evaluate right to left/bottom to top).

webpack.config.js (recommended)

module.exports = {
  experiments: {
    css: true,
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        type: "css/auto",
        use: ["postcss-loader"],
      },
    ],
  },
};

boolean

Enables/Disables autoloading config.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "postcss-loader",
        options: { postcssOptions: { config: false } },
      },
    ],
  },
};

String

Allows to specify the path to the config file.

webpack.config.js

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

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: "postcss-loader",
        options: {
          postcssOptions: {
            config: path.resolve(__dirname, "custom.config.js"),
          },
        },
      },
    ],
  },
};

sourceMap

Type:

type sourceMap = boolean;

Default: depends on the compiler.devtool value

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

webpack.config.js

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

Alternative setup:

webpack.config.js

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

implementation

Type:

type implementation = object;

type of implementation should be the same as postcss.d.ts

Default: postcss

The special implementation option determines which implementation of PostCSS to use. Overrides the locally installed peerDependency version of postcss.

This option is only really useful for downstream tooling authors to ease the PostCSS 7-to-8 transition.

function

webpack.config.js

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

String

webpack.config.js

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

Examples

SugarSS

SugarSS is a whitespace-based syntax for PostCSS.

You'll need to install sugarss:

npm install --save-dev sugarss

Using SugarSS syntax.

webpack.config.js

module.exports = {
  experiments: {
    css: true,
  },
  module: {
    rules: [
      {
        test: /\.sss$/i,
        type: "css/auto",
        use: [
          {
            loader: "postcss-loader",
            options: { postcssOptions: { parser: "sugarss" } },
          },
        ],
      },
    ],
  },
};

Autoprefixer

You'll need to install autoprefixer:

npm install --save-dev autoprefixer

Automatically add vendor prefixes to CSS rules using autoprefixer.

webpack.config.js

module.exports = {
  experiments: {
    css: true,
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        type: "css/auto",
        use: [
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [
                  [
                    "autoprefixer",
                    {
                      // Autoprefixer options (optional)
                    },
                  ],
                ],
              },
            },
          },
        ],
      },
    ],
  },
};

[!WARNING]

postcss-preset-env includes autoprefixer, so adding it separately is not necessary if you already use the preset. More information

PostCSS Preset Env

You'll need to install postcss-preset-env:

npm install --save-dev postcss-preset-env

webpack.config.js

module.exports = {
  experiments: {
    css: true,
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        type: "css/auto",
        use: [
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [
                  [
                    "postcss-preset-env",
                    {
                      // Options
                    },
                  ],
                ],
              },
            },
          },
        ],
      },
    ],
  },
};

CSS Modules

What are CSS Modules? Please read here.

No additional options required on the postcss-loader side to support CSS Modules. With the built-in CSS support of webpack use the css/auto module type - all *.module.css files are treated as CSS modules, other files are treated as regular CSS.

webpack.config.js

module.exports = {
  experiments: {
    css: true,
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        type: "css/auto",
        use: ["postcss-loader"],
      },
    ],
  },
};

Use the css/module module type to treat all matched files as CSS modules, regardless of their name.

webpack.config.js

module.exports = {
  experiments: {
    css: true,
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        type: "css/module",
        use: ["postcss-loader"],
      },
    ],
  },
};

CSS-in-JS and postcss-js

To process styles written in JavaScript, you can use postcss-js as the parser.

You'll need to install postcss-js:

npm install --save-dev postcss-js

If you want to process styles written in JavaScript, use the postcss-js parser.

webpack.config.js

module.exports = {
  experiments: {
    css: true,
  },
  module: {
    rules: [
      {
        test: /\.style.js$/,
        type: "css/auto",
        use: [
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: { parser: "postcss-js" },
              execute: true,
            },
          },
          "babel-loader",
        ],
      },
    ],
  },
};

As result you will be able to write styles in the following way:

import colors from "./styles/colors";

export default {
  ".menu": { color: colors.main, height: 25, "&_link": { color: "white" } },
};

[!WARNING]

If you are using Babel you need to do the following in order for the setup to work

  1. Add babel-plugin-add-module-exports to your configuration.
  2. You need to have only one default export per style module.

Extract CSS

The built-in CSS support of webpack extracts CSS into separate files out of the box, no plugin is required. Use output.cssFilename and output.cssChunkFilename to control the names of the generated files.

webpack.config.js

const isProductionMode = process.env.NODE_ENV === "production";

module.exports = {
  mode: isProductionMode ? "production" : "development",
  experiments: {
    css: true,
  },
  output: {
    cssFilename: isProductionMode ? "[name].[contenthash].css" : "[name].css",
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        type: "css/auto",
        use: ["postcss-loader"],
      },
    ],
  },
};

💡 Use this setup to extract and cache CSS in production while keeping fast rebuilds during development.

Emit assets

To emit an asset from PostCSS plugin to the webpack, need to add a message in result.messages.

The message should contain the following fields:

  • type = asset - Message type (require, should be equal asset)
  • file - file name (require)
  • content - file content (require)
  • sourceMap - sourceMap
  • info - asset info

webpack.config.js

const postcssCustomPlugin = (opts = {}) => ({
  postcssPlugin: "postcss-custom-plugin",
  Once: (root, { result }) => {
    result.messages.push({
      type: "asset",
      file: "sprite.svg",
      content: "<svg>...</svg>",
    });
  },
});

module.exports = {
  experiments: {
    css: true,
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        type: "css/auto",
        use: [
          {
            loader: "postcss-loader",
            options: { postcssOptions: { plugins: [postcssCustomPlugin()] } },
          },
        ],
      },
    ],
  },
};

ℹ️ This allows your plugin to generate additional files as part of the build process, and Webpack will handle them like any other emitted asset.

Add dependencies, contextDependencies, buildDependencies, missingDependencies

The dependencies are necessary for webpack to understand when it needs to run recompilation on the changed files.

There are two way to add dependencies:

  1. (Recommended). The plugin may emit messages in result.messages.

The message should contain the following fields:

  • type = dependency - Message type (require, should be equal dependency, context-dependency, build-dependency or missing-dependency)
  • file - absolute file path (require)

webpack.config.js

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

const postcssCustomPlugin = (opts = {}) => ({
  postcssPlugin: "postcss-custom-plugin",
  Once: (root, { result }) => {
    result.messages.push({
      type: "dependency",
      file: path.resolve(__dirname, "path", "to", "file"),
    });
  },
});

module.exports = {
  experiments: {
    css: true,
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        type: "css/auto",
        use: [
          {
            loader: "postcss-loader",
            options: { postcssOptions: { plugins: [postcssCustomPlugin()] } },
          },
        ],
      },
    ],
  },
};

💡 You can use ready-made plugin postcss-add-dependencies to simplify this process.

  1. Pass loaderContext in plugin (for advanced setups).

webpack.config.js

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

module.exports = {
  experiments: {
    css: true,
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        type: "css/auto",
        use: [
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                config: path.resolve(__dirname, "path/to/postcss.config.js"),
              },
            },
          },
        ],
      },
    ],
  },
};

⚠️ Use this approach only when managing dependencies via custom PostCSS configurations with dynamic imports or external files.

postcss.config.js

Pass the webpackLoaderContext through the PostCSS api object:

module.exports = (api) => ({
  plugins: [
    require("path/to/postcssCustomPlugin.js")({
      loaderContext: api.webpackLoaderContext,
    }),
  ],
});

postcssCustomPlugin.js

Register a file dependency using loaderContext.addDependency:

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

const postcssCustomPlugin = (opts = {}) => ({
  postcssPlugin: "postcss-custom-plugin",
  Once: (root, { result }) => {
    opts.loaderContext.addDependency(
      path.resolve(__dirname, "path", "to", "file"),
    );
  },
});

postcssCustomPlugin.postcss = true;

module.exports = postcssCustomPlugin;

✅ This method is ideal when you want to dynamically declare dependencies without relying on result.messages, especially in more complex setups or shared plugin configurations.

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

sass-loader

npm node tests coverage discussion size discord-invite

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 enable experiments.css and set the module type to css/auto.

If you prefer the loader-based setup, install style-loader and css-loader via npm i style-loader css-loader and chain them with sass-loader instead.

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 and injects them into the document.

Alternatively, you can chain the sass-loader with the css-loader and the style-loader to immediately apply all styles to the DOM, or with 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,
        // 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 use 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, it's recommended to extract the CSS from your bundle to enable parallel loading of CSS/JS resources.

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

1. Built-in CSS support

Webpack emits CSS into separate files on its own, so nothing but experiments.css is required.

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].css",
    cssChunkFilename: "[id].css",
  },
  experiments: {
    css: true,
  },
};

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

3. Asset Modules

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

4. extract-loader (simpler, but specialized on the css-loader's output)

5. file-loader (deprecated--should only be used in webpack v4)

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/,
        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 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

stylus-loader

npm node tests cover discussion size

A Stylus loader for webpack. Compiles Stylus files into CSS.

Getting Started

To begin, you'll need to install stylus and stylus-loader:

npm install stylus stylus-loader --save-dev

or

yarn add -D stylus stylus-loader

or

pnpm add -D stylus stylus-loader

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

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/i,
        // Uses the built-in CSS support of webpack, i.e. `.module.styl` files
        // are treated as CSS modules, other files are treated as plain CSS
        type: "css/auto",
        // Compiles Stylus to CSS
        use: ["stylus-loader"],
      },
    ],
  },
  experiments: {
    // Enables the built-in CSS support of webpack
    css: true,
  },
};

[!NOTE]

The built-in CSS support of webpack requires experiments.css to be enabled. Alternatively you can still chain the loader with css-loader and style-loader (or the mini-css-extract-plugin), see Using css-loader and style-loader.

Finally, run webpack using the method you normally use (e.g., via CLI or an npm script).

Options

stylusOptions

Type:

type stylusOptions =
  | {
      use: (string | ((stylusOptions: StylusOptions) => void))[];
      include: string[];
      import: string[];
      define: any[];
      includeCSS: false;
      resolveURL: boolean | object;
      lineNumbers: boolean;
      hoistAtrules: boolean;
      compress: boolean;
    }
  | ((loaderContext: LoaderContext) => string[]);

Default: {}

You can pass any Stylus specific options to the stylus-loader through the stylusOptions property in the loader options.

See the Stylus documentation.

Options in dash-case should be written in camelCase.

object

Use an object to pass options through to Stylus.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/i,
        type: "css/auto",
        use: [
          {
            loader: "stylus-loader",
            options: {
              stylusOptions: {
                // eslint-disable-next-line jsdoc/no-restricted-syntax
                /**
                 * Specify Stylus plugins to use. Plugins may be passed as
                 * strings instead of importing them in your Webpack config.
                 * @type {(string | (renderer: object) => void)[]}
                 * @default []
                 */
                use: ["nib"],

                /**
                 * Add path(s) to the import lookup paths.
                 * @type {string[]}
                 * @default []
                 */
                include: [path.join(__dirname, "src/styl/config")],

                /**
                 * Import the specified Stylus files/paths.
                 * @type {string[]}
                 * @default []
                 */
                import: ["nib", path.join(__dirname, "src/styl/mixins")],

                /**
                 * Define Stylus variables or functions.
                 * @type {[string, string | number | boolean, boolean?] | Record<string, string | number | boolean>}
                 * @default {}
                 */
                // Array is the recommended syntax: [key, value, raw]
                define: [
                  ["$development", process.env.NODE_ENV === "development"],
                  ["rawVar", 42, true],
                ],
                // Object is deprecated syntax (there is no possibility to specify "raw')
                // define: {
                //   $development: process.env.NODE_ENV === 'development',
                //   rawVar: 42,
                // },

                /**
                 * Include regular CSS on \@import.
                 * @type {boolean}
                 * @default false
                 */
                includeCSS: false,

                /**
                 * Resolve relative url()'s inside imported files.
                 * @see https://stylus-lang.com/docs/js.html#stylusresolveroptions
                 * @type {boolean | { nocheck?: boolean, paths?: string[] }}
                 * @default { nocheck: true }
                 */
                resolveURL: true,
                // resolveURL: { nocheck: true },

                /**
                 * Emits comments in the generated CSS indicating the corresponding Stylus line.
                 * @see https://stylus-lang.com/docs/executable.html
                 * @type {boolean}
                 * @default false
                 */
                lineNumbers: true,

                /**
                 * Move \@import and \@charset to the top.
                 * @see https://stylus-lang.com/docs/executable.html
                 * @type {boolean}
                 * @default false
                 */
                hoistAtrules: true,

                /**
                 * Compress CSS output.
                 * In the "production" mode is `true` by default
                 * @see https://stylus-lang.com/docs/executable.html
                 * @type {boolean}
                 * @default false
                 */
                compress: true,
              },
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

function

Allows setting the options passed through to Stylus based off of the loader context.

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/i,
        type: "css/auto",
        use: [
          {
            loader: "stylus-loader",
            options: {
              stylusOptions: (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.styl") {
                  return {
                    paths: ["absolute/path/c", "absolute/path/d"],
                  };
                }

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

sourceMap

Type:

type sourceMap = boolean;

webpack.config.js

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

webpackImporter

Type:

type webpackImporter = 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.

webpack.config.js

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

additionalData

Type:

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

Default: undefined

Prepends Stylus code before the actual entry file. In this case, the stylus-loader will not override the source but will simply prepend the entry's content.

This is especially useful when some of your Stylus variables depend on the environment.

[!NOTE]

Since you're injecting code, this will break the source mappings in your entry file. Often there's a simpler solution than this, such as using multiple Stylus entry files.

string

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/i,
        type: "css/auto",
        use: [
          {
            loader: "stylus-loader",
            options: {
              additionalData: `@env: ${process.env.NODE_ENV};`,
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

function

Sync
module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/i,
        type: "css/auto",
        use: [
          {
            loader: "stylus-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.styl") {
                  return `value = 100px${content}`;
                }

                return `value = 200px${content}`;
              },
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};
Async
module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/i,
        type: "css/auto",
        use: [
          {
            loader: "stylus-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.styl") {
                  return `value = 100px${content}`;
                }

                return `value = 200px${content}`;
              },
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

implementation

Type:

type implementation = (() => typeof import("stylus")) | string;

The implementation option allows you to specify which Stylus implementation to use. It overrides the locally installed peerDependency version of stylus.

function

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/i,
        type: "css/auto",
        use: [
          {
            loader: "stylus-loader",
            options: {
              implementation: require("stylus"),
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

string

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/i,
        type: "css/auto",
        use: [
          {
            loader: "stylus-loader",
            options: {
              implementation: require.resolve("stylus"),
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

Examples

Normal Usage

Set the module type to css/auto and enable experiments.css to let webpack handle the generated CSS with its built-in CSS support, without any extra loaders or plugins.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/i,
        type: "css/auto", // Handles the generated CSS using the built-in CSS support of webpack
        use: ["stylus-loader"], // Compiles Stylus to CSS
      },
    ],
  },
  experiments: {
    css: true,
  },
};

The css/auto module type treats *.module.styl files as CSS modules and any other file as plain CSS. Use type: "css" to always treat the file as plain CSS, or type: "css/module" to always treat it as a CSS module.

Using css-loader and style-loader

The built-in CSS support of webpack is not mandatory, you can still chain the stylus-loader with css-loader and style-loader to immediately apply all styles to the DOM.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/i,
        use: [
          {
            loader: "style-loader", // Creates style nodes from JS strings
          },
          {
            loader: "css-loader", // Translates CSS into CommonJS
          },
          {
            loader: "stylus-loader", // Compiles Stylus to CSS
          },
        ],
      },
    ],
  },
};

Note that in this case the type and experiments.css options should not be set for this rule, and options like sourceMap have to be enabled for the css-loader too.

Source maps

To enable sourcemaps for CSS, you'll need to pass the sourceMap property in the loader's options. If this is not passed, the loader will respect the setting for webpack source maps, set in devtool.

webpack.config.js

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

Using nib with stylus

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/i,
        type: "css/auto",
        use: [
          {
            loader: "stylus-loader",
            options: {
              stylusOptions: {
                use: [require("nib")()],
                import: ["nib"],
              },
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

Import JSON files

Stylus does not provide resolving capabilities in the json() function. Therefore webpack resolver does not work for .json files. To handle this, use a stylus resolver.

index.styl

// Suppose the file is located here `node_modules/vars/vars.json`
json('vars.json')

@media queries-small
  body
    display nope

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/i,
        type: "css/auto",
        use: [
          {
            loader: "stylus-loader",
            options: {
              stylusOptions: {
                // Specify the path. where to find files
                paths: ["node_modules/vars"],
              },
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

In production

The built-in CSS support of webpack always extracts style sheets into dedicated files, so your styles are not dependent on JavaScript, which improves performance and cacheability. The name of the generated files can be configured using the output.cssFilename and output.cssChunkFilename options.

When you chain the loader with css-loader and style-loader instead, it's recommended to extract the style sheets into a dedicated CSS file in production using the MiniCssExtractPlugin. This way your styles are not dependent on JavaScript.

webpack resolver

Webpack provides an advanced mechanism to resolve files. The stylus-loader applies the webpack resolver when processing queries. Thus you can import your Stylus modules directly from node_modules.

@import 'bootstrap-styl/bootstrap/index.styl';

Using ~ prefix is deprecated and can be removed from your code (we recommended), but we still support it for historical reasons.

Why you can removed it? The loader will first try to resolve @import/@require as relative, if it cannot be resolved, the loader will try to resolve @import/@require inside node_modules.

Just prepend them with a ~ which tells webpack to look up the modules.

@import "~bootstrap-styl/bootstrap/index.styl";

It's important to only prepend it with ~, because ~/ resolves to the home-directory, which is different.

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

Writing @import "file" is the same as @import "./file";

Stylus resolver

If you specify the paths option, modules will be searched in the given paths. This is the default Stylus behavior.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/i,
        type: "css/auto",
        use: [
          {
            loader: "stylus-loader",
            options: {
              stylusOptions: {
                paths: [path.resolve(__dirname, "node_modules")],
              },
            },
          },
        ],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

Extracting style sheets

Bundling CSS with webpack has some nice advantages like referencing images and fonts with hashed URLs or hot module replacement in development. In production, on the other hand, it's not a good idea to apply your style sheets depending on JS execution. Rendering may be delayed or even a FOUC might be visible. Thus it's often still better to have them as separate files in your final production build.

The built-in CSS support of webpack does this out of the box: every entry point and chunk gets its own style sheet, no extra plugin required. When you chain the loader with the css-loader instead, use the MiniCssExtractPlugin to extract a style sheet from the bundle.

CSS modules

With the built-in CSS support of webpack, *.module.styl files are treated as CSS modules when the module type is css/auto, and all files are treated as CSS modules when the module type is css/module:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.styl$/i,
        type: "css/auto",
        use: ["stylus-loader"],
      },
    ],
  },
  experiments: {
    css: true,
  },
};

index.js

import * as styles from "./style.module.styl";

document.body.className = styles.box;

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

thread-loader

npm node tests coverage discussion size

Runs the specified loaders in a worker pool.

Getting Started

npm install --save-dev thread-loader

or

yarn add -D thread-loader

or

pnpm add -D thread-loader

Put this loader in front of other loaders. The following loaders run in a worker pool.

Loaders running in a worker pool have limitations. Examples:

  • Loaders cannot emit files.
  • Loaders cannot use custom loader APIs (i.e. by plugins).
  • Loaders cannot access webpack options.

Each worker is a separate Node.js process, which has an overhead of ~600ms. There is also additional overhead from inter-process communication.

Use this loader only for expensive operations!

Examples

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve('src'),
        use: [
          'thread-loader',
          // your expensive loader (e.g babel-loader)
        ],
      },
    ],
  },
};

with options

use: [
  {
    loader: 'thread-loader',
    // loaders with equal options will share worker pools
    options: {
      // the number of spawned workers, defaults to (number of cpus - 1) or
      // fallback to 1 when require('os').cpus() is undefined
      workers: 2,

      // number of jobs a worker processes in parallel
      // defaults to 20
      workerParallelJobs: 50,

      // additional node.js arguments
      workerNodeArgs: ['--max-old-space-size=1024'],

      // Allow to respawn a dead worker pool
      // respawning slows down the entire compilation
      // and should be set to false for development
      poolRespawn: false,

      // timeout for killing the worker processes when idle
      // defaults to 500 (ms)
      // can be set to Infinity for watching builds to keep workers alive
      poolTimeout: 2000,

      // number of jobs the pool distributes to the workers
      // defaults to 200
      // decrease for less efficient but more fair distribution
      poolParallelJobs: 50,

      // name of the pool
      // can be used to create different pools with otherwise identical options
      name: 'my-pool',
    },
  },
  // your expensive loader (e.g babel-loader)
];

prewarming

To prevent the high delays when booting workers, it is possible to warm up the worker pool.

This boots the max number of workers in the pool and loads the specified modules into the Node.js module cache.

const threadLoader = require('thread-loader');

threadLoader.warmup(
  {
    // pool options, like passed to loader options
    // must match loader options to boot the correct pool
  },
  [
    // modules to load
    // can be any module, i.e.
    'babel-loader',
    '@babel/preset-env',
    'sass-loader',
  ],
);

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

Loaders

What needs no loader

Webpack handles these itself — install a loader only for what is not on this list:

Webpack enables use of loaders to preprocess everything else. This allows you to bundle any static resource way beyond JavaScript. You can easily write your own loaders using Node.js. Loaders are separate packages that extend webpack's capabilities and are maintained within the broader ecosystem. Loaders are activated by using loadername! prefixes in import .. from "mod";/require() statements, or are automatically applied via regex from your webpack configuration – see configuration.

Files

  • ref-loader Create dependencies between any files manually

JSON

Transpiling

Templating

Styling

Frameworks

Awesome

For more third-party loaders, see the list from awesome-webpack.

Edit this page·

1 Contributor

webpack