A loader to process CSS using PostCSS.
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 postcssor
yarn add -D postcss-loader postcssor
pnpm add -D postcss-loader postcssThen add the loader to your webpack configuration. For example:
In the following configuration the plugin
postcss-preset-envis used, which is not installed by default.
file.js
import css from "file.css";webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [
"style-loader",
"css-loader",
{
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 = {
module: {
rules: [
{
test: /\.css$/i,
use: ["style-loader", "css-loader", "postcss-loader"],
},
],
},
};Finally, run webpack using the method you normally use (e.g., via CLI or an npm script).
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 = {
module: {
rules: [
{
test: /\.style.js$/,
use: [
"style-loader",
{ loader: "css-loader" },
{
loader: "postcss-loader",
options: {
postcssOptions: { parser: "postcss-js" },
execute: true,
},
},
],
},
],
},
};See the file ./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.
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,
},
},
},
],
},
};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",
],
};
},
},
},
],
},
};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.
The loader will search up the directory tree for configuration in the following places:
- A
postcssproperty inpackage.json - A
.postcssrcfile in JSON or YAML format - A
.postcssrc.json,.postcssrc.yaml,.postcssrc.yml,.postcssrc.js, or.postcssrc.cjsfile - A
postcss.config.jsorpostcss.config.cjsCommonJS module exporting an object (recommended)
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": {},
},
};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 css-loader (recommended).
Use postcss-loader before css-loader and style-loader, but 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 = {
module: {
rules: [
{
test: /\.css$/,
use: [
"style-loader",
{ loader: "css-loader", options: { importLoaders: 1 } },
"postcss-loader",
],
},
],
},
};Enables/Disables autoloading config.
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
loader: "postcss-loader",
options: { postcssOptions: { config: false } },
},
],
},
};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"),
},
},
},
],
},
};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: /\.css$/i,
use: [
{ loader: "style-loader" },
{ loader: "css-loader", options: { sourceMap: true } },
{ loader: "postcss-loader", options: { sourceMap: true } },
{ loader: "sass-loader", options: { sourceMap: true } },
],
},
],
},
};Alternative setup:
webpack.config.js
module.exports = {
devtool: "source-map",
module: {
rules: [
{
test: /\.css$/i,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" },
{ loader: "postcss-loader" },
{ loader: "sass-loader" },
],
},
],
},
};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.
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" },
{
loader: "postcss-loader",
options: { implementation: require("postcss") },
},
{ loader: "sass-loader" },
],
},
],
},
};webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" },
{
loader: "postcss-loader",
options: { implementation: require.resolve("postcss") },
},
{ loader: "sass-loader" },
],
},
],
},
};SugarSS is a whitespace-based syntax for PostCSS.
You'll need to install sugarss:
npm install --save-dev sugarssUsing SugarSS syntax.
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.sss$/i,
use: [
"style-loader",
{ loader: "css-loader", options: { importLoaders: 1 } },
{
loader: "postcss-loader",
options: { postcssOptions: { parser: "sugarss" } },
},
],
},
],
},
};You'll need to install autoprefixer:
npm install --save-dev autoprefixerAutomatically add vendor prefixes to CSS rules using autoprefixer.
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [
"style-loader",
{ loader: "css-loader", options: { importLoaders: 1 } },
{
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
You'll need to install postcss-preset-env:
npm install --save-dev postcss-preset-envwebpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [
"style-loader",
{ loader: "css-loader", options: { importLoaders: 1 } },
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
[
"postcss-preset-env",
{
// Options
},
],
],
},
},
},
],
},
],
},
};What are
CSS Modules? Please read here.
No additional options required on the postcss-loader side to support CSS Modules.
To make them work properly, either add the css-loader’s importLoaders option.
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [
"style-loader",
{
loader: "css-loader",
options: { modules: true, importLoaders: 1 },
},
"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-jsIf you want to process styles written in JavaScript, use the postcss-js parser.
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.style.js$/,
use: [
"style-loader",
{ loader: "css-loader", options: { importLoaders: 2 } },
{
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
- Add
babel-plugin-add-module-exportsto your configuration. - You need to have only one default export per style module.
To extract CSS into separate files, use mini-css-extract-plugin.
webpack.config.js
const isProductionMode = process.env.NODE_ENV === "production";
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
mode: isProductionMode ? "production" : "development",
module: {
rules: [
{
test: /\.css$/,
use: [
isProductionMode ? MiniCssExtractPlugin.loader : "style-loader",
"css-loader",
"postcss-loader",
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: isProductionMode ? "[name].[contenthash].css" : "[name].css",
}),
],
};💡 Use this setup to extract and cache CSS in production while keeping fast style injection during development.
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 equalasset)file- file name (require)content- file content (require)sourceMap- sourceMapinfo- 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 = {
module: {
rules: [
{
test: /\.css$/i,
use: [
"style-loader",
"css-loader",
{
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.
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:
- (Recommended). The plugin may emit messages in
result.messages.
The message should contain the following fields:
type=dependency- Message type (require, should be equaldependency,context-dependency,build-dependencyormissing-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 = {
module: {
rules: [
{
test: /\.css$/i,
use: [
"style-loader",
"css-loader",
{
loader: "postcss-loader",
options: { postcssOptions: { plugins: [postcssCustomPlugin()] } },
},
],
},
],
},
};💡 You can use ready-made plugin postcss-add-dependencies to simplify this process.
- Pass
loaderContextin plugin (for advanced setups).
webpack.config.js
const path = require("node:path");
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [
"style-loader",
"css-loader",
{
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.
We welcome all contributions! If you're new here, please take a moment to review our contributing guidelines before submitting issues or pull requests.