An instant multi-page app

This is a demo of a instantly loading multi-page app, using modern web technology like Service Worker, ReadableStream and CSS Containment.

The purpose is to demonstrate that a multi-page app can load just as fast as a single-page app, without all the added complexity that a single-page app brings.

Each request is intercepted by the Service Worker which then constructs each page from a header, footer and the page content. These parts are all separate HTML templates that are fetched separately and then put together to form a page.

To make sure that content is shown to the user as soon as possible, a ReadableStream is used to stream content to the browser. This means that the browser doesn't need to wait for the whole response to arrive, but can start rendering content as soon as it becomes available.

The Service Worker also caches all assets locally so these no longer need to be fetched from the network.

The result is that each page loads instantly, just like a single-page app, even though the browser performs a full page reload for each page.

This effectively reduces single-page apps to a polyfill.

How it works

The trick to making multi-page apps blazing fast is utilizing the browser's streaming HTML parser.

The browser renders HTML while it downloads. It doesn't need to wait for the whole response to arrive, but it can start rendering content as soon as it becomes available.

We can leverage this by having a Service Worker fetch all the content we need and have it stream everything to the browser.

The Service Worker will then intercept any outgoing request, fetch the header and footer and then determine which body content it needs to fetch. This can be just a simple HTML template or a combination of a template and some data fetched from the network.

The Service Worker will then combine these parts to a full HTML page and return it to the browser. It's like server-side rendering, but it's all done on the client-side in a streaming manner, using a ReadableStream.

This means it can start rendering the header of the page while the content and footer are still downloading, giving a huge performance benefit.

The demo contains some simple text pages, a page with some large images and a page containing some postings from my blog which are dynamically fetched, combined into a large HTML page and then cached.

You will notice that even the large blog page and the page containing the large images load nearly instantly, even though every page requires a full page reload.

This is how good browsers are at rendering the DOM if we use the streaming HTML parser.

You can find the source code of this demo on Github.