PostCSS plugin that allows the inclusion of CSS from one CSS rule into another by copying the relevant declarations over.
This is similar in spirit to Sass mixins and PostCSS mixins, but solves a different problem in that it tries to be a replacement for CSS Module’s composition.
CSS Modules has introduced the composes
property as a way of inheriting styles from different places. However, after having used composes
heavily, its fundamental flaws have shown through again and again. It tries to solve a similar problem as Sass did with @extend, but in either case these solutions start to break down if overused. It just isn't possible to get this to run reliably due to the nature of CSS where source order matters for specificity.
The PostCSS Includes plugin tries to stay close to composes
so that it can be a drop-in replacement, but solves the problems of source order by inlining the CSS. This will obviously make the CSS bigger, but that is an easy choice for us if the output is reliable.
Include CSS from another rule defined in the same file. Not that in this simple situation the use of composes
would be possible without problems, so be sure to understand the limitations of both approaches.
/* Input */
.bar { color: red; }
.foo { includes: bar; }
/* Output */
.bar { color: red; }
.foo { color: red; }
It's possible to include declarations from another file (the result will be the same as above).
/* bar.css */
.bar { color: red; }
/* main.css */
.foo { includes: bar from './bar.css'; }
This module has only been tested with Webpack so far. The following shows an example of how to integrate the plugin with Webpack; what you can see is that a readFile
function is defined. The reason the readFile
function needs to be defined like this is so that we can load files referenced by an includes
rule using Webpack’s load paths. This example also shows that the postcss
config option can be a function that returns an array of plugins to use.
// postcss.config.js
// https://github.com/michael-ciniawsky/postcss-load-config
const fs = require("fs");
module.exports = ctx => {
function readFile(filepath) {
return new Promise(function(resolve, reject) {
ctx.webpack.resolve(ctx.webpack.context, filepath, function(moduleError, realpath) {
if (moduleError) return reject(moduleError);
fs.readFile(realpath, "utf8", function(readFileError, contents) {
readFileError ? reject(readFileError) : resolve(contents);
});
});
});
}
return {
plugins: [
require("postcss-includes")({ readFile }),
require("postcss-flexbugs-fixes"),
require("postcss-preset-env")({
autoprefixer: {
flexbox: "no-2009"
}
}),
require("postcss-nested"),
require("postcss-css-variables")({
preserve: false,
variables: require("./src/constants")
})
]
};
};