Closed manulitopetito closed 5 years ago
I think this is doable. My OSS time is currently limited, so I’ve made a call out to community members to help you. Please ping me in a week if no one has helped you.
Our team is facing this same issue, wanting to generate multiple themed stylesheets from 1 entry file to provide different themes for our react components in our app.
Our code setup looks like the following. We have a default CSS file using CSS custom properties, this gets imported into app.js.
/* styles.css */
.button {
color: var(--button-color, #f00); /* Falls back to #f00 if --button-color is not set */
}
This stylesheet is then imported into our app.js
file.
// app.js
import ('./styles.css');
app.js
is our main entry we run through webpack. This runs the imported css file through postcss-loader with the postcss-custom-properties and which outputs the following:
/* style.css gets output as app.css */
.button {
color: #f00;
}
We have a separate CSS file which acts as our theme file which contains definitions for all of the CSS custom properties inside of a root selector. It looks something like this.
blue-theme.css
/* blue-theme.css */
:root {
--button-color: #006;
}
If an app wanted to use this this theme, it would import blue-theme.css
into it's app.js
file which acts as the entry file for webpack.
// app.js
import ('./styles.css');
import ('./blue-theme.css');
When app.js
is run through webpack and postcss-loader with the postcss-custom-properties, it outputs the following:
output
/* app.css */
.button {
color: #006; /* value from blue-theme.css used via postcss-custom-properties */
}
:root {
--button-color: #006;
}
What we'd much rather have is 2 generated CSS files: app.css
and app-blue-theme.css
ideal app.css
/* app.css */
.button {
color: #f00; /* default color */
}
ideal app-blue-theme.css
/* app-blue-theme.css */
.button {
color: #006; /* themed color */
}
/* It would be nice to remove this :root selector after the trasformation of CSS custom properties to static values, but thats another issue */
:root {
--button-color: #006;
}
I've thought a little bit about the interface for a plugin to handle this. I've envisioned a plugin which takes file paths for theme files and uses it to generate the additional theme stylesheets from the 1 entry based stylesheet.
// postcss.config.js
const ThemingPlugin = require('./theming-plugin');
module.exports = {
plugins() {
return [
ThemingPlugin({
"blue-theme": "./blue-theme.css",
}),
];
},
};
Where I start to get confused is how to go about splitting the css AST and what happens to it after it is split. Does splitting the CSS file into multiples prevent additional PostCSS modifications.
I've put together a prototype of what I'd like to achieve, multiple themed CSS files using CSS custom properties complied into static values, though it achieves this by using multiple webpack entries. I'd love to find a way to do this via 1 webpack entry and a PostCSS plugin.
Here a few links I've come across discussing this more on this topic:
This example repo I did doesn't utilize custom properties, but it does illustrate a simple approach on how to do theming in postcss. It probably answers the original question at least. Hope it helps.
Right now we are using a scss mixin ( https://github.com/zellwk/themify ) to provide different themes for our react components in our app.
It works great, but produces rather long selector chains in the compiled css file.
While we do have to provide the ability to change themes during runtime ( which is no hassle with the current solution, we only have to switch one classname on the body element ) the default usecase is, that the theme does not change.
So we thought about reducing the complexity and filesize of our stylesheets by splitting them up in separate files.
Example:
themes.scss:
button.sccs
This becomes:
Now I want this to become:
theme-red.css:
theme-blue.css:
How would I achieve this with postcss and custom properties?
Thanks a lot!