-
The last week or so I've been exploring some cool ideas with using server-side rendering (#SSR) in #rules_prerender. Sounds simple, but actually has some very results, I'm really excited about this and I want to share why. 👇 github.com/dgp1130/rules_prerender/tree/ref/ssr/examples/ssr/
-
#rules_prerender is already designed as a static-site generator (#SSG) built on #Bazel and supports bundling and loading of browser #JavaScript for client-side rendering (#CSR). Adding SSR is just one more aspect, but notice anything from this web page? github.com/dgp1130/rules_prerender/tree/ref/ssr/examples/ssr/mixed_component
-
It includes SSG, SSR, and CSR, but *all three* are used on the same page, interchangeably. I even included environment-specific information to prove it and duplicated the items to show that any order is possible.
-
This works by rendering everything possible at build-time, with placeholders for SSR content. When the server starts, it loads this content and parses out the SSR placeholders. Each request invokes the SSR piece and stitches it together in the full document.
-
Not only that, but since SSR is a slice of a component, its content can compose *another* component using some combination of SSG / SSR / CSR. Here, we have an outer component's SSR slice wrapping an inner component with SSG and SSR data. Time travel! github.com/dgp1130/rules_prerender/tree/ref/ssr/examples/ssr/composition_component
-
The server even supports streaming. Any SSG content is automatically streamed to the client and SSR content can support streaming by simply implementing a generator API. In this example, each item takes 50ms to load but is delivered to the client ASAP. github.com/dgp1130/rules_prerender/tree/ref/ssr/examples/ssr/streaming_component
-
Not only that, but all (top-level) SSR components invoked concurrently. So even if two make slow database queries, they won't block on each other. Here, each item takes 1sec to load. Since they are started at the same time, they finish in 1sec, not 10! github.com/dgp1130/rules_prerender/tree/ref/ssr/examples/ssr/concurrent_component
-
The actual APIs are pretty simple IMHO. An SSR component is simply a class with a render function which returns a string. It defines build-time data required as input, registers itself with the server, and defines its types, much like #WebComponents. github.com/dgp1130/rules_prerender/blob/ref/ssr/examples/ssr/foo_component/foo_ssr.ts
-
At build-time, we can "slot" in an SSR piece by simply giving the registered name and the required build-time data. github.com/dgp1130/rules_prerender/blob/ref/ssr/examples/ssr/foo_component/foo_prerender.ts
-
Async SSR is of course supported and streaming is done by simply making the
render()
function a generator. Justyield
any HTML content you want to return and the server will handle the rest. github.com/dgp1130/rules_prerender/blob/ref/ssr/examples/ssr/streaming_component/streaming_ssr.ts -
I know SSG and SSR aren't new things, but I think the technology here is pretty cool, particularly how things can interleave in the same page seamlessly and how data is effortlessly transferred from a build-time context to a server context.
-
As cool as this is, I'm not yet convinced this is a good idea. I'm still skeptical about the usefulness of intermixing SSG and SSR content on the same page. Is it that much worse to just SSR the whole page? Would you find this kind of feature useful?
-
I had a lot of fun prototyping and playing around with this, so I wanted to share. I'm sure I'm not the first to try intermixing SSG and SSR on the same page but it worked out better than I expected and got me really excited. Let me know what you think! github.com/dgp1130/rules_prerender/discussions/44