-
Notifications
You must be signed in to change notification settings - Fork 0
/
readme.html
383 lines (369 loc) · 123 KB
/
readme.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>readme</title>
<link rel="stylesheet" href="https://stackedit.io/style.css" />
</head>
<body class="stackedit">
<div class="stackedit__left">
<div class="stackedit__toc">
<ul>
<li><a href="#theoretical-foundations-for-server-side-rendering-and-static-rendering">Theoretical foundations for server-side rendering and static-rendering</a>
<ul>
<li><a href="#abstract">Abstract</a></li>
<li><a href="#related-work">Related work</a></li>
<li><a href="#definitions">Definitions</a></li>
<li><a href="#when-build-time-rendering-is-possible">When build-time rendering is possible</a></li>
<li><a href="#an-abstract-implementation-of-build-time-rendering">An abstract implementation of build-time rendering</a></li>
<li><a href="#rendering-at-request-time">Rendering at request time</a></li>
<li><a href="#next.js-vision-of-rendering">Next.js vision of rendering</a></li>
<li><a href="#a-unified-api-for-server-rendering-be-it-build-time-request-time-or-somewhere-in-between">A unified API for server-rendering, be it build-time, request-time, or somewhere in between</a></li>
<li><a href="#implementation-in-real-life-framework">Implementation in real-life framework</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="stackedit__right">
<div class="stackedit__html">
<h1 id="theoretical-foundations-for-server-side-rendering-and-static-rendering">Theoretical foundations for server-side rendering and static-rendering</h1>
<p>Eric Burel, LBKE, <a href="mailto:[email protected]">[email protected]</a>, <a href="https://www.lbke.fr">https://www.lbke.fr</a></p>
<p>Draft paper</p>
<p>Read the HTML version online: <a href="https://tinyurl.com/ssr-theory">https://tinyurl.com/ssr-theory</a></p>
<p>Edit on GitHub: <a href="https://github.com/lbke/ssr-theory">https://github.com/lbke/ssr-theory</a></p>
<h2 id="abstract">Abstract</h2>
<p>We consider any reduction of the volume of computation needed to operate a website or web application an obligation to achieve a fast, feature-rich and energy-efficient Internet.<br>
Pre-rendering content server-side is one possible approach to achieve those contradictory goals. Yet, the very concept of “prerendering” is still vague, and not seldom studied in the academic literature, leading to suboptimal implementations in existing frameworks.</p>
<p>This paper contributions are threefold.<br>
First, we propose formal definitions for various web content rendering approaches that powers the “Jamstack”: prerendering, server-side rendering, static rendering… Many definitions exist in the industry but none is canonical and some are even contradictory. Beyond wording details and framework specificities, we strive to unify those concepts within a common, broader understanding.<br>
Then, we model server-side rendering mathematically as a binding between two sets: the set of all possible requests, and the set of responses from the server. From this model, we derive rules that define for which requests pre-rendering is possible or not.<br>
Finally, we develop an API that should encompasses all possible server-rendering approaches, should they happen at build-time, request-time, or somewhere in-between. We demonstrate a partial implementation of this API using Next.js 12.<br>
From this study, we conclude that the division between static and request-time rendering is mostly fictional and sums up to a problem of cache configuration, and that build-time rendering in particular has been vastly underused until recently.</p>
<h2 id="related-work">Related work</h2>
<p>If you believe a paper, article or resource should appear in this section, please reach us out: <a href="mailto:[email protected]">[email protected]</a>.<br>
We use the definitions provided by the 2 current big players of the Jamstack ecosystem as our work-basis, namely Netlify, through the <a href="http://Jamstack.org">Jamstack.org</a> website (<a href="https://jamstack.org/">https://jamstack.org/</a>) and Vercel, through the Next.js framework (<a href="https://nextjs.org/">https://nextjs.org/</a>).<br>
At the time of writing, Next.js proposes the most complete set of features for server-side rendering, and therefore has been chosen as the basis of our implementation.</p>
<p>A good example of concept that requires clarification is “prerendering”. For Vercel, “prerendering” means server-side rendering, whether it happens at build-time or request-time or somewhere in between. For <a href="http://Jamstack.org">Jamstack.org</a>, “prerendering” only includes build-time rendering aka “static rendering”. See <a href="https://github.com/jamstack/jamstack.org/issues/644">https://github.com/jamstack/jamstack.org/issues/644</a><br>
RedwoodJS or SvelteKit adopts this build-time definition of pre-rendering.</p>
<p>SvelteKit specifically states the scenarios where pre-rendering applies<br>
(<a href="https://kit.svelte.dev/docs#ssr-and-javascript-prerender-when-not-to-prerender">https://kit.svelte.dev/docs#ssr-and-javascript-prerender-when-not-to-prerender</a>):<br>
“The basic rule is this: for a page to be prerenderable, any two users hitting it directly must get the same content from the server. Not all pages are suitable for prerendering. Any content that is prerendered will be seen by all users. You can of course fetch personalized data in <code>onMount</code> in a prerendered page, but this may result in a poorer user experience since it will involve blank initial content or loading indicators.”<br>
While we agree with the fact that client-side rendering leads to a slower user experience and unnecessary renders, we claim that personalized content can actually be pre-rendered, under the condition of adding a micro-server with URL rewriting capabilities in front of the frontend application.</p>
<h2 id="definitions">Definitions</h2>
<h3 id="rendering">Rendering</h3>
<p>Rendering is the act of transforming a piece of content into either HTML or a DOM representation that can be displayed by a web browser, client-side.</p>
<h3 id="server-side-rendering">Server-side rendering</h3>
<p>There are many definitions of “server-side rendering” (SSR) or in the wild. Let’s stick to the most basic one : server-side rendering is rendering a web page, on a server, as opposed to rendering in the client browser.<br>
Server-side rendering is as ancient as the web itself, and was almost the only way of rendering HTML content programmatically until client-side JavaScript got serious with the introduction of Chrome V8 engine in 2008.</p>
<p>This includes:</p>
<ul>
<li>build-time server rendering, also known as static rendering, or static site generation (SSG). This is when you render the pages of your website when you publish it, once for all.</li>
<li>request-time server rendering, also known as just server-side rendering (SSR). This is when you render the page every time someone request it.</li>
<li>no rendering at all, when content is stored directly as HTML or text. It’s an edge case yet falls into the server-side rendering category, as it doesn’t involve any kind of client-side rendering.</li>
</ul>
<h3 id="render-moment-and-the-not-so-special-case-of-static-rendering">Render moment and the not-so-special case of static rendering</h3>
<p>Rendering the content at build-time, or not rendering it at all, is considered as a special case. Therefore, in the industry, SSR is often synonymous to request-time server-rendering, while the terme “static” is preferred for build-time rendering or no rendering at all.</p>
<p>From the server owner perspective, this distinction makes sense: the cost structure of per-request rendering and build-time rendering are very different. Per-request has no upfront cost, but a needs a render for each new request ; build-time has an upfront cost, but do not need additional computation afterward.</p>
<p>However, from the web developer perspective, this distinction doesn’t really stand. The only difference is when the render happens. But in both scenarios, this render happens server-side.</p>
<p>In this paper, we’ll stick to the web developer standpoint. Therefore, to us, server-rendering includes per-request server-rendering (aka “SSR”) and build-time rendering (aka “Static Site Generation (SSG)”, “static rendering”…).</p>
<p>Let’s introduce the concept of “render moment”: the time when the render happens, rather than the place. The most well-known render moments are Build-Time Render (BTR) and Request-Time Render (RTR), but there could exist other moments: predictive rendering, incremental rendering, etc.</p>
<p>We advocate for a lighter distinction between patterns whose only difference lies in the render moment, such as per-request SSR versus build-time SSR.<br>
The “render moment” should be treated as a matter of configuration, and not as the fundamental cornerstone of the “Jamstack” philosophy.</p>
<p>The remainder of this paper is focused on server-side rendering only.</p>
<h3 id="technical-definitions">Technical definitions</h3>
<p>In this section, we’ll dive into the deeper technical details of server-side rendering needed for implementation.</p>
<h4 id="page-template-and-props">Page, template and props</h4>
<p>Let’s call the result of render is a page. When the render happens server-side, the page is a combination of HTML, JavaScript and CSS code.</p>
<p>A template is a generic web page, that expects some values to generate actual HTML and styles. Those values can be called “props”.<br>
The template could be typically a React component, or a template written in more classical language, like EJS, PUG, PHP…</p>
<p>So, a page is a rendered template. Like a text with blanks, whose blanks have been filled.</p>
<h4 id="request-as-input-of-a-server-render-be-it-build-time-or-request-time">Request as input of a server-render, be it build-time or request-time</h4>
<p>A request is the basic input of request-time server-rendering. It’s more precisely an HTTP request, most of the time triggered by a human user through a web browser.</p>
<p>A request can be seen as a set of various attributes.</p>
<p>However, there’s a fact often overlooked in the Jamstack ecosystem: in accordance to our definition of server-side rendering, build-time server rendering <em>also</em> expects a request as its input. Not only because the user has to initially query a server, via an URL, to get some content, but also because this URL is actually used by the server to retrieve the right piece of content.</p>
<p>For instance, imagine a blog with 10 articles, that is statically built using a React framework such as Gatsby or Next.js Each article has its own URL. So when the user types “your-super-blog.whatever/article-1” they get article 1.<br>
The URL is one of the attribute of the user request, and this attribute helps the server redirect the user to the right page but also the build engine to pre-render the right article for each page.</p>
<p>The main difference with traditional per-request server-side rendering, is that the build-time rendering approach usually only uses the URL, and ignore the rest of the HTTP request. We argue that even though existing frameworks systematically waste the remainder of the HTTP request, this is not a fatality. Cookies, headers and other request attributes could also be used to select the right piece of content.</p>
<p>We should keep in mind that there is no such thing as a “serverless” website. Static websites are relying on very simple servers, that just do some redirections, but there are always servers and HTTP requests around the corner.</p>
<p>Therefore, build-time rendering can be redefined as a server-side pre-computation of a handful requests the end-user may or may not make against the server. The initial input is still an HTTP request, only the render moment differs with per-request SSR.</p>
<h4 id="steps-of-server-side-rendering-at-runtime">Steps of server-side rendering at runtime</h4>
<p>When a user access a web page, per-request server-side rendering can be split in following steps:</p>
<ol>
<li>For a given request, select the right template depending on the HTTP request attributes.</li>
<li>Compute the props of the template based on user’s request. This step simply translates the HTTP request into a set of attributes that makes more sense in the business domain. Technically, this is not strictly needed for server-side rendering, the request could be directly passed to the render function.</li>
<li>Render the page, by feeding the page template with the right props.</li>
</ol>
<p>Request-time rendering does this for every HTTP request.</p>
<p>Build-time rendering does mainly the same thing, but in advance, at build-time, for a handful of precomputed HTTP requests. Then, when an HTTP request is received, the server will simply return the right rendered page.</p>
<p>Build-time rendering behaves as follow:</p>
<ol start="0">
<li>Prerender the pages for various requests (see steps above)</li>
<li>Same as for per-request SSR: select the right template based on the request. Most often based on the URL, but it could be based on other request attributes such as cookies, request headers, etc.</li>
<li>Return the pre-rendered content (no need for an additional computation)</li>
</ol>
<h4 id="formally">Formally</h4>
<p>A <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mi>e</mi><mi>n</mi><mi>d</mi><mi>e</mi><mi>r</mi><mi>e</mi><mi>r</mi></mrow><annotation encoding="application/x-tex">renderer</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.69444em; vertical-align: 0em;"></span><span class="mord mathnormal">re</span><span class="mord mathnormal">n</span><span class="mord mathnormal">d</span><span class="mord mathnormal" style="margin-right: 0.02778em;">erer</span></span></span></span></span> function takes requests as input and returns pages.</p>
<p><span class="katex--display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>r</mi><mi>e</mi><mi>n</mi><mi>d</mi><mi>e</mi><mi>r</mi><mi>e</mi><mi>r</mi><mo stretchy="false">(</mo><mi>r</mi><mi>e</mi><mi>q</mi><mo stretchy="false">)</mo><mo>↦</mo><mi>p</mi><mi>a</mi><mi>g</mi><mi>e</mi><mspace linebreak="newline"></mspace><mrow><mo fence="true">{</mo><mtable rowspacing="0.1600em" columnalign="left left" columnspacing="1em"><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>r</mi><mi>e</mi><mi>q</mi><mo>=</mo><mo stretchy="false">(</mo><mi>a</mi><mi>t</mi><mi>t</mi><msub><mi>r</mi><mi>i</mi></msub><mo stretchy="false">)</mo></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>p</mi><mi>a</mi><mi>g</mi><mi>e</mi><mo>=</mo><mo stretchy="false">(</mo><mi>H</mi><mi>T</mi><mi>M</mi><mi>L</mi><mo separator="true">,</mo><mi>C</mi><mi>S</mi><mi>S</mi><mo separator="true">,</mo><mi>J</mi><mi>S</mi><mo stretchy="false">)</mo></mrow></mstyle></mtd></mtr></mtable></mrow></mrow><annotation encoding="application/x-tex">
renderer(req) \mapsto page\\
\left\{
\begin{array}{ll}
req = (attr_i)\\
page = (HTML, CSS, JS)
\end{array}
\right.
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathnormal">re</span><span class="mord mathnormal">n</span><span class="mord mathnormal">d</span><span class="mord mathnormal" style="margin-right: 0.02778em;">erer</span><span class="mopen">(</span><span class="mord mathnormal">re</span><span class="mord mathnormal" style="margin-right: 0.03588em;">q</span><span class="mclose">)</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">↦</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.625em; vertical-align: -0.19444em;"></span><span class="mord mathnormal">p</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal">e</span></span><span class="mspace newline"></span><span class="base"><span class="strut" style="height: 2.40003em; vertical-align: -0.95003em;"></span><span class="minner"><span class="mopen delimcenter" style="top: 0em;"><span class="delimsizing size3">{</span></span><span class="mord"><span class="mtable"><span class="arraycolsep" style="width: 0.5em;"></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 1.45em;"><span class="" style="top: -3.61em;"><span class="pstrut" style="height: 3em;"></span><span class="mord"><span class="mord mathnormal">re</span><span class="mord mathnormal" style="margin-right: 0.03588em;">q</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mopen">(</span><span class="mord mathnormal">a</span><span class="mord mathnormal">tt</span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.02778em;">r</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.311664em;"><span class="" style="top: -2.55em; margin-left: -0.02778em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span><span class="mclose">)</span></span></span><span class="" style="top: -2.41em;"><span class="pstrut" style="height: 3em;"></span><span class="mord"><span class="mord mathnormal">p</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal">e</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right: 0.08125em;">H</span><span class="mord mathnormal" style="margin-right: 0.10903em;">TM</span><span class="mord mathnormal">L</span><span class="mpunct">,</span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mord mathnormal" style="margin-right: 0.05764em;">CSS</span><span class="mpunct">,</span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mord mathnormal" style="margin-right: 0.09618em;">J</span><span class="mord mathnormal" style="margin-right: 0.05764em;">S</span><span class="mclose">)</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.95em;"><span class=""></span></span></span></span></span><span class="arraycolsep" style="width: 0.5em;"></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></span></p>
<p>Request-time rendering does this for every request. Build-time rendering caches the page once for all during the build.</p>
<p>If we go step by step, and include the concept of “props” as input of the template (instead of the raw HTTP request), we can also define the following intermediate functions:<br>
<span class="katex--display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>t</mi><mi>e</mi><mi>m</mi><mi>p</mi><mi>l</mi><mi>a</mi><mi>t</mi><mi>e</mi><mi>G</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi><mo stretchy="false">(</mo><mi>r</mi><mi>e</mi><mi>q</mi><mo stretchy="false">)</mo><mo>↦</mo><mi>t</mi><mi>e</mi><mi>m</mi><mi>p</mi><mi>l</mi><mi>a</mi><mi>t</mi><mi>e</mi><mspace linebreak="newline"></mspace><mi>p</mi><mi>r</mi><mi>o</mi><mi>p</mi><mi>s</mi><mi>G</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi><mo stretchy="false">(</mo><mi>r</mi><mi>e</mi><mi>q</mi><mo stretchy="false">)</mo><mo>↦</mo><mi>p</mi><mi>r</mi><mi>o</mi><mi>p</mi><mi>s</mi><mspace linebreak="newline"></mspace><mi>t</mi><mi>e</mi><mi>m</mi><mi>p</mi><mi>l</mi><mi>a</mi><mi>t</mi><mi>e</mi><mo stretchy="false">(</mo><mi>p</mi><mi>r</mi><mi>o</mi><mi>p</mi><mi>s</mi><mo stretchy="false">)</mo><mo>↦</mo><mi>p</mi><mi>a</mi><mi>g</mi><mi>e</mi><mspace linebreak="newline"></mspace><mi>r</mi><mi>e</mi><mi>n</mi><mi>d</mi><mi>e</mi><mi>r</mi><mi>e</mi><mi>r</mi><mo stretchy="false">(</mo><mi>r</mi><mi>e</mi><mi>q</mi><mo stretchy="false">)</mo><mo>=</mo><mi>t</mi><mi>e</mi><mi>m</mi><mi>p</mi><mi>l</mi><mi>a</mi><mi>t</mi><mi>e</mi><mi>G</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi><mo stretchy="false">(</mo><mi>r</mi><mi>e</mi><mi>q</mi><mo stretchy="false">)</mo><mo stretchy="false">(</mo><mi>p</mi><mi>r</mi><mi>o</mi><mi>p</mi><mi>s</mi><mi>G</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi><mo stretchy="false">(</mo><mi>r</mi><mi>e</mi><mi>q</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo><mspace linebreak="newline"></mspace><mrow><mo fence="true">{</mo><mtable rowspacing="0.1600em" columnalign="left left" columnspacing="1em"><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>r</mi><mi>e</mi><mi>q</mi><mo>=</mo><mo stretchy="false">(</mo><mi>a</mi><mi>t</mi><mi>t</mi><msub><mi>r</mi><mi>i</mi></msub><mo stretchy="false">)</mo></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>p</mi><mi>r</mi><mi>o</mi><mi>p</mi><mi>s</mi><mo>=</mo><mo stretchy="false">(</mo><mi>p</mi><mi>r</mi><mi>o</mi><msub><mi>p</mi><mi>j</mi></msub><mo stretchy="false">)</mo></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>p</mi><mi>a</mi><mi>g</mi><mi>e</mi><mo>=</mo><mo stretchy="false">(</mo><mi>H</mi><mi>T</mi><mi>M</mi><mi>L</mi><mo separator="true">,</mo><mi>C</mi><mi>S</mi><mi>S</mi><mo separator="true">,</mo><mi>J</mi><mi>S</mi><mo stretchy="false">)</mo></mrow></mstyle></mtd></mtr></mtable></mrow></mrow><annotation encoding="application/x-tex">
templateGetter(req) \mapsto template\\
propsGetter(req)\mapsto props\\
template(props) \mapsto page\\
renderer(req) = templateGetter(req)(propsGetter(req))\\
\left\{
\begin{array}{ll}
req = (attr_i)\\
props = (prop_j)\\
page = (HTML, CSS, JS)
\end{array}
\right.
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mord mathnormal">m</span><span class="mord mathnormal" style="margin-right: 0.01968em;">pl</span><span class="mord mathnormal">a</span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mord mathnormal">G</span><span class="mord mathnormal">e</span><span class="mord mathnormal">tt</span><span class="mord mathnormal" style="margin-right: 0.02778em;">er</span><span class="mopen">(</span><span class="mord mathnormal">re</span><span class="mord mathnormal" style="margin-right: 0.03588em;">q</span><span class="mclose">)</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">↦</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.88888em; vertical-align: -0.19444em;"></span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mord mathnormal">m</span><span class="mord mathnormal" style="margin-right: 0.01968em;">pl</span><span class="mord mathnormal">a</span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span></span><span class="mspace newline"></span><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathnormal">p</span><span class="mord mathnormal">ro</span><span class="mord mathnormal">p</span><span class="mord mathnormal">s</span><span class="mord mathnormal">G</span><span class="mord mathnormal">e</span><span class="mord mathnormal">tt</span><span class="mord mathnormal" style="margin-right: 0.02778em;">er</span><span class="mopen">(</span><span class="mord mathnormal">re</span><span class="mord mathnormal" style="margin-right: 0.03588em;">q</span><span class="mclose">)</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">↦</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.625em; vertical-align: -0.19444em;"></span><span class="mord mathnormal">p</span><span class="mord mathnormal">ro</span><span class="mord mathnormal">p</span><span class="mord mathnormal">s</span></span><span class="mspace newline"></span><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mord mathnormal">m</span><span class="mord mathnormal" style="margin-right: 0.01968em;">pl</span><span class="mord mathnormal">a</span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mopen">(</span><span class="mord mathnormal">p</span><span class="mord mathnormal">ro</span><span class="mord mathnormal">p</span><span class="mord mathnormal">s</span><span class="mclose">)</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">↦</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.625em; vertical-align: -0.19444em;"></span><span class="mord mathnormal">p</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal">e</span></span><span class="mspace newline"></span><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathnormal">re</span><span class="mord mathnormal">n</span><span class="mord mathnormal">d</span><span class="mord mathnormal" style="margin-right: 0.02778em;">erer</span><span class="mopen">(</span><span class="mord mathnormal">re</span><span class="mord mathnormal" style="margin-right: 0.03588em;">q</span><span class="mclose">)</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mord mathnormal">m</span><span class="mord mathnormal" style="margin-right: 0.01968em;">pl</span><span class="mord mathnormal">a</span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mord mathnormal">G</span><span class="mord mathnormal">e</span><span class="mord mathnormal">tt</span><span class="mord mathnormal" style="margin-right: 0.02778em;">er</span><span class="mopen">(</span><span class="mord mathnormal">re</span><span class="mord mathnormal" style="margin-right: 0.03588em;">q</span><span class="mclose">)</span><span class="mopen">(</span><span class="mord mathnormal">p</span><span class="mord mathnormal">ro</span><span class="mord mathnormal">p</span><span class="mord mathnormal">s</span><span class="mord mathnormal">G</span><span class="mord mathnormal">e</span><span class="mord mathnormal">tt</span><span class="mord mathnormal" style="margin-right: 0.02778em;">er</span><span class="mopen">(</span><span class="mord mathnormal">re</span><span class="mord mathnormal" style="margin-right: 0.03588em;">q</span><span class="mclose">))</span></span><span class="mspace newline"></span><span class="base"><span class="strut" style="height: 3.60004em; vertical-align: -1.55002em;"></span><span class="minner"><span class="mopen"><span class="delimsizing mult"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 2.05002em;"><span class="" style="top: -2.49999em;"><span class="pstrut" style="height: 3.15em;"></span><span class="delimsizinginner delim-size4"><span class="">⎩</span></span></span><span class="" style="top: -2.49199em;"><span class="pstrut" style="height: 3.15em;"></span><span class="" style="height: 0.016em; width: 0.889em;"><svg width="0.889em" height="0.016em" style="width:0.889em" viewBox="0 0 889 16" preserveAspectRatio="xMinYMin"><path d="M384 0 H504 V16 H384z M384 0 H504 V16 H384z"></path></svg></span></span><span class="" style="top: -3.15001em;"><span class="pstrut" style="height: 3.15em;"></span><span class="delimsizinginner delim-size4"><span class="">⎨</span></span></span><span class="" style="top: -4.29201em;"><span class="pstrut" style="height: 3.15em;"></span><span class="" style="height: 0.016em; width: 0.889em;"><svg width="0.889em" height="0.016em" style="width:0.889em" viewBox="0 0 889 16" preserveAspectRatio="xMinYMin"><path d="M384 0 H504 V16 H384z M384 0 H504 V16 H384z"></path></svg></span></span><span class="" style="top: -4.30002em;"><span class="pstrut" style="height: 3.15em;"></span><span class="delimsizinginner delim-size4"><span class="">⎧</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 1.55002em;"><span class=""></span></span></span></span></span></span><span class="mord"><span class="mtable"><span class="arraycolsep" style="width: 0.5em;"></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 2.05em;"><span class="" style="top: -4.21em;"><span class="pstrut" style="height: 3em;"></span><span class="mord"><span class="mord mathnormal">re</span><span class="mord mathnormal" style="margin-right: 0.03588em;">q</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mopen">(</span><span class="mord mathnormal">a</span><span class="mord mathnormal">tt</span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.02778em;">r</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.311664em;"><span class="" style="top: -2.55em; margin-left: -0.02778em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span><span class="mclose">)</span></span></span><span class="" style="top: -3.01em;"><span class="pstrut" style="height: 3em;"></span><span class="mord"><span class="mord mathnormal">p</span><span class="mord mathnormal">ro</span><span class="mord mathnormal">p</span><span class="mord mathnormal">s</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mopen">(</span><span class="mord mathnormal">p</span><span class="mord mathnormal">ro</span><span class="mord"><span class="mord mathnormal">p</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.311664em;"><span class="" style="top: -2.55em; margin-left: 0em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right: 0.05724em;">j</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.286108em;"><span class=""></span></span></span></span></span></span><span class="mclose">)</span></span></span><span class="" style="top: -1.81em;"><span class="pstrut" style="height: 3em;"></span><span class="mord"><span class="mord mathnormal">p</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal">e</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right: 0.08125em;">H</span><span class="mord mathnormal" style="margin-right: 0.10903em;">TM</span><span class="mord mathnormal">L</span><span class="mpunct">,</span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mord mathnormal" style="margin-right: 0.05764em;">CSS</span><span class="mpunct">,</span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mord mathnormal" style="margin-right: 0.09618em;">J</span><span class="mord mathnormal" style="margin-right: 0.05764em;">S</span><span class="mclose">)</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 1.55em;"><span class=""></span></span></span></span></span><span class="arraycolsep" style="width: 0.5em;"></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></span></p>
<p>We do not really care about the final rendered value here. That’s a matter of implementation. The template choice is also most often directly related to the URL. Therefore, the <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mi>r</mi><mi>o</mi><mi>p</mi><mi>s</mi><mi>G</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow><annotation encoding="application/x-tex">propsGetter</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.87777em; vertical-align: -0.19444em;"></span><span class="mord mathnormal">p</span><span class="mord mathnormal">ro</span><span class="mord mathnormal">p</span><span class="mord mathnormal">s</span><span class="mord mathnormal">G</span><span class="mord mathnormal">e</span><span class="mord mathnormal">tt</span><span class="mord mathnormal" style="margin-right: 0.02778em;">er</span></span></span></span></span> is the most important function here, the function that computes the values needed for rendering based on the request.</p>
<p>Attributes of a request may be of different nature. We can represent them as a flat dictionary or a vector.</p>
<ul>
<li>Discrete and finite : the user id, some url parameters</li>
<li>Infinite, or continuous : the current date, some other url parameters</li>
</ul>
<p>So, there is an infinite number of requests if you consider all parameters, but you can build finite subsets if you consider only certain attributes of the request.</p>
<h4 id="takeaways">Takeaways</h4>
<ul>
<li>server-side rendering is just normal request processing. We don’t really care about the technology, any app with server-rendering is just a function that processes requests and outputs some results. If the result happens to be some HTML, CSS and JS, we call that rendering, but there is no strong difference with any other kind of API.</li>
<li>what matters are the value you will use to fill the blanks your template: the props.</li>
<li>build-time rendering, or “static” rendering, is just precomputed server-side rendering</li>
<li>the difference between build-time rendering (“static”) and request-time rendering (“ssr”) is mostly based on the render moment.<br>
In current implementations, the difference also lies in the nature of the request attributes you’ll want to consider to compute the result, although we consider this distinction mostly fictional.</li>
</ul>
<h2 id="when-build-time-rendering-is-possible">When build-time rendering is possible</h2>
<h3 id="build-time-rendering-is-precomputed-request-time-rendering">Build-time rendering is precomputed request-time rendering</h3>
<p>At build time, there is no HTTP request happening. Yet, build-time rendering is still heavily based on the concept of request, as explained before: it’s just server-side precomputation of a bunch of requests.</p>
<p>If a blog application builds 10 pages for 10 articles, it is actually precomputing 10 possible requests, one for each URL. Existing frameworks are often adopting this “URL” vision of build-time rendering.</p>
<p>Yet, they could also consider other request attributes such as cookies. For instance, you could prerender a dark mode and light mode version of your interface, based on a cookie.</p>
<p>Therefore, to keep our definition consistent, we can suppose that the render function is still using a request as input, except that it is limited to parameters you can know at build-time.</p>
<h3 id="what-can-be-built-the-3-static-rules-of-build-eligibility">What can be built: the 3 static rules of build-eligibility</h3>
<p>Intuitively, the build-time rendering-eligibility of a set of requests depends a lot on the attributes you actually consider in the request when picking the template and computing the template props.</p>
<p>Intuitively, if a website has 2 modes, light and dark, build-time rendering works. 10 articles on a blog, that works.<br>
But if an application wants to prerender one page per atom in the universe, it’ll be in trouble.</p>
<p>Let’s try to figure when build-time rendering is possible for a set of requests or not more formally. Since build-time rendering is precomputing some renders for a set of requests, let’s define the “build-eligibility” in terms of ensemble of possible requests.</p>
<p>To be eligible for build-time rendering, our set of requests must have following properties:</p>
<ol>
<li>It’s a subset of the set of all possible requests (the requests are valids and make sense, like URL are correct URLs etc.)</li>
<li>It must be a finite set, otherwise build time would be infinite</li>
<li>Values should be known at build time and stay constant afterward</li>
</ol>
<h3 id="formally-1">Formally</h3>
<p>Let’s note <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>R</mi></mrow><annotation encoding="application/x-tex">R</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.68333em; vertical-align: 0em;"></span><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span></span></span></span></span> the set of all possible HTTP requests in the world.</p>
<p>Let’s note <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>R</mi><mrow><mi>g</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow></msub></mrow><annotation encoding="application/x-tex">R_{getter}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.969438em; vertical-align: -0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.280556em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">tt</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.286108em;"><span class=""></span></span></span></span></span></span></span></span></span></span> the set of all requests that a <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mi>r</mi><mi>o</mi><mi>p</mi><mi>s</mi><mi>G</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow><annotation encoding="application/x-tex">propsGetter</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.87777em; vertical-align: -0.19444em;"></span><span class="mord mathnormal">p</span><span class="mord mathnormal">ro</span><span class="mord mathnormal">p</span><span class="mord mathnormal">s</span><span class="mord mathnormal">G</span><span class="mord mathnormal">e</span><span class="mord mathnormal">tt</span><span class="mord mathnormal" style="margin-right: 0.02778em;">er</span></span></span></span></span> takes as input. It depends on which part of the request <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mi>r</mi><mi>o</mi><mi>p</mi><mi>s</mi><mi>G</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow><annotation encoding="application/x-tex">propsGetter</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.87777em; vertical-align: -0.19444em;"></span><span class="mord mathnormal">p</span><span class="mord mathnormal">ro</span><span class="mord mathnormal">p</span><span class="mord mathnormal">s</span><span class="mord mathnormal">G</span><span class="mord mathnormal">e</span><span class="mord mathnormal">tt</span><span class="mord mathnormal" style="margin-right: 0.02778em;">er</span></span></span></span></span> is actually using to compute the props.</p>
<p>For instance, if we only use attribute 1 (say, the URL), and attribute 4 (say, the cookie that sets light or dark mode):<br>
<span class="katex--display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>R</mi><mrow><mi>g</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow></msub><mo>=</mo><msub><mi>R</mi><mrow><mo stretchy="false">{</mo><mi>a</mi><mi>t</mi><mi>t</mi><msub><mi>r</mi><mn>1</mn></msub><mo separator="true">,</mo><mi>a</mi><mi>t</mi><mi>t</mi><msub><mi>r</mi><mn>4</mn></msub><mo stretchy="false">}</mo></mrow></msub><mspace linebreak="newline"></mspace> <mo>⟺</mo> <mspace linebreak="newline"></mspace><mi mathvariant="normal">∀</mi><mi>r</mi><mi>e</mi><mi>q</mi><mo>∈</mo><msub><mi>R</mi><mrow><mi>g</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow></msub><mo separator="true">;</mo><mi>p</mi><mi>r</mi><mi>o</mi><mi>p</mi><mi>s</mi><mi>G</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi><mo stretchy="false">(</mo><mi>r</mi><mi>e</mi><mi>q</mi><mo stretchy="false">)</mo><mo>=</mo><mi>p</mi><mi>r</mi><mi>o</mi><mi>p</mi><mi>s</mi><mi>G</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi><mo stretchy="false">(</mo><mrow><mo stretchy="false">{</mo><mi>a</mi><mi>t</mi><mi>t</mi><msub><mi>r</mi><mn>1</mn></msub><mo separator="true">,</mo><mi>a</mi><mi>t</mi><mi>t</mi><msub><mi>r</mi><mn>4</mn></msub><mo stretchy="false">}</mo></mrow><mo stretchy="false">)</mo><mspace linebreak="newline"></mspace></mrow><annotation encoding="application/x-tex">
R_{getter} = R_{\{attr_1, attr_4\}} \\
\iff \\
\forall req \in R_{getter}; propsGetter(req) = propsGetter({\{attr_1, attr_4\}})\\
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.969438em; vertical-align: -0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.280556em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">tt</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.286108em;"><span class=""></span></span></span></span></span></span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 1.03853em; vertical-align: -0.3552em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.3448em;"><span class="" style="top: -2.5198em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">{</span><span class="mord mathnormal mtight">a</span><span class="mord mathnormal mtight">tt</span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">r</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.317314em;"><span class="" style="top: -2.357em; margin-left: -0.02778em; margin-right: 0.0714286em;"><span class="pstrut" style="height: 2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.143em;"><span class=""></span></span></span></span></span></span><span class="mpunct mtight">,</span><span class="mord mathnormal mtight">a</span><span class="mord mathnormal mtight">tt</span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">r</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.317314em;"><span class="" style="top: -2.357em; margin-left: -0.02778em; margin-right: 0.0714286em;"><span class="pstrut" style="height: 2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">4</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.143em;"><span class=""></span></span></span></span></span></span><span class="mclose mtight">}</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.3552em;"><span class=""></span></span></span></span></span></span></span><span class="mspace newline"></span><span class="base"><span class="strut" style="height: 0.549em; vertical-align: -0.024em;"></span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">⟺</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="mspace newline"></span><span class="base"><span class="strut" style="height: 0.88888em; vertical-align: -0.19444em;"></span><span class="mord">∀</span><span class="mord mathnormal">re</span><span class="mord mathnormal" style="margin-right: 0.03588em;">q</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">∈</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 1.03611em; vertical-align: -0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.280556em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">tt</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.286108em;"><span class=""></span></span></span></span></span></span><span class="mpunct">;</span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mord mathnormal">p</span><span class="mord mathnormal">ro</span><span class="mord mathnormal">p</span><span class="mord mathnormal">s</span><span class="mord mathnormal">G</span><span class="mord mathnormal">e</span><span class="mord mathnormal">tt</span><span class="mord mathnormal" style="margin-right: 0.02778em;">er</span><span class="mopen">(</span><span class="mord mathnormal">re</span><span class="mord mathnormal" style="margin-right: 0.03588em;">q</span><span class="mclose">)</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathnormal">p</span><span class="mord mathnormal">ro</span><span class="mord mathnormal">p</span><span class="mord mathnormal">s</span><span class="mord mathnormal">G</span><span class="mord mathnormal">e</span><span class="mord mathnormal">tt</span><span class="mord mathnormal" style="margin-right: 0.02778em;">er</span><span class="mopen">(</span><span class="mord"><span class="mopen">{</span><span class="mord mathnormal">a</span><span class="mord mathnormal">tt</span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.02778em;">r</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.301108em;"><span class="" style="top: -2.55em; margin-left: -0.02778em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mord mathnormal">a</span><span class="mord mathnormal">tt</span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.02778em;">r</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.301108em;"><span class="" style="top: -2.55em; margin-left: -0.02778em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">4</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span><span class="mclose">}</span></span><span class="mclose">)</span></span><span class="mspace newline"></span></span></span></span></span></p>
<p>Let’s note <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>R</mi><mi>B</mi></mrow><annotation encoding="application/x-tex">RB</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.68333em; vertical-align: 0em;"></span><span class="mord mathnormal" style="margin-right: 0.05017em;">RB</span></span></span></span></span> the set of all subsets of <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>R</mi></mrow><annotation encoding="application/x-tex">R</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.68333em; vertical-align: 0em;"></span><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span></span></span></span></span> that are build-eligible.</p>
<p>Picture it as any valid combination of attributes that can be used to compute the props, and still respect the 3 rules of build-eligibility. This is not useful to our reasonning but facilitates notation a lot, build-eligiblity can be written like this: <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>R</mi><mrow><mi>g</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow></msub><mo>⊂</mo><mi>R</mi><mi>B</mi></mrow><annotation encoding="application/x-tex">R_{getter} \subset RB</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.969438em; vertical-align: -0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.280556em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">tt</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.286108em;"><span class=""></span></span></span></span></span></span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">⊂</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.68333em; vertical-align: 0em;"></span><span class="mord mathnormal" style="margin-right: 0.05017em;">RB</span></span></span></span></span>.</p>
<p>So, a valid build-time request is any set of attributes that belongs to any valid <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>R</mi><mrow><mi>b</mi><mi>u</mi><mi>i</mi><mi>l</mi><mi>d</mi></mrow></msub></mrow><annotation encoding="application/x-tex">R_{build}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.83333em; vertical-align: -0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.336108em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">b</span><span class="mord mathnormal mtight">u</span><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right: 0.01968em;">l</span><span class="mord mathnormal mtight">d</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span></span></span></span></span> ensemble included in <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>R</mi><mi>B</mi></mrow><annotation encoding="application/x-tex">RB</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.68333em; vertical-align: 0em;"></span><span class="mord mathnormal" style="margin-right: 0.05017em;">RB</span></span></span></span></span>.</p>
<p>A build-eligible set of requests would have to respect those 3 conditions:</p>
<p><span class="katex--display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>R</mi><mrow><mi>b</mi><mi>u</mi><mi>i</mi><mi>l</mi><mi>d</mi></mrow></msub><mo>⊂</mo><mi>R</mi><mspace linebreak="newline"></mspace><mi mathvariant="normal">∣</mi><msub><mi>R</mi><mrow><mi>b</mi><mi>u</mi><mi>i</mi><mi>l</mi><mi>d</mi></mrow></msub><mi mathvariant="normal">∣</mi><mo><</mo><mi mathvariant="normal">∞</mi><mspace linebreak="newline"></mspace><msub><mi>R</mi><mrow><mi>b</mi><mi>u</mi><mi>i</mi><mi>l</mi><mi>d</mi></mrow></msub><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo><mo>=</mo><msub><mi>R</mi><mrow><mi>b</mi><mi>u</mi><mi>i</mi><mi>l</mi><mi>d</mi></mrow></msub></mrow><annotation encoding="application/x-tex">
R_{build} \subset R\\
|R_{build}| < \infty\\
R_{build}(t) = R_{build}
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.83333em; vertical-align: -0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.336108em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">b</span><span class="mord mathnormal mtight">u</span><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right: 0.01968em;">l</span><span class="mord mathnormal mtight">d</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">⊂</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.68333em; vertical-align: 0em;"></span><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span></span><span class="mspace newline"></span><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord">∣</span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.336108em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">b</span><span class="mord mathnormal mtight">u</span><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right: 0.01968em;">l</span><span class="mord mathnormal mtight">d</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span><span class="mord">∣</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel"><</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.43056em; vertical-align: 0em;"></span><span class="mord">∞</span></span><span class="mspace newline"></span><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.336108em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">b</span><span class="mord mathnormal mtight">u</span><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right: 0.01968em;">l</span><span class="mord mathnormal mtight">d</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.83333em; vertical-align: -0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.336108em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">b</span><span class="mord mathnormal mtight">u</span><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right: 0.01968em;">l</span><span class="mord mathnormal mtight">d</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span></span></span></span></span></span></p>
<p>Rule 1 is that obviously the request should make sense and be a “possible” request.</p>
<p>Rule 2 is the “rule of finiteness”</p>
<p>Rule 3 is the “rule of staticness”.</p>
<p>If <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>R</mi><mrow><mi>g</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow></msub></mrow><annotation encoding="application/x-tex">R_{getter}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.969438em; vertical-align: -0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.280556em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">tt</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.286108em;"><span class=""></span></span></span></span></span></span></span></span></span></span> respects all 3 conditions, it’s a build-eligible renderer, and it belongs to <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>R</mi><mi>B</mi></mrow><annotation encoding="application/x-tex">RB</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.68333em; vertical-align: 0em;"></span><span class="mord mathnormal" style="margin-right: 0.05017em;">RB</span></span></span></span></span>.</p>
<p>Build-time rendering is applying <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mi>e</mi><mi>n</mi><mi>d</mi><mi>e</mi><mi>r</mi><mi>e</mi><mi>r</mi></mrow><annotation encoding="application/x-tex">renderer</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.69444em; vertical-align: 0em;"></span><span class="mord mathnormal">re</span><span class="mord mathnormal">n</span><span class="mord mathnormal">d</span><span class="mord mathnormal" style="margin-right: 0.02778em;">erer</span></span></span></span></span> (and thus <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mi>r</mi><mi>o</mi><mi>p</mi><mi>s</mi><mi>G</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow><annotation encoding="application/x-tex">propsGetter</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.87777em; vertical-align: -0.19444em;"></span><span class="mord mathnormal">p</span><span class="mord mathnormal">ro</span><span class="mord mathnormal">p</span><span class="mord mathnormal">s</span><span class="mord mathnormal">G</span><span class="mord mathnormal">e</span><span class="mord mathnormal">tt</span><span class="mord mathnormal" style="margin-right: 0.02778em;">er</span></span></span></span></span>) to all <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mi>e</mi><mi>q</mi></mrow><annotation encoding="application/x-tex">req</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.625em; vertical-align: -0.19444em;"></span><span class="mord mathnormal">re</span><span class="mord mathnormal" style="margin-right: 0.03588em;">q</span></span></span></span></span> included in <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>R</mi><mrow><mi>g</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow></msub></mrow><annotation encoding="application/x-tex">R_{getter}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.969438em; vertical-align: -0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.280556em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">tt</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.286108em;"><span class=""></span></span></span></span></span></span></span></span></span></span>, supposing that <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>R</mi><mrow><mi>g</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow></msub><mo>⊂</mo><mi>R</mi><mi>B</mi></mrow><annotation encoding="application/x-tex">R_{getter} \subset RB</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.969438em; vertical-align: -0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.280556em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">tt</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.286108em;"><span class=""></span></span></span></span></span></span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">⊂</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.68333em; vertical-align: 0em;"></span><span class="mord mathnormal" style="margin-right: 0.05017em;">RB</span></span></span></span></span>.</p>
<p>We can now understand static rendering from an ensemblist point of view.</p>
<h2 id="an-abstract-implementation-of-build-time-rendering">An abstract implementation of build-time rendering</h2>
<p>Here are the typings and the final build-time rendering function:</p>
<pre class=" language-ts"><code class="prism language-ts"><span class="token keyword">type</span> Req <span class="token operator">=</span> Object
<span class="token keyword">type</span> Props <span class="token operator">=</span> Object
<span class="token keyword">type</span> Page <span class="token operator">=</span> <span class="token keyword">string</span> <span class="token comment">// some HTML</span>
<span class="token keyword">type</span> <span class="token function-variable function">RBuildComputer</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">Array</span><span class="token operator"><</span>Req<span class="token operator">></span> <span class="token comment">// must respect the build-eligbility conditions</span>
<span class="token keyword">type</span> <span class="token function-variable function">Template</span> <span class="token operator">=</span> <span class="token punctuation">(</span>Props<span class="token punctuation">)</span> <span class="token operator">=></span> Page
<span class="token keyword">type</span> <span class="token function-variable function">TemplateGetter</span> <span class="token operator">=</span> <span class="token punctuation">(</span>req<span class="token punctuation">:</span> Req<span class="token punctuation">)</span> <span class="token operator">=></span> Template
<span class="token keyword">type</span> <span class="token function-variable function">PropsGetter</span> <span class="token operator">=</span> <span class="token punctuation">(</span>req<span class="token punctuation">:</span> Req<span class="token punctuation">)</span> <span class="token operator">=></span> Props
<span class="token keyword">type</span> <span class="token function-variable function">Renderer</span> <span class="token operator">=</span> <span class="token punctuation">(</span>req<span class="token punctuation">:</span> Req<span class="token punctuation">)</span> <span class="token operator">=></span> Page <span class="token comment">// = TemplateGetter(Req)(PropsGetter(Req))</span>
</code></pre>
<p>Example for a blog:</p>
<pre class=" language-ts"><code class="prism language-ts"><span class="token keyword">function</span> <span class="token function">rBuildComputer</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">{</span>url<span class="token punctuation">:</span> <span class="token string">"article/1"</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> url<span class="token punctuation">:</span> <span class="token string">"article/2"</span><span class="token punctuation">}</span><span class="token punctuation">]</span> <span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">articleTemplate</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>articleId<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token template-string"><span class="token string">`Reading article </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>articleId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span> <span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">templateGetter</span> <span class="token punctuation">(</span>req<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span><span class="token function">match</span><span class="token punctuation">(</span><span class="token regex">/article/</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> articleTemplate
<span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token template-string"><span class="token string">`Default template`</span></span>
<span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">propsGetter</span> <span class="token punctuation">(</span>req<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token punctuation">{</span> articleId<span class="token punctuation">:</span> req<span class="token punctuation">.</span>params<span class="token punctuation">.</span>articleId <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">function</span> renderer <span class="token operator">=</span> <span class="token punctuation">(</span>req<span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token function">templateGetter</span><span class="token punctuation">(</span>req<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token function">propsGetter</span><span class="token punctuation">(</span>req<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p>The <code>rBuildComputer</code> function doesn’t feel very natural. That’s because requests are supposed to be random events, triggered by the user, so we are not used to list all the possible requests for a given endpoint.</p>
<p>Also, when actually serving the pages, this means you still need some request processing logic. The final HTML/CSS/JS result may be cached, the result of the <code>renderer</code> function, but you still need to check the request URL everytime to get the right page in this example.</p>
<p>We’ll describe how Next.js can solve a simplified version of this problem later-on.</p>
<h3 id="takeaways-1">Takeaways</h3>
<ul>
<li>By selecting the attributes you consider as input of your renderer function, you define an <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>R</mi><mrow><mi>g</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow></msub></mrow><annotation encoding="application/x-tex">R_{getter}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.969438em; vertical-align: -0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.280556em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">tt</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.286108em;"><span class=""></span></span></span></span></span></span></span></span></span></span> set. If it respects the 3 build rules, you can enjoy static rendering.</li>
<li>Example: rendering a finite number of blog articles. <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>R</mi><mrow><mi>g</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow></msub></mrow><annotation encoding="application/x-tex">R_{getter}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.969438em; vertical-align: -0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.280556em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">tt</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.286108em;"><span class=""></span></span></span></span></span></span></span></span></span></span> is the list of all your articles URL, it’s finite, doesn’t change. If you write a new article, you can of course rebuild to get fresh data (we’ll dig that problem later).</li>
<li>This is theoretical, in real life computing the set of all possible requests feels unnatural.</li>
<li>There is no such thing as a website without a server. Static hosts are just extremely basic server that can only process the URL part of the request, but they still do process the request.</li>
</ul>
<h2 id="rendering-at-request-time">Rendering at request time</h2>
<p>As soon as the request attributes used to render a page violate one of the 3 conditions to be a build-eligible set, this page cannot be build-time rendered anymore. This means the page should instead be rendered on-demand, either server-side per-request, or client-side.</p>
<p>Examples :</p>
<ul>
<li>One attribute is infinite. Say, the page is displaying the current date. You cannot prebuild for all dates.</li>
<li>One attribute is time-dependent. Request timestamp is an obvious example here, but it also violates the finiteness property so it’s not that interesting. A better example would be any kind of dynamic attribute. For example, the user id. The list of users evolves each time someone sign up on your website, so you cannot rebuild every time someone signs up.</li>
</ul>
<p>Let’s focus on this sentence : “you cannot rebuild every time X happens”. Actually, this condition probably depends on the build duration: an infinitely fast static renderer can be updated everytime its set of possible request change.</p>
<h3 id="the-4th-dynamic-rule-of-build-eligibility">The 4th dynamic rule of build-eligibility</h3>
<p>When a write publishes a new article on blog, or someone signs up to a SaaS product, the build-time rendered website becomes obsolete. A rebuild is needed.</p>
<p>Suppose that rendering time is constant for all requests, for the sake of simplicity.</p>
<p>That rendering time must be smaller than the time between 2 changes of the list of articles or the list of users, otherwise there is not enough time to rebuild the website.</p>
<p>Examples:</p>
<ul>
<li>the list of articles on a personal blog only evolves daily/weekly. A rebuild takes a few minutes: articles are eligible for build-time rendering</li>
<li>the list of users on a SaaS product evolves a lot, you can get 10 new users a day (or more, who knows): private pages are not eligible for build-time rendering</li>
</ul>
<h3 id="formally-2">Formally</h3>
<p>Let’s call it <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>t</mi><mrow><mi>r</mi><mi>e</mi><mi>n</mi><mi>d</mi><mi>e</mi><mi>r</mi></mrow></msub></mrow><annotation encoding="application/x-tex">t_{render}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.76508em; vertical-align: -0.15em;"></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.336108em;"><span class="" style="top: -2.55em; margin-left: 0em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">re</span><span class="mord mathnormal mtight">n</span><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span></span></span></span></span> the execution time of <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mi>e</mi><mi>n</mi><mi>d</mi><mi>e</mi><mi>r</mi><mi>e</mi><mi>r</mi></mrow><annotation encoding="application/x-tex">renderer</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.69444em; vertical-align: 0em;"></span><span class="mord mathnormal">re</span><span class="mord mathnormal">n</span><span class="mord mathnormal">d</span><span class="mord mathnormal" style="margin-right: 0.02778em;">erer</span></span></span></span></span>.</p>
<p>Let’s note the time for a variation of <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>R</mi><mrow><mi>g</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow></msub></mrow><annotation encoding="application/x-tex">R_{getter}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.969438em; vertical-align: -0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.280556em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">tt</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.286108em;"><span class=""></span></span></span></span></span></span></span></span></span></span> to happen <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>t</mi><mrow><mi mathvariant="normal">Δ</mi><msub><mi>R</mi><mrow><mi>g</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow></msub></mrow></msub></mrow><annotation encoding="application/x-tex">t_{\Delta R_{getter}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.9624em; vertical-align: -0.34732em;"></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.328331em;"><span class="" style="top: -2.55em; margin-left: 0em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">Δ</span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.296343em;"><span class="" style="top: -2.357em; margin-left: -0.00773em; margin-right: 0.0714286em;"><span class="pstrut" style="height: 2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">tt</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.281886em;"><span class=""></span></span></span></span></span></span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.34732em;"><span class=""></span></span></span></span></span></span></span></span></span></span>.</p>
<p><span class="katex--display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>t</mi><mrow><mi>r</mi><mi>e</mi><mi>n</mi><mi>d</mi><mi>e</mi><mi>r</mi></mrow></msub><mo>></mo><msub><mi>t</mi><mrow><mi mathvariant="normal">Δ</mi><msub><mi>R</mi><mrow><mi>g</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow></msub></mrow></msub> <mo>⟹</mo> <msub><mi>R</mi><mrow><mi>g</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow></msub><mo>⊄</mo><mi>R</mi><mi>B</mi><mspace linebreak="newline"></mspace></mrow><annotation encoding="application/x-tex">
t_{render} > t_{\Delta R_{getter}} \implies R_{getter} \not\subset RB \\
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.76508em; vertical-align: -0.15em;"></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.336108em;"><span class="" style="top: -2.55em; margin-left: 0em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">re</span><span class="mord mathnormal mtight">n</span><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">></span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.9624em; vertical-align: -0.34732em;"></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.328331em;"><span class="" style="top: -2.55em; margin-left: 0em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">Δ</span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.296343em;"><span class="" style="top: -2.357em; margin-left: -0.00773em; margin-right: 0.0714286em;"><span class="pstrut" style="height: 2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">tt</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.281886em;"><span class=""></span></span></span></span></span></span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.34732em;"><span class=""></span></span></span></span></span></span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">⟹</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.980548em; vertical-align: -0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.280556em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">tt</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.286108em;"><span class=""></span></span></span></span></span></span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel"><span class="mord vbox"><span class="thinbox"><span class="rlap"><span class="strut" style="height: 0.88888em; vertical-align: -0.19444em;"></span><span class="inner"><span class="mord"><span class="mrel"></span></span></span><span class="fix"></span></span></span></span></span></span><span class="base"><span class="strut" style="height: 0.5782em; vertical-align: -0.0391em;"></span><span class="mrel">⊂</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.68333em; vertical-align: 0em;"></span><span class="mord mathnormal" style="margin-right: 0.05017em;">RB</span></span><span class="mspace newline"></span></span></span></span></span></p>
<p>It means that if you can rebuild faster than the list of possible values, for all attributes, the build-eligibility still holds. But if you rebuild slower, it doesn’t not, you need request-time rendering.</p>
<h3 id="takeaways-2">Takeaways</h3>
<ul>
<li>there are actually 4 rules for build-eligibility, one of them depends on how fast the possible values evolves for each input attributes. Build-time rendering makes sense only for slowly changing values (a few seconds being a minimum, a few minutes more appropriate, a few days the best).</li>
<li>request-time server rendering is more an “exception” than the default. Build-time rendering should be preferred whenever possible.</li>
</ul>
<h2 id="next.js-vision-of-rendering">Next.js vision of rendering</h2>
<p>Let’s apply our model to Next.js (version 12, the most recent at the time of writing).</p>
<h3 id="a-page--a-template--a-props-getter-function">A page = a template + a props getter function</h3>
<p>In Next.js, a “page” is a React component tied to props computing functions, either build time or request time. It lives in the “/pages” folder of the application.</p>
<p>So, in our terminology, a Next.js “page” is a React template coupled with a props getter function <code>getServerSideProps</code> or <code>getStaticProps</code>.</p>
<h3 id="static-site-generation">Static Site Generation</h3>
<p>Static Site Generation is a form build-time rendering. However, it does accept only one attribute as input: the request URL.</p>
<p>This includes the URL parameters as well. So, a page always has a base path, for instance, <code>/blog/articles/:id</code>. In Next.js, this corresponds specifically to its position in the <code>pages</code> folder. But it can also have “parameterized paths”, which are called dynamic routes : that’s just the base path and some route parameters. For instance, <code>/blog/articles/12</code>.</p>
<p>So, Next implicitly defines an additional build-time eligibility rule like follow:<br>
<span class="katex--display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>R</mi><mrow><mi>g</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow></msub><mo>⊂</mo><mi>R</mi><mi>B</mi><mspace linebreak="newline"></mspace> <mo>⟹</mo> <mspace linebreak="newline"></mspace><mi mathvariant="normal">∀</mi><mi>r</mi><mi>e</mi><mi>q</mi><mo>∈</mo><msub><mi>R</mi><mrow><mi>g</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow></msub><mo separator="true">;</mo><mi>p</mi><mi>r</mi><mi>o</mi><mi>p</mi><mi>s</mi><mi>G</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi><mo stretchy="false">(</mo><mi>r</mi><mi>e</mi><mi>q</mi><mo stretchy="false">)</mo><mo>=</mo><mi>p</mi><mi>r</mi><mi>o</mi><mi>p</mi><mi>s</mi><mi>G</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi><mo stretchy="false">(</mo><mi>r</mi><mi>e</mi><msub><mi>q</mi><mrow><mo stretchy="false">{</mo><mi>u</mi><mi>r</mi><mi>l</mi><mo stretchy="false">}</mo></mrow></msub><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">
R_{getter} \subset RB \\
\implies \\
\forall req \in R_{getter}; propsGetter(req)= propsGetter(req_{\{url\}})
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.969438em; vertical-align: -0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.280556em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">tt</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.286108em;"><span class=""></span></span></span></span></span></span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">⊂</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.68333em; vertical-align: 0em;"></span><span class="mord mathnormal" style="margin-right: 0.05017em;">RB</span></span><span class="mspace newline"></span><span class="base"><span class="strut" style="height: 0.549em; vertical-align: -0.024em;"></span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">⟹</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="mspace newline"></span><span class="base"><span class="strut" style="height: 0.88888em; vertical-align: -0.19444em;"></span><span class="mord">∀</span><span class="mord mathnormal">re</span><span class="mord mathnormal" style="margin-right: 0.03588em;">q</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">∈</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 1.03611em; vertical-align: -0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.280556em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">tt</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.286108em;"><span class=""></span></span></span></span></span></span><span class="mpunct">;</span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mord mathnormal">p</span><span class="mord mathnormal">ro</span><span class="mord mathnormal">p</span><span class="mord mathnormal">s</span><span class="mord mathnormal">G</span><span class="mord mathnormal">e</span><span class="mord mathnormal">tt</span><span class="mord mathnormal" style="margin-right: 0.02778em;">er</span><span class="mopen">(</span><span class="mord mathnormal">re</span><span class="mord mathnormal" style="margin-right: 0.03588em;">q</span><span class="mclose">)</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 1.1052em; vertical-align: -0.3552em;"></span><span class="mord mathnormal">p</span><span class="mord mathnormal">ro</span><span class="mord mathnormal">p</span><span class="mord mathnormal">s</span><span class="mord mathnormal">G</span><span class="mord mathnormal">e</span><span class="mord mathnormal">tt</span><span class="mord mathnormal" style="margin-right: 0.02778em;">er</span><span class="mopen">(</span><span class="mord mathnormal">re</span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.03588em;">q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.3448em;"><span class="" style="top: -2.5198em; margin-left: -0.03588em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">{</span><span class="mord mathnormal mtight">u</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">r</span><span class="mord mathnormal mtight" style="margin-right: 0.01968em;">l</span><span class="mclose mtight">}</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.3552em;"><span class=""></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span></span><br>
The props must only depends on the considered route or URL. Otherwise you can’t use the static props computation functions provided by Next.</p>
<p>If we consider that all URLs for a page are known at build-time, we can render the page once for each possible URL. At runtime, all subsequent request on the same URL will get the same page.</p>
<p>Note: experience Next.js users might argue that middlewares, introduced in Next 12, can be used to bypass this limitation. They are right and this is addressed in a further section of this paper.</p>
<p>The main advantage of limiting static rendering to URLs is that it is easier to understand for Next.js end users and easier to manage at runtime.<br>
The request processing is limited to a bare minimum, since you only need to look at the base path to find the template, and the route parameters to compute the props.<br>
Intuitively, it’s easy to precompute all the possible paths for an app. Even if the values are dynamic, you simply need a few requests, for instance to get the list of articles from your CRM.</p>
<p>The limitation of this URL-based approach is that in order to get different props for a template, so a new variation of a page, we need a different URL. So if we want to build-time render a light and dark mode for the same route, we would need a route parameter just for that. You cannot get different props based on a cookie or a query parameter. Also, a lot of valid build-time attributes cannot be obtained just by looking at the URL. The application would also need to process the request cookies for instance, to tell if the user is authenticated or not.</p>
<p>Extending the rendering to other request parameters also requires stronger request processing capabilities, even for static content. “Edge” features introduced by both Vercel and Netlify hosts recently, in 2021, will alleviate this limitation in the future.</p>
<h3 id="server-side-rendering-1">“Server-Side Rendering”</h3>
<p>Next.js vision of request-time rendering is representative of what can be found in the industry. Note that for Next.js, SSR means request-time rendering specifically, while SSG (Static Site Generation) is preferred for build-time rendering.</p>
<h3 id="incremental-static-regeneration">Incremental Static Regeneration</h3>
<p>Formally, Incremental Static Rendering alleviates both the rule of finiteness and the rule of staticness for build-eligibility. Instead of rendering all the pages at build-time, you render them only on-demand. You can also re-render the pages more frequently, without rebuilding everything.</p>
<p>Since the number of requests that can hit a website is finite in a finite amount of time, it allows to stretch the build time infinitely.</p>
<p>Note: there is still a very minor hypothesis, that people don’t spam your website with so many different requests that it saturates your ability to render the pages. More formally, that they don’t map <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>R</mi><mrow><mi>g</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow></msub></mrow><annotation encoding="application/x-tex">R_{getter}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.969438em; vertical-align: -0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.280556em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">tt</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.286108em;"><span class=""></span></span></span></span></span></span></span></span></span></span> faster than <span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">∣</mi><msub><mi>R</mi><mrow><mi>g</mi><mi>e</mi><mi>t</mi><mi>t</mi><mi>e</mi><mi>r</mi></mrow></msub><mi mathvariant="normal">∣</mi><mo>∗</mo><msub><mi>t</mi><mrow><mi>r</mi><mi>e</mi><mi>n</mi><mi>d</mi><mi>e</mi><mi>r</mi></mrow></msub></mrow><annotation encoding="application/x-tex">|R_{getter}|*t_{render}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 1.03611em; vertical-align: -0.286108em;"></span><span class="mord">∣</span><span class="mord"><span class="mord mathnormal" style="margin-right: 0.00773em;">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.280556em;"><span class="" style="top: -2.55em; margin-left: -0.00773em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right: 0.03588em;">g</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">tt</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.286108em;"><span class=""></span></span></span></span></span></span><span class="mord">∣</span><span class="mspace" style="margin-right: 0.222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right: 0.222222em;"></span></span><span class="base"><span class="strut" style="height: 0.76508em; vertical-align: -0.15em;"></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.336108em;"><span class="" style="top: -2.55em; margin-left: 0em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">re</span><span class="mord mathnormal mtight">n</span><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight" style="margin-right: 0.02778em;">er</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span></span></span></span></span>.</p>
<p>And also, that the possible values still evolves relatively slowly, otherwise user will still get stale data. If the cache time to live is too short, you end up with usual server-side rendering, which defeats the purpose of ISR.</p>
<p>There is still a strong limitation: props are still entirely defined by the URL. It was not possible to process the request with a custom function in the current implementation, until Next.js introduced middlewares.</p>
<h2 id="a-unified-api-for-server-rendering-be-it-build-time-request-time-or-somewhere-in-between">A unified API for server-rendering, be it build-time, request-time, or somewhere in between</h2>
<p>Based on our model, here is what could be a unified view of server-rendering:</p>
<pre class=" language-ts"><code class="prism language-ts"><span class="token comment">// The actual page, written with a SPA framework like React, Vue, Svelte...</span>
<span class="token keyword">type</span> <span class="token function-variable function">Page</span> <span class="token operator">=</span> <span class="token punctuation">(</span>props<span class="token punctuation">:</span> Props<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">[</span>HTML<span class="token punctuation">,</span> CSS<span class="token punctuation">,</span> JS<span class="token punctuation">]</span>
<span class="token comment">// Compute the requests we want to prerender</span>
<span class="token comment">// Example : all the articles of a blog</span>
<span class="token keyword">type</span> <span class="token function-variable function">computePossibleRequests</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> Promise<span class="token operator"><</span><span class="token keyword">Array</span><span class="token operator"><</span>Request<span class="token operator">>></span>
<span class="token comment">// For a given request, compute the right props</span>
<span class="token comment">// Example : get the article 42 when URL is « /article/42 »</span>
<span class="token keyword">type</span> <span class="token function-variable function">propsGetter</span> <span class="token operator">=</span> <span class="token punctuation">(</span>req<span class="token punctuation">:</span> Request<span class="token punctuation">)</span><span class="token operator">=></span> Promise<span class="token operator"><</span>Props<span class="token operator">></span>
<span class="token comment">// Time the rendered page should stay in the cache for a given set of props</span>
<span class="token keyword">type</span> TTL <span class="token punctuation">:</span> Number
</code></pre>
<p>Yes, build-time static rendering is just server-side rendering with a cache + precomputed requests.<br>
For instance, Next.js differentiation between <code>getServerSideProps</code> (SSR) and <code>getStaticProps</code> (SSG) is a relevant implementation choice, but a still an implementation choice. It is possible to imagine other implementation of server-rendering that blurs the line between the different possible “render moments”.</p>
<p>Exemple implementation for paid pages on a blog:</p>
<pre class=" language-ts"><code class="prism language-ts"><span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">BlogPage</span> <span class="token operator">=</span> <span class="token punctuation">(</span>props<span class="token punctuation">:</span> Props<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span>
<span class="token operator"><</span>div<span class="token operator">></span>
<span class="token operator"><</span>p<span class="token operator">></span><span class="token punctuation">{</span>props<span class="token punctuation">.</span>paidArticle<span class="token punctuation">.</span>title<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span>
<span class="token operator"><</span>p<span class="token operator">></span><span class="token punctuation">{</span>props<span class="token punctuation">.</span>paidArticle<span class="token punctuation">.</span>content<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span>
<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span>
<span class="token punctuation">)</span>
<span class="token comment">// The requests you'd like to precompute</span>
<span class="token comment">// In Next.js, this is currently limited to a list of URLs for public content.</span>
<span class="token comment">// Here, we also want to pre-render private paid articles.</span>
<span class="token comment">// When the user opens the page:</span>
<span class="token comment">// 1. An upfront middleware/server checks authentication, subscription</span>
<span class="token comment">// and set the right headers securely (X-PAID in this example).</span>
<span class="token comment">// 2. If the url params + headers are matching an existing pre-rendered</span>
<span class="token comment">// request, the page will be rendered immediately.</span>
<span class="token comment">// 2bis. If there is no match, it will lead to a 404 (but you could</span>
<span class="token comment">// have a smarter strategy, like letting the upfront server redirect the user</span>
<span class="token comment">// to a "/subscription" page)</span>
<span class="token keyword">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> computePossibleRequests <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">Array</span><span class="token operator"><</span>Request<span class="token operator">></span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> paidArticles <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetchPaidArticles</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> paidArticles<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>article <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
urlParams<span class="token punctuation">:</span> <span class="token punctuation">{</span> id<span class="token punctuation">:</span> article<span class="token punctuation">.</span>id<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// those articles are only available to paid users</span>
header<span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token string">"X-PAID"</span><span class="token punctuation">:</span> <span class="token keyword">true</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token comment">// This function will be run during static render </span>
<span class="token comment">// for all the private articles of the database, </span>
<span class="token comment">// and also be run during request-time render</span>
<span class="token comment">// There is no way to tell whether it's static or request-time render, </span>
<span class="token comment">// because you don't need to! </span>
<span class="token comment">// Think of Next.js getInitialProps, but with the request also available</span>
<span class="token comment">// during static render</span>
<span class="token keyword">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">propsGetter</span><span class="token punctuation">(</span>req<span class="token punctuation">:</span> Request<span class="token punctuation">)</span><span class="token punctuation">:</span> Props <span class="token punctuation">{</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> urlParams<span class="token punctuation">,</span> header <span class="token punctuation">}</span> <span class="token operator">=</span> req
<span class="token keyword">const</span> privateArticle <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetchPrivateArticle</span><span class="token punctuation">(</span>urlParams<span class="token punctuation">.</span>id<span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token punctuation">{</span> privateArticle <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// we rerun propsGetter every minute to get a fresh version of the article</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> TTL_MS <span class="token operator">=</span> <span class="token number">60000</span>
</code></pre>
<p>Possible scenarios depending on the caching strategy:</p>
<ul>
<li><span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi><mi>T</mi><mi>L</mi><mo>=</mo><mi mathvariant="normal">∞</mi></mrow><annotation encoding="application/x-tex">TTL = \infty</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.68333em; vertical-align: 0em;"></span><span class="mord mathnormal" style="margin-right: 0.13889em;">TT</span><span class="mord mathnormal">L</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.43056em; vertical-align: 0em;"></span><span class="mord">∞</span></span></span></span></span> => this is static rendering. You must define <code>computePossibleRequests</code> as well, to get the list of pages to render.</li>
<li><span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi><mi>T</mi><mi>L</mi><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">TTL = 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.68333em; vertical-align: 0em;"></span><span class="mord mathnormal" style="margin-right: 0.13889em;">TT</span><span class="mord mathnormal">L</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.64444em; vertical-align: 0em;"></span><span class="mord">0</span></span></span></span></span> => this is server-side rendering.</li>
<li><span class="katex--inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi><mi>T</mi><mi>L</mi><mo>=</mo><mi>X</mi><mo separator="true">;</mo><mn>0</mn><mo><</mo><mi>X</mi><mo><</mo><mi mathvariant="normal">∞</mi></mrow><annotation encoding="application/x-tex">TTL = X; 0 < X < \infty</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 0.68333em; vertical-align: 0em;"></span><span class="mord mathnormal" style="margin-right: 0.13889em;">TT</span><span class="mord mathnormal">L</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.87777em; vertical-align: -0.19444em;"></span><span class="mord mathnormal" style="margin-right: 0.07847em;">X</span><span class="mpunct">;</span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mord">0</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel"><</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.72243em; vertical-align: -0.0391em;"></span><span class="mord mathnormal" style="margin-right: 0.07847em;">X</span><span class="mspace" style="margin-right: 0.277778em;"></span><span class="mrel"><</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.43056em; vertical-align: 0em;"></span><span class="mord">∞</span></span></span></span></span> => this is incremental static regeneration. You may want to prerender some pages as well.</li>
<li>If <code>propsGetter</code> always return a new value (say it includes current time for instance), TTL should be set at zero. Otherwise memory will explode because of useless caching.</li>
<li>You can always define <code>computePossibleRequests</code> to precompute some pages at build-time, for an hybridation between static render and server render (that’s the point of ISR).</li>
</ul>
<h2 id="implementation-in-real-life-framework">Implementation in real-life framework</h2>
<p>As far as we can tell, no existing framework implements the API we propose out-of-the-box.</p>
<p>However, the introduction of a middleware system in Next.js, coupled with “Incremental Static Regeneration”, let’s us get as close as possible from an optimal static rendering with a minimal setup.</p>
<p>We used a palliative approach based on route parameters to simulate the precomputation of a set of request. The parameter encodes other attributes such as headers, cookies.</p>
<p>This implementation is further described in this informal article: <a href="https://blog.vulcanjs.org/render-anything-statically-with-next-js-and-the-megaparam-4039e66ffde">https://blog.vulcanjs.org/render-anything-statically-with-next-js-and-the-megaparam-4039e66ffde</a><br>
Code: <a href="https://github.com/VulcanJS/vulcan-next/blob/devel/src/pages/vn/examples/%5BM%5D/megaparam-demo.tsx">https://github.com/VulcanJS/vulcan-next/blob/devel/src/pages/vn/examples/[M]/megaparam-demo.tsx</a><br>
Implementation:</p>
<p><a href="https://github.com/VulcanJS/vulcan-next/blob/devel/src/pages/vn/examples/%5BM%5D/megaparam-demo.tsx">https://github.com/VulcanJS/vulcan-next/blob/devel/src/pages/vn/examples/[M]/megaparam-demo.tsx</a></p>
<h2 id="conclusion">Conclusion</h2>
<p>We hope this paper could form the basis of a unified vision of server-side rendering, that is implementation independent.<br>
Whether a framework favours per-request or build-time rendering, we can adopt an ensemblist point of view to judge its ability to reach an optimal number of renders, that is mapping each possible request exactly once to a response.</p>
<p>Technical implementation could involve either a proxy server for picking the right statically rendered variation, a cache to avoid unnecessary request-time render, or even a machine learning algorithm that could predict incoming requests and prerender pages accordingly.</p>
<p>This vision could be helpful in the task of designing energy-efficient frameworks, that render content only when strictly necessary, while still providing a feature-rich, dynamic experience to the end-user.</p>
<h3 id="changelog">Changelog</h3>
<ul>
<li>07/2021 - first draft</li>
<li>09/2021 - better example for the generic SSR API</li>
<li>11/2021 - Adding abstract, started to add related work, linking a working implementation, formalizing concepts</li>
</ul>
</div>
</div>
</body>
</html>