Offline fallback page with service worker

Years ago, I did some research into how native applications responded to a lack of network connectivity. Whilst I’ve lost the link to the analysis (I could swear it was on Google+), the overarching narrative was that many native applications are inextricably tied to the internet that they just straight up refuse to function. Sounds like a lot of web apps, the thing that set them apart from the web though is that the experience was still ‘on-brand’, Bart Simpson would tell you that you need to be online (for example), and yet for the vast majority of web experiences you get a ‘Dino’ (see chrome://dino).


This content originally appeared on Modern Web Development with Chrome and was authored by Paul Kinlan

<p>Years ago, I did some research into how native applications responded to a lack of network connectivity. Whilst I've lost the link to the analysis (I could swear it was on Google+), the overarching narrative was that many native applications are inextricably tied to the internet that they just straight up refuse to function. Sounds like a lot of web apps, the thing that set them apart from the web though is that the experience was still 'on-brand', Bart Simpson would tell you that you need to be online (for example), and yet for the vast majority of web experiences you get a 'Dino' (see chrome://dino).</p> <p>We've been working on Service Worker for a long time now, and whilst we are seeing more and more sites have pages controlled by a Service Worker, the vast majority of sites don't even have a basic fallback experience when the network is not available.</p> <p>I asked my good chum Jake if we have any guindance on how to build a generic fall-back page on the assumption that you don't want to create an entirely offline-first experience, and within 10 minutes he had created it. <a href="https://glitch.com/edit/#!/static-misc?path=sw-fallback-page/sw.js:6:9">Check it out</a>.</p> <p>For brevity, I have pasted the code in below because it is only about 20 lines long. It caches the offline assets, and then for every fetch that is a 'navigation' fetch it will see if it errors (because of the network) and then render the offline page in place of the original content.</p> <div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-JavaScript" data-lang="JavaScript"><span style="color:#a6e22e">addEventListener</span>(<span style="color:#e6db74">'install'</span>, (<span style="color:#a6e22e">event</span>) => { <span style="color:#a6e22e">event</span>.<span style="color:#a6e22e">waitUntil</span>(<span style="color:#a6e22e">async</span> <span style="color:#66d9ef">function</span>() { <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">cache</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">await</span> <span style="color:#a6e22e">caches</span>.<span style="color:#a6e22e">open</span>(<span style="color:#e6db74">'static-v1'</span>); <span style="color:#a6e22e">await</span> <span style="color:#a6e22e">cache</span>.<span style="color:#a6e22e">addAll</span>([<span style="color:#e6db74">'offline.html'</span>, <span style="color:#e6db74">'styles.css'</span>]); }()); }); <span style="color:#75715e">// See https://developers.google.com/web/updates/2017/02/navigation-preload#activating_navigation_preload </span><span style="color:#75715e"></span><span style="color:#a6e22e">addEventListener</span>(<span style="color:#e6db74">'activate'</span>, <span style="color:#a6e22e">event</span> => { <span style="color:#a6e22e">event</span>.<span style="color:#a6e22e">waitUntil</span>(<span style="color:#a6e22e">async</span> <span style="color:#66d9ef">function</span>() { <span style="color:#75715e">// Feature-detect </span><span style="color:#75715e"></span> <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">self</span>.<span style="color:#a6e22e">registration</span>.<span style="color:#a6e22e">navigationPreload</span>) { <span style="color:#75715e">// Enable navigation preloads! </span><span style="color:#75715e"></span> <span style="color:#a6e22e">await</span> <span style="color:#a6e22e">self</span>.<span style="color:#a6e22e">registration</span>.<span style="color:#a6e22e">navigationPreload</span>.<span style="color:#a6e22e">enable</span>(); } }()); }); <span style="color:#a6e22e">addEventListener</span>(<span style="color:#e6db74">'fetch'</span>, (<span style="color:#a6e22e">event</span>) => { <span style="color:#66d9ef">const</span> { <span style="color:#a6e22e">request</span> } <span style="color:#f92672">=</span> <span style="color:#a6e22e">event</span>; <span style="color:#75715e">// Always bypass for range requests, due to browser bugs </span><span style="color:#75715e"></span> <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">request</span>.<span style="color:#a6e22e">headers</span>.<span style="color:#a6e22e">has</span>(<span style="color:#e6db74">'range'</span>)) <span style="color:#66d9ef">return</span>; <span style="color:#a6e22e">event</span>.<span style="color:#a6e22e">respondWith</span>(<span style="color:#a6e22e">async</span> <span style="color:#66d9ef">function</span>() { <span style="color:#75715e">// Try to get from the cache: </span><span style="color:#75715e"></span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">cachedResponse</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">await</span> <span style="color:#a6e22e">caches</span>.<span style="color:#a6e22e">match</span>(<span style="color:#a6e22e">request</span>); <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">cachedResponse</span>) <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">cachedResponse</span>; <span style="color:#66d9ef">try</span> { <span style="color:#75715e">// See https://developers.google.com/web/updates/2017/02/navigation-preload#using_the_preloaded_response </span><span style="color:#75715e"></span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">response</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">await</span> <span style="color:#a6e22e">event</span>.<span style="color:#a6e22e">preloadResponse</span>; <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">response</span>) <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">response</span>; <span style="color:#75715e">// Otherwise, get from the network </span><span style="color:#75715e"></span> <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">await</span> <span style="color:#a6e22e">fetch</span>(<span style="color:#a6e22e">request</span>); } <span style="color:#66d9ef">catch</span> (<span style="color:#a6e22e">err</span>) { <span style="color:#75715e">// If this was a navigation, show the offline page: </span><span style="color:#75715e"></span> <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">request</span>.<span style="color:#a6e22e">mode</span> <span style="color:#f92672">===</span> <span style="color:#e6db74">'navigate'</span>) { <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">caches</span>.<span style="color:#a6e22e">match</span>(<span style="color:#e6db74">'offline.html'</span>); } <span style="color:#75715e">// Otherwise throw </span><span style="color:#75715e"></span> <span style="color:#66d9ef">throw</span> <span style="color:#a6e22e">err</span>; } }()); }); </code></pre></div><p>That is all. When the user is online they will see the default experience.</p> <figure><img src="https://paul.kinlan.me/images/2019-04-05-offline-fallback-page-with-service-worker-0.jpeg"></figure> <p>And when the user is offline, they will get the fallback page.</p> <figure><img src="https://paul.kinlan.me/images/2019-04-05-offline-fallback-page-with-service-worker-1.jpeg"></figure> <p>I find this simple script incredibly powerful, and yes, whilst it can still be improved, I do believe that even just a simple change in the way that we speak to our users when there is an issue with the network has the ability to fundamentally improve the perception of the web for users all across the globe.</p> <p><strong>Update</strong> Jeffrey Posnick kinldy reminded me about using Navigation Preload to not have to wait on SW boot for all requests, this is especially important if you are only controlling <em>failed</em> network requests.</p>


This content originally appeared on Modern Web Development with Chrome and was authored by Paul Kinlan


Print Share Comment Cite Upload Translate Updates
APA

Paul Kinlan | Sciencx (2019-04-05T18:17:22+00:00) Offline fallback page with service worker. Retrieved from https://www.scien.cx/2019/04/05/offline-fallback-page-with-service-worker/

MLA
" » Offline fallback page with service worker." Paul Kinlan | Sciencx - Friday April 5, 2019, https://www.scien.cx/2019/04/05/offline-fallback-page-with-service-worker/
HARVARD
Paul Kinlan | Sciencx Friday April 5, 2019 » Offline fallback page with service worker., viewed ,<https://www.scien.cx/2019/04/05/offline-fallback-page-with-service-worker/>
VANCOUVER
Paul Kinlan | Sciencx - » Offline fallback page with service worker. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2019/04/05/offline-fallback-page-with-service-worker/
CHICAGO
" » Offline fallback page with service worker." Paul Kinlan | Sciencx - Accessed . https://www.scien.cx/2019/04/05/offline-fallback-page-with-service-worker/
IEEE
" » Offline fallback page with service worker." Paul Kinlan | Sciencx [Online]. Available: https://www.scien.cx/2019/04/05/offline-fallback-page-with-service-worker/. [Accessed: ]
rf:citation
» Offline fallback page with service worker | Paul Kinlan | Sciencx | https://www.scien.cx/2019/04/05/offline-fallback-page-with-service-worker/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.