24

How can one do SSR (Server side rendering) with PWA (Progressive web app)?

From what I understand,

SSR

The SSR runtime will load the page and run the necessary scripts to load the data on to the page. Then returns the rendered html. This is important for web crawlers which will not run javascript and browsers with no-script. At least the first impression will be usable.

PWA

Among others, PWA requires having a shell, which will be cached and the data will come after it. This means, even if the user is offline, the shell will be loaded.

?

So, if we're pre rendering the data, how can one cache the shell separate from the data?

Community
  • 1
  • 1
Amanuel Nega
  • 1,899
  • 1
  • 24
  • 42
  • 1
    PWAs do not require shells. That is just a common pattern. SSR with a PWA isn't much different from SSR with an SPA. The PWA should still cache the SPA parts and probably not the SSR parts. – abraham Jun 05 '18 at 15:44

3 Answers3

10

If you want to only cache shell from prerendered SSR view with initial data you must provide two views:

  1. /view-url with data from SSR
  2. /view-url?shell with only shell version, without data (you can change logic from url-query to for example request header).

When user for the first time enter /view-url you send 1. version and cache in Service Worker /view-url?shell. When user come back to /view-url you send him /view-url?shell from Service Worker cache by doing something like this:

const CACHE_NAME = 'cache-token';
const staticUrlsToCache = ['/style.css', '/script.js', '/logo.png'];
const shellUrlsToCache = ['/view-url'];
const urlsToCache = [
    ...staticUrlsToCache,
    shellUrlsToCache.map(url => `${url}?shell`),
];

self.addEventListener('install', event => {
    event.waitUntil(
        caches.open(CACHE_NAME).then(cache => cache.addAll(urlsToCache))
    );
});

self.addEventListener('fetch', event => {
    let request = event.request;

    const shellUrl = shellUrlsToCache.find(url => request.url.endsWith(url));
    if (shellUrl) {
        // here is real magic!
        request = new Request(`${shellUrl}?shell`);
    }

    event.respondWith(
        caches.match(request).then(response => response || fetch(request))
    );
});

The key point here is that you change original request /view-url to /view-url?shell in Service Worker!

If you want to read more about this technique I wrote an article about this problem How to combine PWA and isomorphic rendering (SSR)?

Everettss
  • 15,475
  • 9
  • 72
  • 98
0

The strategy is to serve the first page loading using SSR and all following page navigations using the cached app shell. SSR returns different html for different pages, so we can specify a special path like /app-shell to fetch a skeleton html for client side rendering.

If you want to learn more about it, you can refer to my article How To Turn a Server-Side-Rendered React SPA Into a PWA.

0

You should use workbox library by google - look at these docs on how to cache routes by using the workbox-routing module.

Here are also some common recipes or approaches to handle caching in any type of a web app.

Maye Edwin
  • 49
  • 5