geddski / csstyle

MOVED TO https://github.com/csstyle/csstyle a modern approach for crafting beautifully maintainable stylesheets
http://csstyle.io
Other
851 stars 34 forks source link

Discussion: Convert PostCSS to use @rules instead of custom selectors #48

Open zspecza opened 9 years ago

zspecza commented 9 years ago

This will have some benefits. The most notable benefit is that Stylus leaves custom @rules as-is when it compiles down to CSS (so, @component { } in file.styl will be @component { } in file.css. That means that the Stylus CSStyle plugin can simply hook into Stylus, listen for it's end event, grab the processed css, pass it to PostCSS which will run it through CSStyle and finally pass it back to Stylus, and hey presto, a working Stylus plugin! :)

module.exports = function(opts) {
  opts = opts || {};
  var settings = _.defaults({
    // csstyle prefix settings
  }, opts);

  return function(style){
    style = this || style;
    var filename = style.options.filename;

    style.on('end', function(err, css){
      // ... handle error

      // configure the options to be passed to csstyle
      process_opts = {
        from: filename,
        to: path.join(
          path.dirname(filename),
          path.basename(filename, path.extname(filename))
        ) + '.css'
      }

      // if there is a stylus sourcemap, ensure postcss also generates one
      if (style.sourcemap) {
        process_opts.map = { annotation: false }
      }

      // run csstyle
      var res = postcss(opts).use(nested).use(csstyle(settings).process(css, process_opts);

      // if sourcemaps are generated, combine the two
      if (res.map && style.sourcemap) {
        var combined_map = map.transfer({
          fromSourceMap: res.map.toString(),
          toSourceMap: style.sourcemap
        });

        // then set the combined result as the new sourcemap
        style.sourcemap = JSON.parse(combined_map);
      }

      // return the css output
      return res.css;
    });

  }

}

The second benefit is that postcss-nested supports custom @rules bubbling:

By default, plugin will unwrap only @media, @support and @document at-rules. You can add your custom at-rules to this list by bubble option:

postcss([ require('postcss-nested')({ bubble: ['phone'] }) ]

Which will help clean up a lot of the PostCSS code in CSStyle.

If only Sass and Less also allowed custom @rules and left them as-is - then no one would have to write 3 different versions of their plugin ^_^

Also, I did read something (trying to find it, will update this when I do) about PostCSS plugins eventually being able to detect the use of plugins previously in the chain, so you could refactor CSStyle to be a plugin pack consisting of:

Then, if nested is not found, you could simply flag csstyle to use it - if it is found, csstyle will just use the already-existing version in the pipeline - this makes installation/setup a tad easier, and has a little bit of performance benefit.

What do you think @geddski?

zspecza commented 9 years ago

Side note:

If it's possible to pipe output from Sass / Less to PostCSS and then back again the same way Stylus can, then it might be possible to re-use the PostCSS CSStyle internals for each and every CSS preprocessor, as long as the PostCSS version handles both the selector syntax (component(name)) and the AtRule syntax (@component(name)).

Here's what's possible to output using Stylus, Sass and Less (the css output is commented out):

Stylus:

@component(name)
  color: blue
/*
  @component (name) {
    color: blue;
  }
*/

Sass:

$com: 'component()';

#{$com} {
  color: blue;
}

/*
  component() {
    color: blue;
  }
*/

Less:

@com: component();

@{com} {
  color: blue;
}

/*
component() {
  color: blue;
}
*/

So, as long as we have a way to build the necessary syntax in each processor, CSStyle can just keep all the transformation logic in one place - making it easier to update and maintain. :boom:

geddski commented 8 years ago

I'd like to explore this option, thanks for the suggestion.