We need a way (probably babel transform?) to extract and precompile the static styles of our components!
Extracting static styles is actually not what we want, we want to pre-parse the CSS in a build step but leave it in the JS: See this comment
Has anybody done this before? I know I haven'tâŠ
Take a look at CSJS, similar template strings construct and has a pipeline to statically extract styles
Good tip, this doesn't look _too_ hard! https://github.com/rtsao/csjs-extractify/blob/master/index.js (browserify thoughâŠ)
I'm curious about the motivation behind. Shouldn't we aim for the opposite?
What I mean is, injecting as small bits of CSS as possible in the document in order to:
Does it scale up?
@oliviertassinari the reason is that once certain styles are defined they can never change. Some component X will always have some chunk of styles applied. So we can basically parse over the files and extract that into a static mapping, which is effectively all a CSS file is anyway :)
If you're doing SSR, you _might_ prefer not to do this, but if you have a fairly common set of components across the entire site it could be better to extract all _those_ into a static, separately-cached CSS file. But not everyone is doing SSR.
As for bootstrap JS & CSSDOM parsing, serving raw CSS is always going to be faster than serving JS, executing it and dynamically injecting styles. Browsers have been optimising their CSS parsing since... CSS became a thing. So I'd like to make use of as much of that as is possible.
With the content of the stylesheet classes changing between renders (because they are based on props) how is this going to work?
Whatever CSS is extracted, is only for the initial state? Looking at how it works it seems each different render wich results in a different style output will also result in a new classname..
I don't see an easy way of pre-generating all possible classes.
take this style:
styled.button`
background: ${(props) => props.theme.main || 'palevioletred'};
border: ${(props) => (props.width || 2) + 'px'} solid ${(props) => props.theme.main || 'palevioletred'};
`;
Potentially props.width could be any Integer, resulting in infinite classes to generate?
As @tizmagik pointed out, CSJS seems rather similar and also support interpolation inside the template strings, so might deal with the same issue?
I'm trying to understand how this might work, would love to contribute in some way.
This is _probably_ possible to do with the static portions of styles, but, as mentioned by @ndelangen, I'm not sure there is a way to handle anything that uses ${} inside the template.
I'm wondering if Babel may not be the best tool for the job either way? Few problems I can see with that:
Babel transforms run per-file. So, to share style information (so you can get 1 final stylesheet across all JS files), you'd need to write to a tmp file along the way. This would probably become a major problem when you introduce incremental compilation (Babel's watch mode, for example)..babelrc, and then just dump to some file the user then includes in their bundler.My suspicion is that something like this might be _much_ better suited for Webpack + Browserify plugins. I believe you'd be able to solve both 1 and 2 above.
I think extracting just the static portion of styles is enough to start with. @DrewML you might be right we might need something more build-tool-specific like a Webpack/Browserify plugin to actually _do something_ with the output css, but as a first step I'd like to transform a single file and extract the css, and so babel seems like the obvious choice, right?
as a first step I'd like to transform a single file and extract the css, and so babel seems like the obvious choice, right?
Yep, definitely. I went to go mock up an example for y'all before I left my comment, but then I realized I had been using JSCodeShift instead of Babel đ - whoops!. Having said that, definitely possible to update the template literal to _only_ have the dynamic bits.
Knowing nothing about this project (besides that it looks awesome), what would be your suggested approach, while extracting the static styles, to get a dynamic classname onto that component. Need _something_ once those styles are ripped out to associate them with the component.
I've been thinking about content addressable css rules which could be useful here. Each rule that is identified as being static could be output to a stylesheet with a classname that directly maps to the rule contents itself, then you apply that classname to the component. This is nice because you could write the same style rules all over the place and they would only ever end up in the extracted css once. Implementation wise you could build up a { classname: ruleContent } hash and just set every rule, then parse the object into actual css using one of the many tools for that on npm.
Yep these are the lines that currently do that logic: https://github.com/styled-components/styled-components/blob/d112ff7bd1bc211e62c29aa348412560737a9afb/src/models/ComponentStyle.js#L37-L43
.selector { ... css ... }Then we'd just need an API to get that on to the class at runtime, but that should be easy enough.
@SeeThruHead yeah I've wanted to do that!! But I decided we had to strictly preserve the ordering of definitions. If you have two conflicting rules on an element then using content-addressable css means the one defined _later_ would apply. So you'd need to resolve all the conflicts per component, then only inject the CSS classnames that "win". So I gave up đ
This was actually issue #1 on this repo, and we've gone through a few iterations to make sure that the CSS you get is in the same order as the Styled Components you write. But if we could resolve things ahead of time it would make the output pretty amazing. And the extracted CSS would be super minimal.
If you're up for trying, let me know! I can throw you all the edge-cases that stumped me đ
Here is a not-so-pretty example of a Babel plugin that gets the static pieces (it's not removing them from the source for this example). Comes fully-loaded with a million edge-cases, but it gives you a starting point. Open console to see output.
đ this is an excellent start!
I think it's safe to assume that if a line has a ${} on it it can be treated as dynamic, yeah.
Then would you strip out all the "static" pieces and leave the dynamic lines in for runtime evaluation? This looks really promising...
Potentially if proptypes for the prop contains a list of potential values for the prop, we could use it to pre-generate these dynamic classes as well?
Starting with just extracting static styles seems like a good idea that can be expanded on later.
Then would you strip out all the "static" pieces and leave the dynamic lines in for runtime evaluation? This looks really promising...
Yes exactly.
@DrewML that's an amazing start, wow!
This might be slightly off topic, but extracting static CSS is going to result in a FOUC when server rendering styled-components. The browser will apply static CSS immediately, then apply dynamic CSS once JS has evaluated. That kind of defeats the purpose of doing it in the first place.
I worry that mixing both dynamic and static CSS in the same declaration might be more confusing than useful. Is there another approach that makes it obvious to developers when they can write static vs. dynamic styles?
Historical note, learning about this FOUC was why I've somewhat abandoned css-loader#287.
FOUC could be handled by making the resulting React component have state, and only render itself once the CSS is in the DOM?
@ndelangen yeah! I imagine a lot of function interpolations will be of the form props => props.val, props => props.flag && 'val' or props => props.flag ? 'value1' : 'value2'. Sounds pretty achievable to be able to take expressions that have no side-effects and pre-calculate the potential set of values that will be in the output.
@chrislloyd I don't think that FOUC is real. If you're doing SSR for the markup, then extract the "rendered" CSS from rendering the components alongside the <link href="extracted.css">. If, like in react-snapshot, you're pre-rendering using JSDOM or Phantom or something, when you take a snapshot of the DOM you'll get the <style> tags from rendering inline. Then again, if you're doing either of these, you might not even need to use extracted.css. In any case, I don't think it's so much of a potential problem.
A benefit I can see of extracting static styles is to prevent flickering when doing server-side rendering. Right now, you would see very basic DOM elements render with minimal, if any styling, and most of it would flicker in when the js bundle loads and inserts the <style> classes.
If we could inline static styles as the components' style prop, then the differential between the initial render from the server and the one driven by the client when it loads would be smaller and potentially reduce the flicker substantially.
_Edit:_ Sorry, just noticed the comment above. That makes sense as well, inlining the actual CSS in the <style>.
@geelen does that mean styled components will only support jsdom/phantom style SSR?
@geelen does that mean styled components will only support jsdom/phantom style SSR?
No, not at all. What makes you think that? We're going to extract a static .css file, that has nothing to do with jsdom or phantomjs!
If we could inline static styles as the components' style prop, then the differential between the initial render from the server and the one driven by the client when it loads would be smaller and potentially reduce the flicker substantially.
This is an interesting proposal that I didn't realize was a possibility. The one issue I see is that more complicated styles (e.g. media queries) won't be there for the initial render, but this might be an interim solution until we've built the static style extracting/without a build process⊠Hmm.
Helmet doing a nice thing with server usage:
https://github.com/nfl/react-helmet#server-usage
Maybe it's possible to doing something like that
So, I've thought about this a lot over the past week and come to realize: extracting static styles to a separate stylesheet is the wrong solution.
The two goals we want to achieve here:
As it turns out, we already do number 2, server-side rendering with styled-components is quite awesome as-is! But extracting a static stylesheet won't help us with 1., and will remove (or very complicate) our ability to do awesome server-side rendering.
Looking holistically at this, what we actually want to do is:
styled-components/no-parser) that handles our internal parsed-representation of CSS and removes PostCSS from the bundleThis should very much be doable with just a babel transform, and will enable us to shave off the entire size of PostCSS while still having amazing server-side rendering support.
I'll start looking into this next week, I hope to get it done sometime within the next 2-4 weeks!
I did an experiment that does something very similar to this, and has a babel plugin. It might help here.
To get around the temp file issue, I just concatenated to the CSS file, but put comment markers for each JS file in the CSS file. If you tried to add a JS file that already existed in the CSS file, it would throw an error saying to delete the CSS file and try again. This was the best I could get.
One thing with trying to split your CSS into dynamic and static content is that the static properties will be referenced in className and the dynamic in style. That means the specificity of dynamic properties will always override the static properties.
Just for the sake of discussion though, it might also be possible to get around dynamic string interpolation by using CSS properties to map to React properties. Just a thought!
const Button = styled.button`
color: black;
&[large] { font-size: 18pt; }
&[color=âblueâ] { color: blue; }
`;
<Button large />
<Button color=âblueâ />
@jacobp100 you'd want to inject dynamic css into the dom inside a style tag, with the same classname as that in the static css. the only difference is you could dynamically generate the content in the style tag, and update it.
So if the CSS is not extracted into a style sheet, it means that users with
JavaScript disabled won't have styles? Or are the server-side-generated
styles also injected in
It will make the download of each page a bit bigger, but for SPA apps
that's probably not an issue. For static sites, it might be more annoyingâŠ
Or are the server-side-generated styles also injected in
?
They are.
The two goals we want to achieve here:
@mxstbr I think the goals are a bit wrong. Actually, the main goal of the styles extraction is to allow browser engine deal with CSS ASAP and not wait for the JS bundle load and runtime. Calculating styles only in runtime has lots of performance drawbacks. These have been pointed out already in this thread here https://github.com/styled-components/styled-components/issues/59#issuecomment-253596470 and by @geelen
As for bootstrap JS & CSSDOM parsing, serving raw CSS is always going to be faster than serving JS, executing it and dynamically injecting styles. Browsers have been optimizing their CSS parsing since... CSS became a thing. So I'd like to make use of as much of that as is possible.
I think, this can be a blocker for many users. At least it is for me ATM.
For SSR we are just injecting the critical CSS into the HEAD, so there is no need to wait for JS bundle load and runtime. Doesn't get faster than just-critical-CSS-in-HEAD! (in fact, generating an external CSS file would heavily slow down the rendering, so it'll have a negative performance impact)
For non-SSR we _could_ create a babel transform that extracts static CSS but due to the dynamic nature of our styles it's not quite as easy as "Just take out the string of CSS and put it into a file". I will build it eventually, but it will take some time.
Much more important than extracting is pre-parsing the CSS at build time so we can kick PostCSS out of the bundle. (just extracting static CSS won't be enough to kick it out since you still need to parse the dynamic stuff) Currently styled-components is ~18kb min+gzip of which ~10kb is just PostCSS.
If we can somehow pre-parse the CSS and put it into a state where we don't need to ship a full CSS parser anymore that'd be a much bigger win than extracting a static CSS file for now. It's also easier đ (the other option is to write a new CSS parser which weighs less than 1k min+gzipped, but I'm not sure if that's possible, /cc @ai)
(we're focussed on #227 and babel-plugin-styled-components at the moment, which will make the development experience better and fix some ugly bugs by adding per-component-classnames. Afterwards I'll look further into the pre-parsing/extraction stuff)
I think, this can be a blocker for many users. At least it is for me ATM.
It shouldn't be! Why is that blocking you? Why does it affect you so much?
>
If we can somehow pre-parse the CSS and put it into a state where we don't
need to ship a full CSS parser anymore that'd be a much bigger win than
extracting a static CSS file for now. It's also easier đ (the other
option is to write a new CSS parser which weighs less than 1k min+gzipped,
but I'm not sure if that's possible, /cc @ai https://github.com/ai)
This is an interesting idea, but it would require the props functions to
also return pre-parsed css.
Perhaps this can be achieved by only allowing interpolation of the result
of css``, which would imply that interpolation needs to include the
attribute at all times. Combine that with build-time evaluation and we
might get somewhere.
Even then, the total resources saved would be 10KB on the JS bundle and
some cpu at runtime. Nothing earth-shattering, reallyâŠ
Even then, the total resources saved would be 10KB on the JS bundle and
some cpu at runtime. Nothing earth-shattering, reallyâŠ
Exactly, that's why it hasn't been my focus so far. We're going to get it done, but it's not the highest priority issue on the list right now!
That being said, if somebody wants to help sketch this out and submit a first discussion/RFC... _winkwink_
Do you allow arbitrary interpolation? I.e.
const interpolatedRule = 'color: red;';
const Button = styled.button`
font-weight: bold;
${interpolatedRule}
`;
If not, you could do the un-nesting, autoprefixing, and minification in babel.
const hoverColor = 'blue';
const Button = styled.button`
color: red;
&:hover {
color: ${hoverColor};
}
`;
to,
const Button = styled.compiled.button`
.SCOPE_STYLE_NAME {
color: red;
}
.SCOPE_STYLE_NAME:hover {
color: ${hoverColor};
}
`;
And even smaller with minification.
I also think in theory, as long as they donât do interpolation in a component, you can completely extract that componentâs css into a separate CSS file.
We do at the moment, but we probably won't do forever due to security concerns (CSS injection) and what you just posted. If you want to go ahead and start a WIP/RFC that'd be much appreciated!
@mxstbr: Much more important than extracting is pre-parsing the CSS at build time so we can kick PostCSS out of the bundle. (just extracting static CSS won't be enough to kick it out since you still need to parse the dynamic stuff) Currently styled-components is ~18kb min+gzip of which ~10kb is just PostCSS.
I made a babel plugin a while ago for regular inline styles (I use this in React native). it converts css string into JSON at compile time babel-plugin-css-to-js
This is how it works
css`
margin: 20px;
padding: ${constants.padding}px;
font-size: ${props => anyArbitraryExpression};
`
Transforms to
{
margin: "20px",
padding: constants.padding + "px",
fontSize: ((props) => anyArbitraryExpression)
}
As you can see, dynamic properties are handled properly, it would be up to styled-components to actually evaluate the function itself, which would have the return type of a number in this example.
I definitely think this can be utilized to remove the run-time dependency of postcss. The only problem is that this requires the template literal identifier to be constant (css in this example). It's too hard to figure out if styled.button`whatever` is css or not, at compile time. This would mean the api might have to change to something like styled.button(css`whatever`)
It also has the benefit of being able to apply postcss plugins beforehand, so for example you can bake in autoprefixer at compile time
I made a babel plugin a while ago for regular inline styles (I use this in React native). it converts css string into JSON at compile time
That's awesome @JakeCoxon, thanks so much for showing us that!
@vdanchenkov we should steal this for babel-plugin-styled-components maybe?! We could pass the JSON structure to another private API possibly, that way we avoid any external API changes. What do you think?
I'm not sure if it worth it, given we migrate to stylis and the fact that precompilation will unlikely support all the usages currently possible.
Yeah I've come to the same conclusion. We'll get back to pre-compilation for v3 when we've figured out how to make sure all interpolations work!
I've started working on this over at babel-plugin-styled-components.
Basically as @mxstbr said, the first goal is to preprocess the CSS into a state, where we don't need to bundle stylis at runtime, for people who'd opt-in to use the babel plugin.
If we can somehow pre-parse the CSS and put it into a state where we don't need to ship a full CSS parser anymore that'd be a much bigger win than extracting a static CSS file for now.
The steps I'll take are basically: writing a naĂŻve CSS AST parser (done-ish), transform the template strings with their interpolation into an AST, transform the AST into a JSON that only needs minimal changes on the client. The AST has the additional advantage that extracting static CSS will eventually be easy as well. :tada:
I hope I can get it done soon :smile:
@philpl This looks great!
What was the resolution on arbitrary style interpolation? I think you could allow either interpolating whole styles, or interpolating values. I.e.
const styles = styled.div`
${mixin}
color: ${color};
`
But you have an edge case, where color is red; background-color: green. Is this an edge case we should ignore/disallow?
I believe that edge case is a recipe for disaster. I further believe that
${mixin} should be the result of css... and not an arbitrary string.
Likewise, ${color} (and ${p=>p.color}) should result in a valid attribute
string, and if the result is not valid, the whole line should be deleted.
Another edge case: what about csscolor: rgba(${p=>p.commacolors}, 0.5)?
(commacolors being e.g. "23,45,67")
OTOH, CSS is pretty forgiving about invalid things. So perhaps we should
first step back and figure out what a pre-processed result looks like, so
we can determine what would be good and what bad.
For starters, the pre-processed result should be easy to convert to valid
CSS, so perhaps nesting is a pre-processing step?
What are currently the big resource hogs in processing the styles?
On Wed, Jan 25, 2017 at 10:29 PM Jacob Parker notifications@github.com
wrote:
What was the resolution on arbitrary style interpolation? I think you
could allow either interpolating whole styles, or interpolating values. I.e.const styles = styled.div
${mixin} color: ${color};But you have an edge case, where color is red; background-color: green.
Is this an edge case we should ignore/disallow?â
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/styled-components/styled-components/issues/59#issuecomment-275238576,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AADWlsfaUK_tG3ufMdfrrOqvifdVvQk1ks5rV76xgaJpZM4KVrq4
.
@jacobp100 @wmertens I do think interpolation that output entire rule sets or declarations shouldn't be allowed going forward. They open the door for a lot of edge cases and some nasty vulnerabilities. Interpolation should only return a partial or complete value literal.
That does add a runtime check though, that checks for this, but I think that's fine.
@wmertens I think if the user messes up the values that interpolation return, we can't really do anything to prevent it at compile time. Preprocessing the css helpers arguments is something we can do, and could be used to inject additional rule sets, but as soon as that's inside a big function, that gets hard to parse, since we'd need to find the result of the function in the babel AST...
All in all, for now I'm gonna experiment with as few constraints and as little code as possible, and go from there :)
@philpl awesome, thanks for kicking this off!
@jacobp100 @wmertens are both right re: interpolations. At the moment we YOLO the entire result so there's absolutely zero restrictions on what someone can output. I wanted to keep it flexible to see what came up as a valid usecase. It's one of the benefits of using strings over objects, you can combine and insert chunks of text much more easily than merging a data structure.
But I agree that it'd be great to strip the CSS back to the simplest possible representation that requires the least amount of run-time overhead. And the only real barrier is restricting what interpolations are treated as valid. Here's what I think we should support:
styled.div`
${ ruleSets }
property: ${ value };
other-prop: rgba(${ partialValue }, 0.5);
${ selector } {
...
}
`
ruleSets â generated by calling css. Can have multiple rules, nesting, etc etc. But can only appear where a property: value; or a selector { } would be valid.value â any valid CSS value i.e. no ; or {} allowed except in quoted url(" ... ") expressionspartialValue â same rules as value.selector â any valid selector. &s and ,s should be handled as if they were written literally, so nesting can't be known until this gets evaluated.All of these interpolations can be functions that return values based off props or theme so there would need to be some runtime validation.
Have I missed anything?
@geelen I think that sums up all the current possible (and valid) use cases quite nicely. It obviously just comes down to injecting the interpolations at the right place in the AST, since most of the restrictions (interpolations can't contain ;, {, or }, except values which can contain these in quotes) can only be applied at runtime.
Are there any attributes or selectors that are super weird to parse?
Otherwise they can be validated at runtime with regexes, yes? Plus, the
browser also validatesâŠ
Right now, styled-components is 87K minimized in my app, it is totally
worth it, but if we could eliminate a bunch by not having real css parsing
in the runtime, that'd be great.
With the above restrictions, nesting and comments can be handled by the
babel plugin, and the rest at runtime, right?
Can the browser be leveraged to check CSS rules before they are applied?
Like, making a css object and reading it back (I guess that doesn't existâŠ)
On Thu, Jan 26, 2017 at 1:00 AM Phil Pluckthun notifications@github.com
wrote:
@geelen https://github.com/geelen I think that sums up all the current
possible (and valid) use cases quite nicely. It obviously just comes down
to injecting the interpolations at the right place in the AST, since most
of the restrictions (interpolations can't contain ;, {, or }, except
values which can contain these in quotes) can only be applied at runtime.â
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/styled-components/styled-components/issues/59#issuecomment-275271413,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AADWlj8K7JnLsDG_YDGWBnER3FI6mm_Rks5rV-IygaJpZM4KVrq4
.
Right now, styled-components is 87K minimized in my app
Sidenote: That will be half that size already with v2 since we have the new tiny parser. Please try out the v2 branch!
I think it will be difficult to parse mixins as well as selectors. This is ambiguous, but is probably common.
styled`
${maybeMixinMaybeSelector}
${selector} {
âŠ
}
`
Yeah I've used the above syntax for a grid component. https://gist.github.com/ndelangen/da41797e9e506d6d6f1aca182d516281
@jacobp100 @ndelangen Like @geelen said, there are zero restrictions right now as to what can be injected using an interpolation, but a restriction that is becoming more likely is, that entire rulesets have to be wrapped using the css helper. This way during the parsing process, it's possible to put different restrictions on css interpolations, than on normal ones.
I haven't figured most of this stuff out yet though, so if you want to chime in, feel free to check out this WIP PR đ https://github.com/styled-components/babel-plugin-styled-components/pull/25
I was looking at this in my project. Thereâs a few differences to styled-components, but otherwise itâs the same. Firstly, weâre doing Native (you canât do interpolations for web). Secondly, we split components into those that use CSS custom properties (Dynamic Component), and those that donât (Static Component). You can ignore the second part for styled-components, but if youâre reading my code, be aware of that!
The gist of what happens is
${interpolations} into CSS comments, where ${interpolation1} becomes /*substitution-1*/decl.values as interpolated values using the interpolation from the comment to interpolation mapSo,
styled.div`
${mixinInterpolation}
color: ${valueInterpolation};
`
Becomes
styled.div`
/*substitution-1*/
color: /*substitution-2*/;
`
Where you have a substitution map,
{
'/*substitution-1*/': mixinInterpolation,
'/*substitution-2*/': valueInterpolation,
}
Then your AST looks like,
{
type: 'root',
nodes: [{
/* This will become a mixin */
type: 'comment',
name: 'substitution-1',
}, {
/* This has an interpolated value */
type: 'decl',
prop: 'color',
value: '/*substitution-2*/',
}],
}
Then you use your AST and substitution map for the following.
Youtake fragments of non-mixin code, which we pre-parse in babel, and combine it with the interpolated mixins. We have to put the mixins through a run-time helper that parses them on the client. But we have at least parsed some of the CSS.
// in
styled.div`
background-color: blue;
${mixin}
color: red;
`
// out
composeFragments([
{ backgroundColor: 'blue' },
parseMixin(mixin),
{ color: 'red' },
]);
You could also assume that the mixins are pre-parsed, as was suggested here. Then you just remove the run-time helper.
Because this is Native, we also try and do optimisations on the interpolated values, but fall back to css-to-react-native when we canât optimise it. This wonât be too relevant for styled-components on the web, but will be for styled-components/native.
// in
styled.View`
padding-top: ${large};
color: ${primary};
margin: ${shortHandValues};
`;
// out
const styles = StyleSheet.create({
0: Object.assign(
/* The bits we could parse */
{
paddingTop: Number(large),
color: String(primary).trim(),
},
/* The bits we could not */
cssToReactNative([
['margin', shortHandValues],
])
),
});
styledHelper([
styles[0],
]);
It looks like identifying all comment nodes as mixins is fundamentally incorrect, as they could be selectors.
My intent was that this should always be applied, but looking at the selector issue, it looks like it will still have to be an optional optimisation. Without the optimisation turned on, youâll just have to ignore any component with interpolated values.
I hope this somewhat helps. Itâs pretty complicated, so it's hard to get it all in one post. Let me know if you need more information.
@jacobp100 Thanks that's really helpful. I've tried out using substitutions on a separate branch, although I haven't done so using comments yet, and I'm not sure whether it's the correct road to go down to. There's a lot of things we can do in the future, but I do believe all of that stuff could become easier by having a custom, naĂŻve AST, if that makes sense?
By doing that the substitutions become quite trivial, but I'm running into other issues, like selector concatenation. If you don't mind, I'd very much appreciate it, if you could take the time to look through the ongoing PR over at the babel plugin đ
So previously I said that a mixin was ambiguous from a selector because
styled`
${maybeMixinMaybeSelector}
${selector} {
âŠ
}
`
But what if,
styled`
${clearlyAMixin}
.${clearlyASelector} {
/* If you missed it, the selector has a . before */
}
`
This is not just great for pre-parsing, it's a lot more declarative for the user.
It is a breaking change, however.
@jacobp100 you can have a look at my branch over at the babel plugin repo. The parser now just uses stylis and is already done. However, I haven't found the time yet to actually add support for preparsed css to styled-components :(
Am I right in thinking all stylis is now doing in the browser is scoping the styles? If so, I think you might almost be there.
I think it should be possible to scope keyframe constructors. We'd just need to create a code path in styled-components that doesn't require stylis for preprocessed components. Maybe something like this?
@jacobp100 global css, flat css, nested css, namespace scoping(including keyframes when enabled) & vendor-prefixing. @philpl are you trying to do something like this dynamic styles mode, pre-parse + collect & remove the dynamic parts.
@thysultan This is after the babel plugin. The aim is to use stylis as a pre-compilation step rather than on the client for file size and performance optimisations.
You can see philpl's work here. If you look at test/fixtures/15-preprocess-keyframes/after.js, it looks like we're really close to the above goal for keyframes!
@jacobp100 sorry, it's getting hard for me to sift through the github notifications. I consider the preprocessor as done for a first version. Of course there needs to be more testing involved, but I haven't completed the part of this work on styled-components itself. I really need to get onto that ;)
@thysultan this is only for preprocessing it, like Jacob said. However, it should make splitting static and dynamic styles really easy, in the future.
No worries! Let me know if I can help in any way!
@jacobi pinged you on gitter. Since I haven't done anything on implementing the preprocessed css in a while, we could definitely divvy it up, if you want
I've started from scratch on the 'v2-preprocessed' branch. It looks like I'm actually going to be done with it soon. Maybe today even? Who knows ;)
Released experimental CSS preprocessing with babel-plugin-styled-componenrs v1.1.0 and styled-components v2.0.0-9
@philpl how can we try it now
@garmjs Get the latest styled-components v2 prerelease and use the babel plugin with the preprocess option turned on ;) https://github.com/styled-components/babel-plugin-styled-components
@philpl I have styled-components 2.0.0-10 and the plugin 1.1.1, turning on preprocess complains that it can't find the no-parser exportâŠ
Oops, PEBCAK. Disregard, I had 2.0.0-4, was reading the output of yarn wrongly.
Hi all,
I'm grappling with SSR and subsequent client-side connecting, and was wondering if someone here could help me - I suspect I'm missing some very important and obvious point.
State-wise, all is well, but using style-components seems to mean that SSR HTML is immediately being updated solely because the client side 'processor' is generating a different sc-tag from the server side on component render. Am I trying to use the wrong tool for the job, or am I missing an important point?
Thanks in advance - I'm keen to get this up and running; component-scoped style seems like a very sensible idea to me!
Will
@WilliamDugdale please create a new issue and we'll help you. This issue is unrelated :)
Most helpful comment
@oliviertassinari the reason is that once certain styles are defined they can never change. Some component
Xwill always have some chunk of styles applied. So we can basically parse over the files and extract that into a static mapping, which is effectively all a CSS file is anyway :)If you're doing SSR, you _might_ prefer not to do this, but if you have a fairly common set of components across the entire site it could be better to extract all _those_ into a static, separately-cached CSS file. But not everyone is doing SSR.
As for bootstrap JS & CSSDOM parsing, serving raw CSS is always going to be faster than serving JS, executing it and dynamically injecting styles. Browsers have been optimising their CSS parsing since... CSS became a thing. So I'd like to make use of as much of that as is possible.