Full static extraction to CSS file while keeping all dynamic parts intact.
- Dominant language
- JavaScript
- Stars
- 7.1k
- Forks
- 386
- PR merge metrics
- No merged PRs in 30d
Description
The idea is to optimize it in a way that shifts preprocessing runtime overhead to the build stage, while keeping all dynamic parts working. It includes 2 stages: one is babel plugin, another is webpack plugin.
With full extraction,:
- There will be no static styles at runtime that need to be parsed and injected (only dynamic)
- No double loading of static styles in JS build + CSS build.
With babel plugin only there will be no runtime processing of static styles, only dynamic. Current state is that jss core without plugins with styles object vs preprocessed version of the same object results in 50% performance boost.
## Exmple
```js
// source js
const styles = {
static: {
color: 'green'
},
mixed: {
color: 'red',
margin: (props) => props.spacing
}
}
createStyleSheet(styles).attach()
// generated js
const styles = {
'@raw': `
.static-0-0-1 {
color: green;
}
.mixed-0-0-2 {
color: red;
}
`,
mixed: {
margin: (props) => props.spacing
}
}
const {classes} = createStyleSheet(styles, {
classes: {
static: 'static-0-0-1',
mixed: 'mixed-0-0-2'
}
}).attach()
```
## Todo babel plugin
- [x] Identify injectSheet(styles, options), createStyleSheet(styles, options) calls, make it customizable for different function names.
- [x] allow to pass jss config to the babel plugin
- [x] extract static styles object literal
- [x] extract static styles from the reference
- [x] extract any value from reference
- [x] extract sheet options if provided
- [x] extract sheet options from reference
- [x] extract sheet options nested properties from reference
- [x] create jss with plugins => createStyleSheet(styles, options).toString()
- [x] insert static css as a `@raw` rule into the styles declaration
- [x] remove original static styles
- [x] pass classes map from static sheet as options
- [x] math expressions
- [x] function call results
- [ ] css preprocessing pipeline (with postcss)
- [ ] autoprefixer
- [ ] babel like theming configuration over file system in any directory????
## Todo core
- [x] implement option `classes` to createStyleSheet
- [x] implement`@raw` plugin, add it to default preset
- [x] make a bench comparing `@raw` with equivalent style objects
- [ ] docs
- [ ] blogpost?
## Todo webpack plugin
- [ ] identify `@raw` rule
- [ ] extract css
- [ ] remove the rule
- [ ] provide the css to webpack so that other loaders can use it (tbd how)
## Future enhancements
- Think of potential solution to the problem: `{padding: (props) => props.spacing, paddingLeft: 10}` after compilation paddingLeft will be overwritten by padding since it will have higher source order specificity
- If static CSS is used without critical CSS over SSR, dynamic styles are not part of the static bundle and styling is incomplete. Think of a strategy to warn/require default values for dynamic styles.
- a demo app with webpack/postcss/css-modules/autoprefixer
- When there are no dynamic styles, remove all jss runtime code from the module
- When function values/rules are not using props and can be statically extracted (see linaria)
- Separate entry point `jss/static` for a reduced version of jss which does not include any plugins etc logic, since it is all preprocessed (unless we can treeshake it???)
- Remove unused styles or warn when any detected, see [this](https://github.com/jaredly/stylecleanup/blob/master/analyzeFile.js) and the [article](https://jaredforsyth.com/posts/analyzing-javascript-with-babel-traverse/) for e.g.
## Some inspiration can be taken from
https://github.com/4Catalyzer/css-literal-loader
https://github.com/callstack-io/linaria
https://www.npmjs.com/package/extract-jss-webpack-plugin
Contributor guide
Assessment
This issue has not been assessed yet.