Progressive web apps
Built into lunx: a web app manifest and a service worker that precaches your build, so the app installs and works offline. No plugin, no Workbox.
Setup
typescriptlunx.config.ts
import { defineConfig } from 'lunx-dev' export default defineConfig({ pwa: { manifest: { name: 'My Lunx App', short_name: 'LunxApp', theme_color: '#2563eb', background_color: '#ffffff', icons: [ { src: '/icons/pwa-192x192.png', sizes: '192x192', type: 'image/png' }, { src: '/icons/pwa-512x512.png', sizes: '512x512', type: 'image/png' }, { src: '/icons/pwa-512x512.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' }, ], }, }, })
manifest is written as-is (keys as in the Web App Manifest spec), with start_url, scope and display: 'standalone' filled in when you leave them out. Put the icons in public/.
What lunx build writes
text
dist/ ├── manifest.webmanifest # from pwa.manifest ├── registerSW.js # registers sw.js once the page has loaded ├── sw.js # precaches the build └── index.html # + <link rel="manifest"> and <script src="/registerSW.js" defer>
- Precache: every file of the finished build (pages with their SRI, assets,
public/), except source maps,.gz/.brcopies and lunx's reports. - Cache-first: precached files load from the cache; anything else goes to the network.
- Offline navigation: a page that isn't cached (a client-side route) gets
index.html, so single-page apps keep working. - Updates: each build has its own cache. A deploy installs the new service worker, which takes over and deletes the old cache.
registerSW.jsis an external script, so lunx's Content-Security-Policy (script-src 'self') allows it.
lunx dev registers no service worker: it would serve your edits from a stale cache.
Options
| Field | Type | Default | Description |
|---|---|---|---|
| manifest | object | false | — | The web app manifest, or false to write none. |
| register | boolean | true | Add registerSW.js to every page. false to register the service worker yourself. |
| navigateFallback | string | null | 'index.html' | The page offline navigations fall back to; null for none (multi-page sites). |
| exclude | (string | RegExp)[] | — | Build files to leave out of the precache. Strings may use * wildcards. |
pwa: true turns it on with the defaults.
Checking it
bash
lunx build && lunx preview # DevTools → Application → Service Workers: sw.js is "activated" # DevTools → Network → Offline, then reload: the app still loads
Already using vite-plugin-pwa?
It keeps working with lunx, and while it is in your plugins lunx writes no service worker of its own.
Maskable icons
Provide a
maskable icon variant. Android crops icons to various shapes; without a maskable variant, the standard icon is padded with white space.