How can one do SSR (Server side rendering) with PWA (Progressive web app)?
From what I understand,
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.
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?
One of the main arguments for why (though CSR is making significant strides in that direction which we'll explore in more detail later), is that SSR has traditionally been the better choice in the context of search engine optimisation (SEO) because SSR pages are more accessible to search engine bots and crawlers.
A central benefit of a PWA is that it provides a faster experience for users. You can further optimize the loading speed by having the PWA use cache-first networking, prioritizing resources, and use adaptive loading based on network quality.
To build PWAs locally, you need a web server to serve your files or bundle. For example, https://localhost:3000 —I 'm using Live Server on Visual Studio Code for demo purposes.
Despite their progressiveness, these are still web apps. Without access to device hardware, PWAs can't support such native-app typical features as fingerprint scanning, vicinity sensors, NFC, Bluetooth, geofencing, inter-app communications, and advanced camera controls.
If you want to only cache shell from prerendered SSR view with initial data you must provide two views:
/view-url
with data from SSR/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)?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With