NEXT: CSS

Well not quite. There’s also CSS. I have a lot of opinions on this one. But I’ll save most for the readme to Extract CSS Chunks Webpack Plugin.

I also have answers. It boils down to:

the fact that Using CSS Modules already is “CSS-in-JS”

Wasting cycles on both the client and server rendering CSS is just that — a waste!

Cacheable Stylesheets are just that — cacheable!

HMR is a must

is a must And: guess what? If you can chunkify your CSS just like your JS you don’t need to generate “render-path” CSS to send the least amount of bytes over the wire. In fact, you send less!

See with truer CSS-in-JS solutions like StyleTron, Aphrodite, etc, all your CSS is represented in code anyway, aka javascript. So you may be sending the smallest amount of CSS possible, but you’re sending it all down in the form of javascript IN ADDITION and NO MATTER WHAT.

It also turns out that if you can statically chunkify your CSS, you’ve achieved the 80–20 rule: you’ve achieved the sweet-spot of 80% optimization in how little CSS you send over the wire. See, the real problem is, for example, sending over the CSS of your private user panels to your public-facing site or vice versa. If you have many sections/panels, your CSS exponentially grows and is sent everywhere. However, if you have a straight-forward mechanism to breakup your CSS into chunks by sections you’ve solved 80% of the problem, if not more.

Again, you can read the Extract CSS Chunks Webpack Plugin readme for a lot more thoughts on this. It boils down to static determination of what CSS to send being a damn good solution. Going after that last 20% by sacrificing render cycles and having to use custom hocs — IMHO — is nitpicking and results in diminishing returns.

Did I mention when you do in fact request async chunks, those chunks have the CSS ready for injection embedded in the JavaScript again? See, it creates two js chunks: one without css which is sent in initial requests along with real stylesheets AND another for async requests which has CSS injection as usual! This gives you the smallest possible initial js bundles.

Did I mention — unlike the original Extract Text Webpack Plugin — it supports HMR! “USE THAT SHIT!”

MORE

Yes, I got more. You wanna make your own Async Component because neither React Loadable nor React Universal Component serves your needs?

Well, the core aspect for all this “universal rendering” goodness has been abstracted/extracted into its own package:

And what you make with it will flush chunks along with Webpack Flush Chunks just as easily as React Loadable and React Universal Component.

This time, I really won’t say anymore. USE THAT SHIT!

REACT UNIVERSAL COMPONENT

But let’s not get ahead of ourselves. A lot has been put into React Universal Component to make it the be-all-end-all — what I’m calling “Universal” — component. React Loadable kicked ass and this is its spiritual successor after all!

Basically everything under the sun (from PRs, issues, other packages, etc) has been included in it. With discretion of course ;)

I’m trying to think of a few noteworthy capabilities to point out (as just reading its readme probably is the best thing to do once again). Well, lets look at some code:

import universal from ‘react-universal-component’



const UniversalComponent = universal(() => import(‘./Foo’), {

loading: Loading,

error: Error,

timeout: 15000,

minDelay: 300,

chunkName: ‘myChunkName’,

onLoad: module => replaceReducers({ ...reducers, module.bar })

key: ‘Foo’ || module => module.Foo,

path: path.join(__dirname, ‘./Foo'),

resolve: () => require.resolveWeak('./Foo')

})



export default ({ isLoading, error }) =>

<div>

<UniversalComponent isLoading={isLoading} error={error} />

</div>

et voila!

A 2 argument API like Next.js’ dynamic , and an options argument with a super clean surface like Vue’s, which itself is also inspired by React Loadable.

Not all those options are required. In fact they are all optional. You could even have an async-only component which as you’ll read at the end of the readme — thanks to Async Reactor — may very well be the basis for an even further evolution in universal rendering.

There’s still a lot more than meets the eye. For one, you can wrap the resulting <Universal Component/> in a HoC that does data-fetching (i.e. some separate async work) and re-uses the Loading component (DRY) via the isLoading prop, etc. It makes for a perfect match for Apollo and the like.

Both promises will run in parallel, and the same loading spinner will show.

You can use onLoad to utilize other exports from the module to do related work: replacing reducers, updating sagas, perhaps something with animation, etc.

If 15000 milliseconds is reached, the error component will show. Thank you Vue.

The minDelay is different than what React Loadable has. It results in a more responsive component. Instead of waiting a few ms to see anything, it always shows the spinner immediately. And you can set the minimum amount of time before the async component can show. This also helps with animations. Say your page with the spinner in it slides in and the sliding animation takes 500ms — well, now youcan avoid rendering jank from messing up your sliding animation by prolonging the page update until the sliding animation is done. It also better solves the original problem of avoiding flashing between the loading spinner and the component since, no matter what, they could appear around the same time without a minimum delay you can control. The readme has you covered there as well. This is just off the top of my head.

It has support for HMR which React Loadable has yet to attain. Same with all your async CSS if you’re using Extract CSS Chunks Webpack Plugin.

Lastly, instead of being restricted to promises with import() you can use a function that calls require.ensure with a callback, which gives you the additional capabilities of require.ensure . You can actually do all the stuff Async Reactor does including data-fetching in it. More importantly, the props are passed as an arg so you can determine what data to fetch dynamically. This is a story for another day, but checkout Async Reactor as you review this stuff. Even if you’re very familiar with React Loadable, but you haven’t checked that, it will likely throw you for a loop [in a very good way].

The interface proposed by Async Reactor has a lot of potential for becoming the idiomatic future of combination async/sync “universal” rendering.

Basically it has potential to be the greater NPM community’s answer to Next.js’ getInitialProps if it has a recursive promise resolution system like Apollo. Read the end of the readme to hear me go off on what I think is the future.

And did I mention: you don’t have to use it in a sever-rendered scenario. That’s just where it shines. If you read the readme (and compare it to Async Reactor), you can do some pretty cool things with the async component argument. Async-only is a primary use case for this package as well.

CONCLUSION

USE ALL THIS SHIT. THERE’S FAR MORE YOU CAN DO AS YOU’LL READ IN THE READMES. SO MANY BASES ARE COVERED. GOODBYE.

PS.

Did I mention Webpack’s “magic comments” feature which just came out is fully supported as well? Just use it and name your chunks and call flushChunkNames instead of flushModuleIds and pass chunkNames to universal(asyncWork, { chunkNames }) to make it work. It will save your server some cycles from doing all I had to do to jump through hoops to cross-reference module IDs with stats.

Richard Scarrott’s Webpack-Hot-Server-Middleware (HMR on the Server) is world class. Examine its usage in the boilerplates. It’s important and related because this is supposed to be the most modern [non-restricting] React/NPM developer experience for serious apps. The boilerplates themselves — I might add — are pristine. Developer experience goodness everywhere, hopefully you find it all to be idiomatic. Enjoy!

> For more idiomatic javascript in Reactlandia, read:

Tweets and other love are much appreciated. Find me on twitter @faceyspacey Want to stay current in Reactlandia? Tap/click “FOLLOW” next to the FaceySpacey publication to receive weekly Medium “Letters” via email 👇🏽