{"id":361001,"date":"2022-01-18T06:30:26","date_gmt":"2022-01-18T14:30:26","guid":{"rendered":"https:\/\/css-tricks.com\/?p=361001"},"modified":"2022-01-18T06:30:29","modified_gmt":"2022-01-18T14:30:29","slug":"vitepwa-plugin-offline-service-worker","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/vitepwa-plugin-offline-service-worker\/","title":{"rendered":"Making a Site Work Offline Using the VitePWA Plugin"},"content":{"rendered":"\n
The VitePWA plugin<\/a> from Anthony Fu<\/a> is a fantastic tool for your Vite-powered sites. It helps you add a service worker that handles:<\/p>\n\n\n\n We\u2019ll walk through the concept of service workers together, then jump right into making one with the VitePWA plugin.<\/p>\n\n\n\n\n\n\n\n New to Vite? Check out my prior post<\/a> for an introduction.<\/p>\n\n\n Before getting into the VitePWA plugin, let\u2019s briefly talk about the Service Worker<\/a> itself.<\/p>\n\n\n\n A service worker<\/dfn> is a background process that runs on a separate thread in your web application. Service workers have the ability to intercept network requests and do\u2026 anything. The possibilities are surprisingly wide. For example, you could intercept requests for TypeScript files and compile them on the fly. Or you could intercept requests for video files and perform an advanced transcoding that the browser doesn\u2019t currently support. More commonly though, a service worker is used to cache assets, both to improve a site\u2019s performance and enable it to do something<\/em> when it\u2019s offline.<\/p>\n\n\n\n When someone first lands on your site, the service worker the VitePWA plugin creates installs, and caches all of your HTML, CSS, and JavaScript files by leveraging the Cache Storage API<\/a>. The result is that, on subsequent visits to your site, the browser will load those resources from cache, rather than needing to make network requests. And even on the first visit to your site, since the service worker just<\/em> pre-cached everything, the next place your user clicks will probably be pre-cached already, allowing the browser to completely bypass a network request.<\/p>\n\n\n You might be wondering what happens with a service worker when your code is updated. If your service worker is caching, say, a But in practice you don\u2019t have a It turns out the Service Worker API is an extremely<\/em> low-level primitive. If you\u2019re looking for a native turnkey solution between it and the cache API, you\u2019ll be disappointed. Basically, the creation of your service worker needs to be automated, in part, and connected to the build system.<\/strong> You\u2019d need to see all the assets your build created, hard-code those file names into the service worker, have code to pre-cache them, and more importantly, keep track of<\/em> the files that are cached.<\/p>\n\n\n\n If code updates, the service worker file also changes, containing the new<\/em> filenames, complete with hashes. When a user makes their next visit to the app, the new service worker will need to install, and compare the new file manifest with the manifest that\u2019s currently in cache, ejecting files that are no longer needed, while caching the new content.<\/p>\n\n\n\n This is an absurd amount of work and incredibly difficult to get right. While it can be a fun project, in practice you\u2019ll want to use an established product to generate your service worker \u2014 and the best product around is Workbox<\/a>, which is from the folks at Google.<\/p>\n\n\n\n Even Workbox is a bit of a low-level primitive. It needs detailed information about the files you\u2019re pre-caching, which are buried in your build tool. This is why we use the VitePWA plugin. It uses Workbox under the hood, and configures it with all the info it needs about the bundles that Vite creates. Unsurprisingly, there are also webpack<\/a> and Rollup<\/a> plugins if you happen to prefer working with those bundlers.<\/p>\n\n\n I\u2019ll assume you already have a Vite-based site. If not, feel free to create one<\/a> from any of the available templates<\/a>.<\/p>\n\n\n\n First, we install the VitePWA plugin:<\/p>\n\n\n\n We\u2019ll import the plugin in our Vite config:<\/p>\n\n\n\n Then we put it to use in the config as well:<\/p>\n\n\n\n We\u2019ll add more options in a bit, but that\u2019s all we need to create a surprisingly useful service worker. Now let\u2019s register it somewhere in the entry of our application with this code:<\/p>\n\n\n\n Don\u2019t let the code that\u2019s commented out throw you for a loop. It’s extremely important, in fact, as it prevents the service worker from running in development. We only want to install the service worker anywhere that\u2019s not on the localhost where we\u2019re developing, that is, unless we\u2019re developing the service worker itself, in which case we can comment out that check (and revert before pushing code to the main branch).<\/p>\n\n\n\n Let\u2019s go ahead and open a fresh browser, launch DevTools, navigate to the Network tab, and run the web app. Everything should load as you\u2019d normally expect. The difference is that you should see a whole slew of network requests in DevTools.<\/p>\n\n\n\nTable of Contents<\/h2>
\n
Service workers, introduced<\/h3>\n\n\n
Versioning and manifests<\/h3>\n\n\n
foo.js<\/code> file, and you modify that file, you want the service worker to pull down the updated version, the next time a user visits the site.<\/p>\n\n\n\n
foo.js<\/code> file. Usually, a build system will create something like
foo-ABC123.js<\/code>, where \u201cABC123\u201d is a hash of the file. If you update
foo.js<\/code>, the next deployment of your site may send over
foo-XYZ987.js<\/code>. How does the service worker handle this?<\/p>\n\n\n\n
Our first service worker<\/h3>\n\n\n
npm i vite-plugin-pwa<\/code><\/pre>\n\n\n\n
import { VitePWA } from \"vite-plugin-pwa\"<\/code><\/pre>\n\n\n\n
plugins: [\n VitePWA()<\/code><\/pre>\n\n\n\n
import { registerSW } from \"virtual:pwa-register\";\n\nif (\"serviceWorker\" in navigator) {\n \/\/ && !\/localhost\/.test(window.location)) {\n registerSW();\n}<\/code><\/pre>\n\n\n\n