In this article, Ekene Eze shares his thoughts about the direction of the web in 2022, and what solutions we can expect to see come up in the ecosystem to significantly improve the Jamstack experience.
In the early days of the Jamstack, developers mostly used it for static sites and opt for a more verbose frontend framework like Vue and React when they need to perform more sophisticated operations like server-side rendering in web applications. The need for adding dynamic functionalities to web apps never went away, but it didn’t make us appreciate Jamstack any less. We loved what it proposed and the value it provided. Web pages are instantly available to users, and developers could build websites easily and deploy them faster. Users are happy, developers are happy; it’s a win-win.
Then came static site generators which made things better by adding a build process to the previous flow of a static site which meant that all the site’s assets were all pre-generated by a build server (not on a local machine) and then deployed. This was a step forward in improving the developer experience of Jamstack developers and consequently the popularity of this model. Developers could build Jamstack sites with a static site generator like Gatsby, push the project to a version control system like Github, and deploy to a hosting service like Netlify which provides a workflow that will rebuild the site when there’s an update to the project.
Everything seemed great, and we were all better for it.
But like every other technology, Jamstack started evolving as the need for more sophisticated functionalities continued to grow. As a “static site”, a Jamstack site was limited in the things it could do, and people did not keep quiet about it. Suddenly, it seemed like Jamstack was an incomplete model that could not be used at scale. The concerns raised were mostly around the inability to perform server-side operations and the length of build times in larger Jamstack sites. This didn’t sit well within the Jamstack community, and we started to “extend” the Jamstack to solve this new challenge, which it was not originally meant to solve.
Dynamic Functionalities In The Jamstack
While Gatsby made a lot of advancements in how we build and update Jamstack sites with features like incremental builds, Next.js introduced server-side rendering with getServerSideProps()
:
function Page({ data }) { // Render data...
} // This gets called on every request
export async function getServerSideProps() { const res = await fetch(`https://.../data`) const data = await res.json() // Pass data to the page via props return { props: { data } }
} export default Page
While also maintaining the good-old static generation with getStaticProps()
:
// posts will be populated at build time by getStaticProps()
function Blog({ posts }) { return ( <ul> {posts.map((post) => ( <li>{post.title}</li>))} </ul>)
} export async function getStaticProps() { const res = await fetch('https://.../posts') const posts = await res.json( return { props: { posts, }, }
} export default Blog
This gave developers the idea of a hybrid approach to building Jamstack sites. Suddenly, you could build Jamstack sites that could render different pages with different rendering patterns. For instance, your /about
page could be statically generated while your /cart
page is server-side rendered. However, the issue of long build times remained. But not for long.
With Incremental Static Regeneration (ISR), Next.js also made it possible for pages to be generated on demand and cached for subsequent requests. This meant that developers could have a site with 10,000 pages and only generate 100 pages at build time. All other pages will be dynamically generated on-demand and cached for subsequent requests, effectively bringing the concern about long-running build times to bay.
function Blog({ posts }) { return ( <ul> {posts.map((post) => ( <li key={post.id}>{post.title}</li>))} </ul>)
} export async function getStaticProps() { const res = await fetch('https://.../posts') const posts = await res.json() return { props: { posts, }, revalidate: 10, // In seconds }
} export async function getStaticPaths() { const res = await fetch('https://.../posts', {limit: 100}) const posts = await res.json() // Get the paths we want to pre-render based on posts const paths = posts.map((post) => ({ params: { id: post.id }, })) return { paths, fallback: 'blocking' }
} export default Blog
