How do we make “styles in components” play nicely with server-side rendering?
I was at ReactEurope last week, and thoroughly enjoyed Michael Chan’s talk on how and when to use inline styles in components, and when to use css.
If you haven’t seen it, watch it now, it’s great.
Back? good. I’ve been following this space all year but Michael basically shoved me over the line that Thursday morning in Paris.
As someone who works on open source react.js UI components, I love the idea of inline styles. All the concerns about preprocessors, supporting less vs. sass, themes, build processes and so on just disappear. Want my component? just use it! no worries about distibuting css. Want to change the theme? extend this object! so simple.
Now, I don’t do a lot of server-side rendering (yet). But one of the things that I really love about React is that it has a good solution when server-side rendering is important.
And regardless of whether I render on the server in my projects, if others are to be able to reuse my components I have come to learn they will want to render on the server; and if they can’t, my work is less valuable to the community as a whole. Who would want that?
So let’s talk about it.
Well, one, really. If you render a component to an HTML string and it’s got a stack of inline styles, it’ll quickly bloat your source code. What’s worse is that if you render a lot of components the impact is significantly greater.
It basically punishes you for using more instances of your component on a page. Authors are incentivised to use less styles, and users are incentivised to use less components. This is not freedom.
This is something CSS solved long ago, when we stopped having to use <font> tags to style our markup. Declare a style once, and you don’t add page weight or complexity if you use it ten or a hundred times.
External stylesheets also solve other problems; they can be cached, for instance, which would be very important for a blog or news site rendered from React components.
… but is this really a problem?
I’ve heard people dismiss this issue. Compression algorithms eat repetitive code for breakfast. On mobile, latency is your enemy (not download speed) so less requests is more important than serving a smaller html file. Nobody needs to be able to read your source code.
I’m not on board. Until someone makes a more compelling argument in favour of ditching html-from-the-server (preferably someone with authority, like Google or Yahoo) I’ll continue to strive for a good code/content ratio with proper markup and followable links on sites where I care about SEO; and I’ll do my best to make my sites accessible to as many visitors as possible.
I did come up with an idea at the conference while talking to Michael Jackson, co-author of react-router — a project that has put a lot of effort into making server-side rendering work for React.js websites and apps.
What if we extended React.renderComponentToString() so that, after generating the DOM but before serialising it, it walks the tree capturing `style` attributes and replacing them with generated `className` attributes? It could then return a second object containing the classNames and their values. We’ll call this React.renderComponentToStringAndCSS()
The style values would be sorted and deduped of course, I suspect we could use something like immutable to make this really efficient.
The css object could then be used to write out a stylesheet, which could be served with a filename that’s a hash of the contents, making it possible to permanently cache for future requests.
Notice I’ve also added a new data attribute to those React already uses; data-react-classname would let React swap the className out for the generated styles when the component is rehydrated on the client.
I haven’t had time yet to experiment with actually implementing React.renderComponentToStringAndCSS(), but based on conversations with some of the React team it should be possible without too much difficulty.
If anyone is interested in tackling it, or has other ideas (or thinks my concerns are truly redundant) — please let me know!
A quick note: I don’t believe a solution dependent on a specific build process — I’m looking at you, Webpack — is a valid solution for the entire community. It’s fine for your own projects, but as a component author I work hard not to force my opinions about build pipeline or tooling on others!
The point of this post is to get feedback, and start a conversation about how we might eventually solve the challenges of server-side rendering if we continue down the “styles in components” route.
Which I really hope we do; otherwise we risk fracturing the community if component authors stay on Michael’s train, and developers with real-world requirements for server-side rendering have to get off early.