Replies: 15 comments 38 replies
-
interesting proposal and addresses a key pain point! I feel like we need more concrete examples here as I have trouble understanding how it works. i think i see how this works with Nextjs as that is a core design goal. but... would DPR work with Hugo or Jekyll or Gatsby as-is today, or would it require an adapter per SSG, or would it require internal modifications to be made by each SSG maintainer? edit: ah hang on.. there is a related thing for On-demand Builders that may add context. Question still stands - i see assertions that this process will work with any framework, but I'd love some more detail on how, for given popular SSGs that dont have any concept of on demand builders, or understanding of when to stop SSGing. |
Beta Was this translation helpful? Give feedback.
-
If I understand this correctly it's essentially ISR but without the stale - so it would have definite first hit performance implications. Probably not an issue for the intended sort of content (archival/stale data), but important to understand to use it correctly. It would be interesting to have some sort of control over how the on-demand builder interacts with the cache; perhaps some content is revalidate-once-then-cache-until-next-deploy, but others should use every-n-minutes-SWR (data that updates frequently between deploys, like maybe a news home page, could become almost semi-dynamic). There might also be issues with dependency in ODB content (i.e. a news article might be built by an ODB but it might be missing from lists or navigation elsewhere that should also be rebuilt). I wonder if perhaps the ODB might be able to ask the CDN to drop other ODB-driven paths from its cache to handle this? As to the atomic deployment: because ODBs are by their nature dynamic, they break the idea of a fully atomic deployment because they can build using data sources that are newer than the last deployment, so the site is not a full snapshot. Broken datasource APIs during on demand builds could also break stuff at any time, so the points of failure also increase. I like this, it makes a lot of sense. |
Beta Was this translation helpful? Give feedback.
-
First hit would have a performance impact and subsequent ones won't? If so, this approach doesn't seem to improve the users experience as this defies what the industry is striving to prevent/fake by using skeleton screens, service workers, app shell design with AMP + PWA etc. Seems ok for news sites, certainly not for e-commerce where you want the response as fast as possible. Another approach could be to have a Lambda/Function etc. that hits the content that wasn't included in the build as soon as production deploy happens so the user isn't penalized and the DX/build time aren't impacted. |
Beta Was this translation helpful? Give feedback.
-
Great proposal and well explained! A valid warm-up mechanism may include what @matijagrcic mentioned above: lambda functions that executes requests of content not built yet and that run right after the build finishes. |
Beta Was this translation helpful? Give feedback.
-
Very interesting proposal. However, I'm still a bit unconvinced about the lack of customization of the cache duration. The points are clear and make sense, but to me it seems that the Jamstack philosophy is applied a bit too strictly on a feature with a bigger potential. IMHO allowing developers to customize the cache could enable a broader range of use cases. |
Beta Was this translation helpful? Give feedback.
-
It's an interesting proposal! Does it handle the use case of having a page who displays product price or product stock (who can change?). How does it impact with FCP? As what I understood (I could have been missing something) When a user hits a page that is not critical, we need to build it, cache it and after that deliver to the browser. All of that while using request time. |
Beta Was this translation helpful? Give feedback.
-
Love the proposal, this rocks! 🔥🤘 Is there any thought towards having the option to run the DPR functions as post-build background tasks? Then new deploys are still speedy, but you get the benefit of (eventually) having every page built instead of generating them on the fly. For example, my personal blog site would probably wouldn't care if the first load is generated with a DPR function for the first visit after a deploy. However, an eCommerce site might not want that initial extra load, so they choose to have the pages rendered as a post-build action. In the worst case, if a user visits a page right after a deploy but before the DPR functions run as a post-build action, they would force the page to be rendered on the fly through DPR. (Am I making sense? This makes this more of a spectrum of how static you want your site to be) |
Beta Was this translation helpful? Give feedback.
-
This is super intriguing. I like where it is headed! In particular, I really like that you're keeping the original Jamstack benefits top of mind when considering how to expand and evolve the approach. I felt we were heading down a path where any site could fall under the purview of Jamstack simply because you can achieve it with Netlify, Vercel, etc. This reigns those ideas in by bringing us back to why the Jamstack was so revolutionary in the first place. The main concern I have when thinking about how I might adopt to a change like this is in considering build processes that require the context of the full built output to achieve their maximum benefit. Two examples:
These types of benefits are trivial to achieve with build plugins today on a completely static site. How do we ensure we don't way overcomplicate working with these supporting tools as a result of this approach? |
Beta Was this translation helpful? Give feedback.
-
How would on-demand builders work with Jamstack SPA sites? I'm the maintainer of Docusaurus (quite similar to Gatsby, using Webpack and React for SSG) and wonder how easy it can be to generate that lambda function to generate pages lazily. That seems easier with non-SPA jamstack tools or Next.js and SSR-based tools that already generate lambdas. Has anyone made a POC with Gatsby or a similar tool? |
Beta Was this translation helpful? Give feedback.
-
I do like (if not love Rendering non-critical pages on request is fine, but we need to have access to the result of the initial build process. Let's say in the build process we gather data from different sources. Now to render a page we want to have access to this data. In my understanding we would have to gather that data on every page request, right? If in the other hand we have access to that data, serving could be quite fast. 🚀 If not, I don't see much difference to a conventional server rendered approach really. 👴 Also I'd love to see (in the future) a way to validate those non-critical pages automatically after the build process is done. We'd have to generate a list of URLs. As soon as another (partial) build succeeds, the validation queue would restart. This of course only would make sense if the result persists centrally (and not in a single edge node). |
Beta Was this translation helpful? Give feedback.
-
Neat idea. Couple of questions though:
|
Beta Was this translation helpful? Give feedback.
-
Concerns:
I'm not trying to throw shade on the idea of DPR. I'm trying to get my head around where the real issues are now that we have Jamstack defined. Slow builds are an issue in almost every SSG with lots of content. I'm just apprehensive when I keep perceiving the issue going back to the SSG itself. |
Beta Was this translation helpful? Give feedback.
-
ehhhh, is it just like standard CDN-Origin architecture? |
Beta Was this translation helpful? Give feedback.
-
Hello, fellow jammers! I like the overall flow of the spec. Part of the site can be generated at build time, the rest on demand. As mentioned above, every strategy has its trade-of. Writing specs is difficult because you want to be specific enough but keep the implementation flexible enough so frameworks can choose how to implement it (We all want to have a feature page with checkboxes to all the buzz words). The thing I would like to change in the proposal is:
To me, DPR doesn't need to be opinionated about if the new file is part of the "atomic deploy". DPR & incremental builds are pretty intertwined. The difference is that DPR is built on-demand, and incremental builds ahead of time. If I change an on-demand build page and my code doesn't touch anything else, why would I want to rebuild all other pages? I'm curious why the atomic deployment is so crucial in the proposal? |
Beta Was this translation helpful? Give feedback.
-
I would love to see DPR operate such that we can create new versions of any page using an incremental approach (such as with Next.js Incremental Static Regeneration) and have that actually create a delta build, similar to a commit in git. That way as the data or content for pages change between code builds, we can still account for that and maintain immutability. |
Beta Was this translation helpful? Give feedback.
-
Table of contents:
Challenge
The model of decoupling the generation of a site’s assets from the time they are requested brings a variety of advantages, but also introduces challenges when sites become very large.
As the Jamstack ecosystem has matured, tools and services have emerged bringing ways to automate deploys and provide productive workflows, but the practical ceiling for Jamstack sites often involves maintaining practical site generation (build) times when the number of pages being created in each build becomes very large.
Various strategies have risen in an attempt to satisfy this need such as incremental builds, and incremental static regeneration (ISR) + the use of the stale while revalidate (SWR) pattern.
Each of these approaches is either difficult for developers to implement and reason about, or falls short of upholding core principles of the Jamstack thus compromising some of the key benefits of its architecture.
Goal
What are we trying to achieve?
Provide a means of generating and serving sites which have very large numbers of pages, without build times becoming impractically long, or compromising the following characteristics enabled by Jamstack:
Retain the mental model enabled by the Jamstack architecture — where running a build results in a set of assets deployed (or deployable) to a content delivery network (CDN) or simplified hosting infrastructure which, since it is immutable and atomic, can be rolled back to a previously deployed version with confidence in its resultant state.
Retain the performance, security, and stability profile of the Jamstack architecture by honoring the logical approach of pre-rendering as much content as possible, and serving as much of the site’s content pages as pre-rendered assets from a CDN as possible.
Avoid making it difficult to reason about the logical state of the site, which makes it harder to rationalize the expected state of a site at any given time in its deploy history.
Proposal
Distributed Persistent Rendering (DPR)
With DPR, the generation, or rendering of assets is distributed between build-time and request-time.
With DPR, the responsibility of rendering assets is distributed between the build infrastructure, and serverless functions.
With DPR, the cache of assets which form the site’s deploy can grow progressively and persists over time as requests are made to more URLs which were not previously rendered.
Logically, DPR creates the same result as a Jamstack build - it renders assets and populates them into a CDN or hosting infrastructure. Rather than the rendering of every asset taking place at build time, the rendering of some assets can be deferred from build time and instead take place on demand when each is first requested. These assets then join those previously rendered during the build process or by other on demand requests, in the CDN, logically contained within the same atomic deploy.
In this way DPR would provide the means of rendering some assets at build time, and others, later via serverless functions, as a result of the first request to their URL.
Like the assets generated during a build, those rendered by DPR at request time would remain in the CDN cache until invalidated by the successful completion of a new deploy. This would allow developers to consider the assets rendered during a deploy, and those rendered on demand from requests to DPR functions contained in that deploy as all belonging to the same logical atomic deploy.
Image: A logical overview of the areas of responsibility for a given deploy with DPR
Usage scenarios
Example scenarios utilizing DPR:
Critical and archived pages
Consider a news or publication site which may have hundreds of thousand or millions of unique content pages on unique URLs. Typically, over time, the frequency of updates to specific news story pages diminishes, as does the frequency of requests to them.
DPR would allow the site developers to focus on core content pages in their build, regularly generating those pages as a result of content updates, and as a result of feature and design iterations. The long tail of historic pages might be omitted from the core build such that the build times remain fast and manageable. Historic pages would then get added to the latest deploy output only if they are requested via their public URL. Once rendered on demand, they would remain available until invalidated by a subsequent deploy. Thereafter they would be repopulated by their next first request.
User generated content pages
DPR could also be used to populate pages created as a result of content contributed by users. Consider a site which invites users to submit content via a form which would later be presented on a unique page per contribution.
Instead of regenerating the entire site upon each user submission, only the new page which should exist as a result of the user’s contribution would need to be generated. This rendering could take place on-demand when the URL for the new page is first requested and added to the overall deploy cache for this version of the site.
Updates to the site’s design or functionality would trigger a new deploy as usual, but the build times would no longer be coupled to the volume of user generated content as the rendering of these pages would be deferred until they were first requested.
Points of difference
Key differences between DPR and other strategies for achieving these goals.
Incremental Builds build only certain parts of your site when there are changes. DPR would instead rebuild the whole site, with the exception of the content you want to be rendered on demand.
Incremental static regeneration (which is based on stale while revalidate), similar to DPR, generates only the pages defined, and then renders the new page when a user navigates to that page. That being said, SWR relies on users seeing stale content first. Whether it is a fallback page or a previous version of the page, it is not a consistent experience for each user. The first user to a new page will see stale content, and the second user (and beyond) will see the newest content.
Exclusions and omissions
This RFC does not include descriptions of internal CDN caching strategies or other implementation details. This is a deliberate omission so that we can focus this discussion on the logical model for DPR and the mental model for building sites and applications with it.
Deeper CDN implementation details are out of scope for this discussion and should be possible to be kept opaque to the developers implementing sites with DPR just as they should for existing Jamstack sites.
Beta Was this translation helpful? Give feedback.
All reactions