Over the past few weeks, I've been focused on building out the infrastructure for a new product we'll be offering at Clever Beagle soon, Pupgrades.

Because Pupgrades will be available on a pay-per-item basis, I decided that it'd be worthwhile to integrate the marketing and checkout flow into the existing Clever Beagle app (the one we use with our mentorship customers to track work on their products).

In theory this was a great idea, but in practice there was a little hiccup: the app wasn't built with SEO in mind; all of the HTML for the app was rendered on the client only. While Google has grown more friendly to client side rendering over the years and a few hacks exist to do pre-rendering of your app so search engines can see it, those techniques all leave something to be desired.

Fortunately, Meteor—the platform the Clever Beagle app and our mentorship program is based on—added support for server side rendering (SSR) last year. Instead of relying solely on client side rendering and hacks to serve up rendered HTML to search engines, now, it's possible to actually render HTML on the server-side first.

Why does that matter? Well, that rendered HTML is what Google uses to describe and rank your sites. The more accessible and visible that HTML is, then, the better.

Having worked with SSR previously in Meteor for a tutorial on our sibling site (as well as with a few CB mentees), I knew the gist of how to get it implemented. What I didn't know, though, was how to fix one of the glaring problems when implementing it: the flash of unstyled content (FOUC).

You've no doubt seen this before. When visiting a site, for a few split seconds you see the unstyled HTML show on the page and then after a few seconds see the styled version "snap in." Kind of like this:

The evil flash of unstyled content
The evil flash of unstyled content (FOUC)

Blech. No fun. Having researched this a bit, I knew that tools like styled-components—a library that helps you write per-component CSS for React—gave you a means for compiling your CSS on the server—just before you return your HTML, you compile your stylesheets and inject them into the header. The result? No FOUC!

This is all well and good but styled-components presents a unique dilemma: it's a bit cumbersome to migrate a large application to. If you start out with styled-components, it's a wonderful idea. A migration, though, has the potential to take awhile.

Looking to launch our Pupgrades offer in a few weeks, I started to bite my nails; a move to styled-components was potentially damning to staying on schedule.

Then it dawned on me: why not try something simpler. The problem is the flash of content, not that our CSS was particularly unwieldy. While migrating to styled-components would have been one way to solve the problem, it was far from the most economical. Thinking about the problem, a previous conversation with another developer came to mind. "Just make the body invisible until the content loads!" Well, duh.

With just three lines of code, the entire problem was solved. Three lines. Here's the distilled version:

[...]

if (Meteor.isClient) import './App.scss';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { ready: false }; // This one.
  }

  componentDidMount() {
    this.setState({ ready: true }); // This one.
  }

  render() {
    return (
      {/* This style tag below */}  
      <div className="App" style={{ visibility: this.state.ready ? 'visible' : 'hidden' }}>
        [...]
      </div>
    );
  }
}

[...]

In just five minutes of work (ten total if you consider the thinking that led to this), the problem was solved quite eloquently. No major rewrites. No significant change in process. A dirt simple, easy to "set and forget" solution.

FOUC be gone!
FOUC be gone!

When you're building your own products, always step back before committing to grandiose solutions. More often than not, there's always a far simpler, inexpensive way to solve your problem. Look for those first and only ratchet up your investment if you're certain it's necessary.