Hacker News new | ask | show | jobs
by mercer 3369 days ago
I have a slightly-related question for those of you familiar with Webpack, css modules (css-loader/style-loader), and perhaps React as well: is there any reason not to use the 'default' approach where the styles for the components are simply inserted in a <style> (with unique, generated classnames)?

To be clear: I don't mean philosophical reasons. I personally love letting javascript deal with the 'cascading' part and I don't have a problem with the idea of having styling embedded in the final page.

What I'm curious about is if this has any kind of negative impact on performance, bandwidth, etc. Because the CSS is loaded on the component level, and because Webpack 2 does tree shaking, the page will be guaranteed to only contain CSS for the components that are on the page. And if I'd 'lazy-load' parts of the app, I'd get that benefit for my CSS as well with no extra effort.

On the other hand, any benefits of having a compiled (and hopefully cached) bundle.css are offset by the need for an extra request for the css file, as well as the very likely situation that there'll be a bunch of unused css in that bundle.

Am I missing some drawback to the above-mentioned approach?

3 comments

When you're using a loader, the CSS still exists, it's just a big string in your JS bundle. By default, I believe css-loader/style-loader will use cssnano to minify the CSS within your bundle.

What will be very interesting in the coming years (as the work gets done around it) is "full css" optimization. That is, when you know you have all of the styles for the whole page available to the minifier. If the minifier knows that no other CSS is being loaded, it can do a lot more work to remove and merge rulesets. In the case of styles bundled with Webpack, common CSS could be reduced even further, after tree shaking has taken place.

In the long run I think we're more likely to end up with a full js-based styling approach that, similar to JSX, might look like CSS but really directly styles individual nodes and 'manages' them.

But this is probably quite a ways off.

The tricky part is handling things like hover states and pseudoelements. I think scoped CSS and shadow DOM (and other new techniques) will probably be the key to making this work long-term.
<style> tags in the middle of the DOM often have a rerendering penalty (most browsers force an entire page rerender each time they encounter one).

In a past life a website I worked on had a huge browser paint performance and content flash issue that was eventually cleared out by moving all the styles out of <style> tags in the DOM.

Most webpack loaders put them in the <head>
Fair point. Once packed into the <head> is better.

There's still a care to be taken when using <style> tags in development. I know developers don't always respect development performance (because it's just development), but that performance can still matter: to you in your debug cycle time, and also sometimes bad performance in development masks bad performance that will impact production (and developers don't notice it because it "always performs that way when I test").

For that reason, bringing the aside somewhat back on topic, I often prefer to use minified stylesheets/JS in development and trust sourcemaps to do their job when I need to debug them.

Embedding css into a webpage forces this css to be loaded every time. Even if the css only contains what's needed for the page, it can still be a lot. Caching it is just common sense. I think if you try and calculate, there will be a lot of bandwidth saved if you separate css into a file.
Not true. The CSS is inlined as strings in the js file, and benefits from caching just as much as the rest of your templates (this is for single-page apps).