Open kof opened 7 years ago
Perhaps inspiration can be gotten from babel-plugin-css-in-js.
The only significant downside with this plugin is that usage with webpack-dev-server (and hot module reloading enabled) does reload the page, as compilation is done in two steps.
It's definitely a good improvement, but it can also be made better.
Additional thoughts: if we are not allowed to use any dynamic capabilities like function values etc which can access render time variables, why not put js styles in separate files, name them something.styles.js and just write a small script to extract them into css files, it is a few lines of code and not worth creating a package/library for it.
You would need to
Update:
As far as I understand, having the static styles in a different file would essentially be the same as any SCSS/SASS file, except in JavaScript. The main benefit being that you don't need to set up any loaders and linters for those.
It's still a very nice improvement, but for me the first reason to use JSS is to eliminate unused styles from being present in whatever is served to the user. Dead code elimination simply doesn't work with CSS (unless I missed something) and with JavaScript it's already present (provided you don't mess it up yourself). Do you think that would still work with separate JSS style files?
There are 2 types of unused styles:
Currently we don't do any of these. Uglify will not drop any styles property because it doesn't know if a corresponding classes.rule is used or not.
For SSR we could add something to JSS, evtl. as a plugin for e.g. using getters or proxy that can mark rules as used. In that case separate file or the same doesn't matter.
In case of dead code, there are 2 possibilities:
Define each rule as a separate variable: var btnCls = css(...) so that uglify can see an unused reference. Also eslint has a rule for that. This requires a different API.
Write an eslint rule which is smarter and can check for usage in classes map. It will have to know jss, react-jss, styled-jss interfaces. It can as well work with external files.
Update the original description, since I see that we can actually keep both static extraction and dynamic styles accessing the runtime.
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
I think there are 2 ways to handle this:
I think the first solution is the most logical solution for initial implementation and eventually, the plugin can get smarter about it.
@satya164 I was thinking to not evaluate function values at all and always keep them dynamic and warn the user if his ordering is going to be broken, based on prop names and dynamic values.
Yeah, that's mostly what I meant by the first one :) But no reason to get smarter in future and handle it as well :)
Updated again, I figured out with help from @giuseppeg that
@raw
rule will be handled by a new plugin, which will basically just take the string as it is and render it, this should be 0 processing overheadHi, Is there any timeline so we can use this in production?
@kof Isn't extracting styles during webpack compilation too overcomplicated? Maybe extracting static styles during server startup to one big sheet and adding information about 'critical' classnames to components uuids will be better? I think that creating hash with components class names improve hydration performance - client won't have to manually remove SSR stylesheet after hydration
Consider this:
const {css} = createSheet();
const {classes} = css(
{
base: {
display: 'initial',
background: 'red',
},
green: {
background: 'green',
},
},
);
const Component = () => <div className={classes.base} />;
const CSS = await sheet.compileCSS();
// which compiles to something like it:
{
__styles: `
.c0 {
display: initial;
background: red;
}
.c1 {
background: green;
}
`,
...
[componentUUID]: {
base: 'c0',
green: 'c1',
}
...
}
runServer(CSS);
Any update on this?
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,:
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
Todo babel plugin
@raw
rule into the styles declarationTodo core
classes
to createStyleSheet@raw
plugin, add it to default preset@raw
with equivalent style objectsTodo webpack plugin
@raw
ruleFuture enhancements
{padding: (props) => props.spacing, paddingLeft: 10}
after compilation paddingLeft will be overwritten by padding since it will have higher source order specificityjss/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???)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