It is often assumed that static site generators have limitations that server side rendering or client side rendering is necessary to get beyond. Single page applications, progressive web apps, engaging and dynamic UI's, integrations with databases and content management systems; these cannot be used with a statically generated site can they? They certainly can. One of the names this technique goes by is JAMstack. While in my opinion a server sending prebuilt HTML to a browser should be the standard it has become necessary to give it a name as both the server side and browser side of web development has become cumbersome and overly complex.
However there are many things to consider when building a JAMstack website. How do you integrate content and databases? How do you enhance it with modern web development techniques such as SPA and PWA? We will take a look at some of these considerations and specifically how they apply to web content management.
If your website is large enough, rebuilding it might be a heavy burden on your content provider and databases. How often builds occur, the source and scope of the changes, and the number of requests to your content providers and database that it requires all need considered when designing the build process. Imagine you are building a news outlet that will have tens of thousands of pages and data is changing hundreds of times per day. In a circumstance like this it is important to only rebuild the part of the site that is affected by any given content or code change. We will look at some of the ways to fine tune build processes to only rebuild the pieces of the website that are necessary so that our JAMstack site can scale indefinitely.
First it is important to understand when this is not a problem. If your site has about a hundred pages and rebuilds from code and data changes are expected a few times per day, then this should only produce a few hundred page builds. If your content providers are capable of millions of reads per day, then this is multiple orders of magnitude away from being a problem. In addition it is often easier to scale the capabilities of data and content providers than it is to deal with restrictive build processes. That being said there are circumstances where a fine tuned build process is necessary.
When deploying a JAMstack site you usually need to rebuild your site any time dependent data or content changes. To do this your hosting solution needs to have build hooks so that other systems can notify it when it needs to perform a rebuild. The content providers, databases, and code hosting solutions that you select in turn need to be capable of web hooks so that they can notify the hosting service that a rebuild is necessary. They also need to be capable of passing on detailed information so that the build process can identify exactly what needs rebuilt. Additionally, your selection of a static site generator will either limit or enable fine tuned build hooks and will affect how much of your site needs rebuilt on each content or data update.
Websites are always going to have global data. This might be the name, metadata, and other information that appears in all or many pages. Another example of this would be a "latest posts" section that appears on every page of your site. Any time this data changes each page might need updated, and there is no way to know until you actually perform the build. One solution is to restructure your site features to not run into this issue, but that is of course limiting and we would rather find a solution that enables us to maintain the feature. There are two general approaches we can follow to solve this problem.
The first option is simply to limit the number of changes to global content. This tighter control allows you to maintain the same build process, keeping a simple build system with maximal end user performance. This might come in the form of limiting who has access to updating the content or limiting how often changes to it are integrated into the build. The benefit of this is simplicity and end user performance. However this limits how flexible you can be with global data and how quickly changes can be integrated into the site.
The other option is loading this content asynchronously after the page load from an always up to date API. This means that the data can change as often as you would like and changes can be integrated into the end user experience the moment they are made. The limitation of this option is complexity and performance as it introduces client side rendering. The page and any dependent libraries must be loaded, requests for data made, and the UI updated. This is the design that nearly all web frameworks follow, and is the reason for much of the slowness of the modern web. However sometimes it is necessary in order to implement highly interactive and data intensive UI. In these scenarios using this asynchronous UI approach in a careful and selective manner can give content flexibility and more real time content updates.
The other data consideration with JAMstack sites is authenticated experiences. Do users have their own data? Should some content require authentication? Are some views user specific, where the content they see depends upon their profile? In these scenarios there are some additional considerations with regards to how these views should be delivered.
You can still follow the JAMstack pattern of prebuilt HTML, but this time delivered only through an authenticated UI. This means that your otherwise static server needs to be capable of authorizing requests, increasing hosting complexity, but it also means that you maintain the performance benefits of prebuilt HTML. It is worth noting that this not a very common solution and many build process will either not support this or require a lot of customization.
JAMstack sites are a perfect fit for continuous integration made simple. Your build process already produces a site that can be simply and statically delivered. We have already discussed the need for build hooks that force a rebuild of the site. This same process can be easily extended into version control. All that is needed if for your coding hosting system such as GitHub to use a web hook that triggers the build hook of the hosting system.
However not every code change requires a full rebuild of the site. Very often static site generators will have a source directory hierarchy that matches the end website. In this case if only one page is modified in the source code then it is possible that only that page needs rebuilt.
It is common to think that static site generation cannot be a single page application. This is in fact far from the truth. Combined the two can give you the best of both worlds, SPA architecture reducing the amount of network traffic and static site generation reducing the amount of run time processing. Single page applications increase performance by loading only the information needed to update the view, without reloading and re-rendering the whole page. Static sites are good at limiting the amount of run time processing, simply delivering prebuilt HTML as the user needs it. These can be combined to produce a website that is maximally performant.
To do this the static site generator that you select needs to be capable of rendering not only the full static page, with metadata, footer, header, and other layout elements included, but also needs to generate the HTML of just the page. This way the client code can load in these views upon navigation without loading in the whole page layout and metadata
With these considerations in mind, I have the following suggestions when implementing a JAMstack site alongside a CMS:
Enable fine tuned build hooks my maintaining a meaningful site hierarchy and selecting the right content, hosting, and site generating solutions.
Enable single page applications by selecting a static site generator capable of generating content in various formats such as with layouts included and not included.
Enable user specific experiences with client side rendering solutions that can fulfill their purpose without overtaking the entire app.
Limit the amount of global data changes and places where small content changes would require full site rebuilds by planning your page layouts and features ahead of time. It is also important to know ahead of time which features will have such an impact so that you can plan accordingly.
Know which side of the build cost vs data request cost equation you are on. Are your databases capable of fulfilling orders of magnitude more requests than your build requires? Then skip the fine tuned build process. Will you have millions of product pages where rebuilding them even once is a heavy load on your database? Then carefully plan ahead for a fine tuned build process.
Check out my blog for more of my musings upon technology and various other topics.