CanopyTax / kremling

Embarrassingly simple css for React
https://kremling.js.org
Apache License 2.0
36 stars 4 forks source link

Add support for sass #56

Closed Darhagonable closed 3 years ago

Darhagonable commented 3 years ago

Seems great but i wish one could type scss

joeldenning commented 3 years ago

The kremling-loader project is a postcss plugin. You can run SASS as a postcss plugin as well - https://github.com/AleshaOleg/postcss-sass. You could try using them together - you'd want kremling-loader to run after SASS has finished.

Darhagonable commented 3 years ago

Will that allow one to write scss within the JS file though? My understanding is that it's just for separate scss files?

joeldenning commented 3 years ago

Your understanding is correct - the approach I described above only works when putting the css in separate files.

The challenge with allowing sass within the js component is that SASS must be compiled at build-time. We created https://github.com/CanopyTax/kremling-babel-plugin a while back with the intent of allowing build-time compilation to occur within JS files. I think that would be the place to attempt an implementation. cc @geoctrl who worked on the babel plugin

geoctrl commented 3 years ago

the problem with the kremling-bable-plugin is that babel runs synchronously, and a lot of postcss plugins are asynchronous - so there was absolutely no way of implementing this without running into lots of problems

however, I did create a work-around: kremling-inline-loader (npm link)

note: this is an experiment and should be used with a fair amount of caution (note the lack of docs for the project - I really need to get that updated...)

kremling-inline-loader is a webpack loader that runs babel within it for each js file looking for the k template literal tag - once it finds one, it runs postcss or sass on it (depending on your config). Currently postcss and sass (scss) are the only ones supported.

for writing inline scss, your webpack config might look something like this:

module.exports = {
  ...
  module: {
    rules: [
      {
        test: /\.js/,
        exclude: /node_modules/,
        use: [
          'babel-loader',
          {
            loader: 'kremling-inline-loader',
            options: {
              sass: { // this is a pass-through for your sass config
                data: `@import "${path.resolve(
                  './src/styles/globals/variables.scss'
                )}";`
              },
            },
          },
        ],
      },
    ],
  },
}

your inline styles can now look like this:

const css = k`
  .fun-thing {
    background-color: $primary-color;
    .inside {
      text-align: right;
    }
  }
`;

and just like the kremling-loader, this is automatically scoped without having to write the ampersands before each rule 👍

downsides

babel is now parsing each file TWICE on every js file (assuming you're using babel-loader)... which could make your project start up a bit slower (especially for large projects)

however, once the project is running, changes you make to each file very quick 🤷

geoctrl commented 3 years ago

one thing I forgot to mention - the babel parser running within the loader has hardcoded options plugins: jsx and classProperties - if your js file requires other babel plugins, then this loader will fail

the ultimate goal would be to use the babel config (.babelrc or something) that lives in your project root dir - but I haven't gotten to that yet

Darhagonable commented 3 years ago

Having it configured inside babel config instead would be great because then it could work with Parcel 2 as well

Darhagonable commented 3 years ago

@geoctrl I also never got it working with webpack either for some reason