In my last post, I introduced the concepts behind serverless engineering and enumerated some of the technologies used by each “tier” of a three tier application (front-end/back-end/data). The purpose of that post was primarily to illustrate the boundaries of each tier with respect to a serverless design. In this post, I will discuss the front-end tier and how to apply serverless practices to this layer.
To quickly refresh some of the main points, the last post made note that front-end is frequently the easiest to develop serverlessly and many may already be practicing strategies shared by a serverless design. Utilizing the technology discussed in the earlier post, this article will set forth practices and strategies for developers to build with. The primary technologies discussed were:
- Single Page App (SPA) Frameworks
- Static Site Generators
- Content Delivery Networks (CDNs)
- Generalized Object Storage as a Service
In order to build an application you have to build the application. This is more than just what framework or language is used, but how the build environment is automated and managed. The practice of codifying and automating builds is called “Continuous Integration” (CI); This is commonly used in conjunction with “Continuous Deployment” (CD), which will be discussed later, as “CI/CD”. The benefits of CI/CD in reducing build time, recovery time, build stability and repeatability have been espoused by nearly every corner of software development. To serverless front-end design, CI provides a reliable building and testing point at the most important event in front-end software lifecycle -- code change.
Most front-end developers are already building with serverless-friendly technology. The critical aspect of the build and design process of a serverless front-end application follows one simple rule:
- Build and deploy as static assets, ie html, css, js and image files. Avoid using templates which are designed to be evaluated at request time, opt instead to have that presented client-side using a framework and favor build-time template evaluation.
While it’s possible to simply write your application directly in this format, there are a number of frameworks which simplify this process and enable developers to easily target their builds to these assets. If the application is going to be mostly static or based entirely on text or flat, encoded content, it might be good to evaluate static site generators like:
Static site generators can be used to maintain a consistent style and prevent repetition for sites where the content is mostly text or easily repeatable (like a blog or store) and where content doesn’t necessarily change instantly. If some of the content is dynamic, it may still be possible to integrate it with a static site generator, depending on the choice, but with enough dynamic content, it may be time to evaluate a Single Page App (SPA) framework like:
There are many more SPA frameworks and variants on the ones listed which may increase or decrease the complexity of the application, but the idea is the same -- as long as they are not Server-Side Rendered (SSR) frameworks which require a backend server and they target the static build assets listed above, they are a good fit for a serverless front-end. SSR which is "pre-rendered" or targets static assets is fine. While SSR is an important topic for performance, it will be discussed later in the back-end blog post. It is also worth noting that popular web frameworks like Ruby on Rails, Django, Phoenix aren’t listed here, despite their popularity, because they tie their template rendering to a request, not to a build. It is still possible to build a front-end serverless-friendly but doing so would require abandoning the templating engine provided by these frameworks.
Once the application is built and the static files are ready for deployment, the Continuous Deployment (CD) practices become the next priority. In serverless designs, CD is important not only to developer convenience and for redeploy repeatability, but also because production servers, themselves, are a service that the developer utilizes. Working with these services should be like writing an API client-side interaction. The primary services, mentioned previously, which are invoked during a deployment are:
- Generalized Object Store as a Service
- Content Delivery Networks (CDNs)
Some examples of Generalized Object Stores as a Service are:
- AWS Simple Storage Service (S3)
- Backblaze B2
- Digital Ocean Spaces
- Google Cloud Storage (GCS)
- Microsoft Azure Blob Storage
- Rackspace Cloud Files
And examples of CDNs that could be used:
- AWS CloudFront
- CloudFlare (Workers Sites or CDN)
- Digital Ocean Spaces CDN
- Google Cloud CDN
- Microsoft Azure CDN
The deciding factors between which service to use for a given artifact breaks down to a few relatively simple rules:
- If the file being served needs to be served from a custom domain name with a custom TLS/SSL certificate use a CDN.
- If the file is large media or accessed by individual users and not all or most users, use a generalized object store.
It’s recommended from a cost and simplicity standpoint to prefer generalized object stores when they don’t fall into these explicit categories. Fortunately, traditional CDNs operate well over object stores to form a cache and more-modern CDNs integrate their own object store, so transitioning objects between these two is relatively easy.
Developers should build their CD pipeline so that the builds generated in CI are eventually uploaded to an object store or CDN via its API, then CDN cache is invalidated to complete the deployment. Teams can optionally retain old deployments for easier rollbacks, but with a fast CI/CD pipeline that may not be required. There are a number of tools/services which can help your team with building and simplifying this pipeline -- this author started NullServe to do just that.
While building serverless-ready applications might be a fun exercise in constrained design, it’s also important to many to justify why a change ought to happen and why not the old way. What this article and NullServe are here to show you is that this is the old way, before we brought in backend server bloat that slowed our websites down and made them more complicated. This “old thing” is just re-energized and empowered with a strong ecosystem of APIs and frameworks to support developers who are focused on user-first metrics.
Beyond simply reducing bundle size and improving routing / network latency within your infrastructure, the final line of improvement is cache hits and customer proximity. CDNs dramatically improve last mile latency and aid teams in caching resources for customers. Using static site frameworks and SPAs can help to reduce network calls and hopefully reduce bundle size in some cases where the tooling is available. With this design, the app is already built for scale of any size, big or small, so there are no servers to manage to ensure your users get a fast and positive experience.
By segregating the visual concerns from the data and service concerns, it’s much easier for a development team to pursue service workers for a PWA experience for low bandwidth or offline customers. Since the deploy is only targeting front-end assets and they’re served from an edge-CDN, performance has already been accounted for by previous effort.
In this post I've declared a rough design for setting up a front-end web application serverlessly and detailed what technology would be used for each aspect. In later posts of this series, I'll outline API and Data considerations.
I am a Computer/Software Engineer focused primarily on Cloud-First Software Architecture. I have been working professionally with serverless applications for 3 years as a DevOps/Architect and 10 years overall in a DevOps role. I previously worked on a large web application, designing the architecture of APIs, React apps, and databases for a serverless stack. I recently left my previous role to start a company focused on serverless applications -- NullServe. NullServe aims to provide the tooling and platform necessary for product-teams to build out their ideas quickly and coherently using technology that scales up (and down) based on their needs. NullServe leverages existing cloud platforms to provide the performance and stability customers expect, but it simplifies serverless infrastructure and setup process so that developers can focus on building, not configuring. NullServe is Serverless DevOps as a Service.