rtsao / csjs

:sparkles: Modular, scoped CSS with ES6
MIT License
575 stars 32 forks source link

csjs-loader : webpack loader support #29

Open SilentCicero opened 8 years ago

SilentCicero commented 8 years ago

I've been studying the csjs-extractify, but I don't know how I could approach it with the webpack loader model.

Thoughts? @rtsao

codrin-iftimie commented 8 years ago

I've tried making such a loader. I even made it work with extract-text-webpack-plugin. Mostly the code you need is

// csjs-loader.js

var requireFromString = require('require-from-string');
var getCss = require('csjs').getCss;
module.exports = function(source) {
  return getCss(requireFromString(source));
}

The problem is that you'd be interpreting all .csjs.js files, through css!csjs!babel. This disables the compose feature:

//simple_button.csjs.js
export default csjs`
  .simple-button {
     // styles ...
   }
`;

//custom_button.csjs.js
import s from './simple_button.csjs' // <-- this is actually translated into css

export default csjs `
  .primary-button extends `${s['simple-button']}` { // <-- you cannot extend it
    // style
  }
`;

@rtsao Does this work well with csjs-extractify?

SilentCicero commented 8 years ago

@codrin-iftimie why does this disable the compose feature?

And can you provide the code you used for webpack for extract-text? Would like to take a look.

codrin-iftimie commented 8 years ago

I've created a gist. When importing a csjs.js file inside another csjs.js file the import gets translated into css. The import is undefined, so when you are extending the imported styles you are calling accessing undefined['simple-button'].

mkazlauskas commented 8 years ago

I'm doing it using a little different approach. To be compatible with css modules, I'm setting locals to the loader exports object. This way I can use style-loader out of the box to add css to page and re-export locals object. So I simply do:

styles.csjs.js

module.exports = csjs`.myClass { ... }`

app.js

import { myClass } from './styles.csjs';
import { classFromCss } from './someCss.css';

webpack.config.js

loaders: [
      {
        test: /\.csjs\.js?$/,
        loader: 'style!csjs!val!babel',
      }, {
        test: /\.css$/,
        loader: 'style!csjs!css!postcss',
      },
],

csjs loader:

const csjs = require('csjs');

const csjsify = (source) => (
  typeof source === 'string'
  ? csjs`${source}`
  : source
);

const stringify = (styles) => {
  const result = Object.assign(styles, {});
  Object.keys(result).forEach((k) => (result[k] = result[k].className));
  return JSON.stringify(result);
};

module.exports = (source, map) => {
  const styles = csjsify(source);
  return `
    module.exports = [[module.id, \`${csjs.getCss(styles)}\`, ${map}]];
    module.exports.locals = ${stringify(styles)};
  `;
};

I still didn't figure out how to enable sourcemaps using this approach. val-loader doesn't seem to provide those.

SilentCicero commented 8 years ago

interesting, yes more thought is needed @mkazlauskas

mkazlauskas commented 8 years ago

@SilentCicero I updated my previous comment, added support to pipe plain css files over csjs loader. This way we can keep external classes of dependencies scoped.

avesus commented 8 years ago

"I still didn't figure out how to enable sourcemaps using this approach."

"added support to pipe plain css files over csjs loader"

That's sounds so amazingly great that we definitely should support source maps generation for csjs.