Eleventy: PostCSS filter for concatenated CSS files

Created on 26 Apr 2019  路  6Comments  路  Source: 11ty/eleventy

Is there anywhere a working example for this? E. g. concerning Autoprefixer

What I have tried is to make a filter first:

const postcss = require('postcss');
const autoprefixer = require('autoprefixer');

eleventyConfig.addFilter( "postCSS", function( code ) {
    postcss([
        autoprefixer({
            // options
        })
    ])
    .process(code)
    .then( function (result) {
        return result.code;
    })
});

and then apply this filter to a template like this:

permalink: css/styles-mix.css
---
{% set css %}
    {% include "baseCSS/style1.css" %}
    {% include "baseCSS/style2.css" %}
    {% include "baseCSS/style3.css" %}
{% endset %}

{{ css | postCSS | safe }}

But it does not work.

I know, there is a similar approach with a single CSS file (https://github.com/11ty/eleventy/issues/272#issuecomment-474883189) but the example lacks the PostCSS part.

Most helpful comment

First of all, the resulting CSS is accessed via result.css. The processed CSS is in there; however, it looks like Eleventy鈥檚 universal filters don鈥檛 work with asynchronous (e.g. promise-based) APIs like postcss.process. That鈥檚 why the result of the filter is empty (or probably undefined).

Since there is also a synchronous variant of postcss.process, you can use that instead:

const postcss = require("postcss");
const autoprefixer = require("autoprefixer");

module.exports = function(eleventyConfig) {
  eleventyConfig.addFilter("postCSS", function(code) {
    return postcss([autoprefixer]).process(code).css;
  });

  return {
    htmlTemplateEngine: "njk"
  }
};

All 6 comments

What does not work? Are there errors? What is the result and what do you expect it to be?

As for my example, "css/styles-mix.css" is empty.
I have expected that the CSS files were concatenated and the Autoprefixer filter were applied then.

The console displays this error:

Without `from` option PostCSS could generate wrong source map and will not find Browserslist config. Set it to CSS file path or to `undefined` to prevent this warning.

What could "from" be while concatenating?

First of all, the resulting CSS is accessed via result.css. The processed CSS is in there; however, it looks like Eleventy鈥檚 universal filters don鈥檛 work with asynchronous (e.g. promise-based) APIs like postcss.process. That鈥檚 why the result of the filter is empty (or probably undefined).

Since there is also a synchronous variant of postcss.process, you can use that instead:

const postcss = require("postcss");
const autoprefixer = require("autoprefixer");

module.exports = function(eleventyConfig) {
  eleventyConfig.addFilter("postCSS", function(code) {
    return postcss([autoprefixer]).process(code).css;
  });

  return {
    htmlTemplateEngine: "njk"
  }
};

Awesome! Your are brilliant, @kleinfreund! Thank you.

I suppose your point could be interesting for a lot of people, maybe as another "Quick tip" at 11ty's site.

As being solved I am closing now this issue.

Sorry,the above solution does not work for two or more PostCSS filters like this:

eleventyConfig.addFilter( "postCSS", function( code ) {
    return postcss( [
        require( 'autoprefixer' )( {
            /* options */
        } ),
        require( "cssnano" )( {
            preset: [ 
                'default', {
                    /* options */
                } 
            ]
        } )
    ] )
    .process( code )
    .css;
} );

Any suggestions?

Error: Use process(css).then(cb) to work with async plugins (Template render error)

... which does not work also ...

Was this page helpful?
0 / 5 - 0 ratings