PWA Starter Kit

Build a PWA with React and Vite

Published · by

Lire en français

In short. To build a PWA with React and Vite, add vite-plugin-pwa, which generates the manifest and the service worker. Provide 192 and 512 pixel icons, including a maskable one, pick an update strategy, set the base path, then test on a production build, because the service worker is disabled in development.

A progressive web app (PWA) can be installed on the home screen, opens in its own window and can start without a network. With React and Vite, the foundation is quick to lay. What turns it into a PWA comes down to three building blocks, and a few decisions best made early.

The three building blocks of a PWA

Step by step

  1. Create the project. npm create vite@latest my-app -- --template react-ts sets up a React app in TypeScript.
  2. Add the PWA plugin. npm install -D vite-plugin-pwa, then declare VitePWA() in vite.config.ts. The plugin generates the manifest and a Workbox-based service worker, which caches the files produced by the build.
  3. Fill in the manifest: name, short_name, start_url, display, theme_color, background_color, lang, and icons of 192 and 512 pixels.
  4. Add a "maskable" icon. Android crops icons into a circle or a rounded square. An icon declared maskable keeps its design inside a safe zone: a centered circle whose diameter is 80% of the icon. On a 512-pixel icon, the design must fit in a circle of about 410 pixels.
  5. Pick an update strategy. With registerType: 'autoUpdate', the page reloads as soon as a new version is ready. With 'prompt', a message offers the update and the user chooses when. If your app contains forms, prefer 'prompt': a reload in the middle of typing loses data.
  6. Set the base path and routing. On GitHub Pages, the app often lives under a subpath: set base (for example /my-app/). And static hosting does not know your routes: reloading /my-app/settings returns a 404 error. Two workarounds: route with # (HashRouter), or publish a 404.html that reloads the app.
  7. Test on a build. By default, the plugin does not enable the service worker during development. Run npm run build then npm run preview, and open the Application tab of the browser's developer tools: manifest, service worker and cache are all visible there.

What takes time afterwards

A PWA that holds up in production needs more than these three blocks: a light and dark theme, several languages, data that survives an update, sync with a server that copes with network drops, tests, a size budget. Every project rewrites that framework. That is what a starter kit saves you.

How PWA Starter Kit helps

PWA Starter Kit is the skeleton of the mister-guiiug family of apps: a complete, tested and deployed app that has no business logic, only the framework.

Starting from the skeleton

The repository recommends not cloning it, but using its generator: npx github:mister-guiiug/create-lg-pwa-app my-app --from main. Without --from main, the generator starts from the skeleton's latest published tag, which may lag behind what is described here: at the time of this update, that tag lacks undoable deletion and the offline queue. The generator applies your id and display name, installs dependencies, builds the app and makes the first commit. With --publish, it also creates the public repository and turns on GitHub Pages.

Two caveats. The shared library is published on GitHub Packages, which requires a token even for a public package: export NODE_AUTH_TOKEN (a GitHub token with the read:packages scope) before npm install. And the skeleton is designed first for the apps of the family. Its code is under the MIT license: read it, take what helps you. The French original of this guide is Créer une PWA avec React et Vite.

Frequently asked questions

Does a React PWA work offline automatically?

Not entirely. The service worker caches the app's files, so the app can open without a network. Data coming from a server needs its own strategy: local storage, a queue of pending writes. The skeleton shows both.

HashRouter or path-based routing on GitHub Pages?

Both work. Routing with # avoids any 404 but gives less readable addresses. Path-based routing needs a fallback 404.html. The skeleton chose paths, and documents why.

Why prompt rather than autoUpdate?

Because an automatic reload can land in the middle of typing. With prompt, the new version offers itself and the user chooses when. The trade-off: someone can ignore the message and stay on an old version for a long time.

Can you use the skeleton without Supabase?

Yes. It starts with no configuration at all, in local mode, and says so in its settings. Supabase is just an adapter that switches on when its two variables are present.

References