Extra guides

PWA, Workers And Notifications

Make an app installable, register browser workers, and prepare push notification subscriptions.

By Guillermo Alvarez - Published Updated

Progressive web app behavior is optional. Enable it when the app should be installable, cache selected content offline, or prepare for browser push notifications.

Enable installability

Configure PWA support during application startup:

return lazyapp.New(lazyapp.Config{
    Name:   "example.com",
    Drawer: Draw,
    Public: app.Public,
    Views:  app.Views,
    PWA: lazypwa.Config{
        Installable: true,
        Manifest: lazypwa.ManifestConfig{
            Name:       "Example",
            ShortName:  "Example",
            StartURL:   "/",
            Scope:      "/",
            Display:    "standalone",
            ThemeColor: "#FDDD00",
        },
    },
})

Add the PWA helper in the layout head:

<head>
  {{seo}}
  {{pwa}}
</head>

GoLazy serves /manifest.webmanifest, a generated service worker, and a small client script. The client dispatches browser events such as lazypwa:installready, lazypwa:ready, lazypwa:updateavailable, lazypwa:offline, and lazypwa:online. The application decides whether to show install or update UI.

Cache content offline

Offline caching is disabled unless you opt in:

PWA: lazypwa.Config{
    Installable: true,
    Offline: lazypwa.OfflineConfig{
        Enabled:       true,
        FallbackURL:   "/",
        URLs:          []string{"/", "/guides/latest/"},
        IncludeAssets: true,
    },
}

The service worker reads /pwa-cache-manifest.json and refreshes the cache when the app version changes. By default the version comes from Go build information; set PWA.Version when a deployment needs a different value.

Do not cache dynamic authenticated pages unless the application explicitly lists them and owns the consequences. The default mode is installability only, which is enough for apps that should be installable but do not make sense offline.

Register workers directly

Workers are not only a PWA feature. Register app-owned worker scripts through lazyapp.Config.Workers:

Workers: func(ctx context.Context, workers *lazyworkers.Registry) error {
    return workers.AddAsset(
        "search",
        lazyworkers.WebWorker,
        "/assets/search-worker.js",
        lazyworkers.WithScriptType(lazyworkers.ModuleScript),
        lazyworkers.WithDescription("Search index worker"),
    )
},

Generated service workers, route-backed workers, and asset-backed workers share one registry. Templates can resolve registered paths:

<script type="module">
  const worker = new Worker({{printf "%q" (worker_path "search")}}, {type: "module"})
</script>

The development panel's PWA tab lists workers registered through this registry, including the PWA service worker.

Prepare push notifications

lazypwa.PushConfig exposes browser subscription plumbing and Go interfaces for application-owned storage and delivery. Real apps should store subscriptions in their own user/session database and choose a sender implementation that matches their deployment.

The first framework slice does not force a database, authentication model, or concrete Web Push sender. Keep the boundary at application services: request handlers ask a service to subscribe, unsubscribe, or send a notification, and that service decides how to associate subscriptions with users.