The SSR Comeback
In the mid-2010s, a few key drawbacks of client-side rendering became apparent to the web development community. These downsides fall under two main categories: performance and marketing.
- SPAs, which need to download and run a bundle of JS before rendering, suffer from a slow First Meaningful Paint. This can have a direct impact on eCommerce conversion rates, or more drastically, cause users to abandon the application entirely.
- If you have a network intensive application, the user experience can be hurt by a slow network connection (as opposed to keeping heavy-duty network activity on a server you control).
- Increasing traffic through search engines (Search Engine Optimization, or SEO) relies on having informative and indexable pages that crawlers can parse. SPAs typically have a barebones HTML document that in turn links to all the JS it needs in order to work, making them less search engine friendly. Caveat – Google (and presumably other browsers) can render and understand web pages, even SPAs. However, if SEO is a priority, having pre-rendered pages is the safe bet.
- Sharing thumbnails, snippets, and previews on social media is much easier with pre-rendered pages than it is with a dynamic SPA.
So, in the later teens, server-side rendering started to see more adoption, and a higher order of frameworks emerged that enabled and accommodated server-side rendering – notably Next.js (React) and Nuxt.js (Vue). These are excellent frameworks that offer out-of-the-box support for SSR, along with other intelligent defaults that reduce developer decision-making and offer anti-pattern guardrails – altogether giving more time to developers to focus on the application itself. Honorable mention goes to Angular Universal, which makes it very easy to tack SSR support onto existing Angular SPAs.
Enter the Jamstack
Since around 2017, a piercing question has been making its way into more and more architectural discussions:
What if you don’t need a web server at all?
The answer to this is a paradigm shift from a vertical, monolithic stack as shown in this diagram:
To a service-oriented, loosely coupled, stack as seen here:
- Need business logic for things like authentication or eCommerce? Forget the monolithic web/app servers, and say hello to modular, loosely coupled APIs.
- Use markup (or markdown!) and templating in conjunction with non-interactive, infrequently updated content from a headless CMS to statically generate as much of your website as possible at the build phase.
And voila! You have a snappy, pre-rendered application, enriched by JS at runtime, that is intrinsically scalable, secure, and cheap, with the added bonus of separating your concerns. Front-end development, API development, and content management are each an art and science unto themselves, and the natural separation of the Jamstack allows for more focused cultivation of expertise in each.
That all sounds great, but so does going on a two-week meditation retreat to restructure your character. What matters is the practicality. So, what are some practical considerations to keep in mind regarding the Jamstack?
- Greater reliance on external services – By nature, you will be imparting control and logic to decentralized services, each of which is liable to be a single point of failure. It can be a scary proposition to put your faith in a service’s reliability, availability, and data stewardship, especially services that are black-box or offered by third parties. (This is reminiscent of Ken Thompson’s reflections on trust.)
- Entire site must be pre-built on each change – Currently, static sites must be fully generated upon each change, which can lead to change backlogs and lots of waiting on builds, particularly for larger sites. This was well-detailed in Smashing Magazine’s case study of its own transition from WordPress to the Jamstack. However, with Gatsby’s recent release of incremental builds (and other implementations sure to follow), this consideration will be outdated soon.
- May require an institutional paradigm shift – The Jamstack is not easy to adopt incrementally due to its reliance on an entirely different architecture. Because of this, moving from a traditional architecture to the Jamstack in an effective way may require resolute initiative and some degree of institutional willingness to venture into new territory.
All said, it’s difficult to deny the compelling reasoning behind the Jamstack, and it would be a lie to say the movement wasn’t growing, as evidenced (loosely) by the literally hundreds of static site generators that have sprung up in the last few years; generators that are well-used and continually maintained. And, while there has been a perception that Jamstack is really only suited for static, content-oriented sites, its broadening portfolio of powerful applications serves as evidence that static does not necessarily mean unmoving.
Even if you don’t go gung-ho on the Jamstack, there is a moral that’s easier to adopt: do as much work as possible at build time to take the load off at runtime. Does the text of a blog post need to be fetched upon every request? Does the unchanging “About” section of a website need to be rendered on demand? When building out a new application, make it a practice to ask, “Does this need to be rendered at runtime?” If the answer is no, then there is likely an opportunity for optimization.
Note: Next.js and Nuxt.js, the two powerful SSR frameworks mentioned earlier, both offer SSG out of the box. Next.js goes a step further with its automatic static optimization, detecting and pre-rendering everything it possibly can at build time, unless explicitly directed otherwise. Frameworks of this kind, that offer functionality across the entire “SPA – SSR – SSG” gradient with a bias toward SSG, are wonderful at both giving developers options and beating the drum for the static movement.