type: runbook
status: active
timestamp: 2026-06-21
tags: [runbook, distribute, pwa, pwabuilder, tauri, aab, msix]

Build PWA + Android AAB/APK + Windows MSIX + desktop EXE from one app

Build PWA + Android + MSIX + desktop from one app

Build PWA + Android AAB/APK + Windows MSIX + desktop EXE from one app

When to use

You have an app under repos/oriz/own/prod/apps/**/<brand>-app/ and you want it distributed as a PWA + Android app (Play Store or sideload APK) + Windows app (Microsoft Store or sideload MSIX) + optional desktop EXE/dmg/AppImage from the same source. iOS is PWA-only; no App Store path. See decisions/architecture/pwabuilder-as-primary-converter.md for the rationale.

Prerequisites

The single command

cd repos/oriz/own/prod/apps/<category>/<brand>-app
pnpm build                            # Astro → dist/ (this IS the PWA)
pnpm astro-distribute build           # PWABuilder fetches <brand>.oriz.in, emits packages

Default emits PWABuilder packages only:

dist/                          ← PWA, deployed by CF Pages workflow
dist-native/<brand>.aab        ← Android App Bundle (Play Store)
dist-native/<brand>.apk        ← Android sideload APK
dist-native/<brand>.msix       ← Windows MSIX (Microsoft Store + sideload)
dist-native/<brand>-ios/       ← iOS XCode project (slug-reserved, NOT published)

Opt-in Tauri route (smaller binaries + auto-update, costs Rust toolchain at build):

pnpm astro-distribute build --tauri   # adds Tauri outputs
# → dist-native/<brand>-setup.exe (NSIS), .dmg, .AppImage

What each path does

PWA (already there)

@chirag127/astro-pwa registers @vite-pwa/astro with the manifest fed from astro-chrome’s brand config. pnpm build IS the PWA build. Cloudflare Pages deploys dist/ per cloudflare-pages-only.md.

PWABuilder route (primary)

astro-distribute invokes the PWABuilder CLI:

pwabuilder package --url https://<brand>.oriz.in --platform android --output dist-native/
pwabuilder package --url https://<brand>.oriz.in --platform windows --output dist-native/
pwabuilder package --url https://<brand>.oriz.in --platform ios     --output dist-native/   # slug-reserved

PWABuilder reads the deployed PWA manifest, generates a Trusted Web Activity for Android (via Bubblewrap), an MSIX for Windows, an XCode project for iOS. Digital Asset Links (/.well-known/assetlinks.json) are emitted into dist/ automatically.

Tauri route (optional)

When --tauri is passed, astro-distribute ALSO wraps dist/ in a Tauri v2 shell:

Tauri offers auto-update via its built-in updater pointing at https://updates.oriz.in/<brand>/. Use this route for apps that ship weekly or where the MSIX install size matters.

What is NOT emitted

Wiring it into CI

Per-app .github/workflows/build-distributables.yml:

name: Build distributables
on:
  push:
    tags: ['v*']
jobs:
  pwa:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22, cache: pnpm }
      - run: pnpm install
      - run: pnpm build
      - run: pnpm wrangler pages deploy dist --project-name "<brand>-app"
  native:
    needs: pwa
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - run: pnpm install
      - run: pnpm astro-distribute build              # PWABuilder fetches <brand>.oriz.in
      - uses: softprops/action-gh-release@v2
        with:
          files: dist-native/*

Publish to Play Console / Microsoft Partner Center is manual — download the AAB / MSIX from the GitHub Release and upload via each store’s web UI. Both stores’ APIs are gated behind credentials that don’t fit the unattended-CI model on free tiers.

Verify

After pnpm astro-distribute build:

Time budget


Edit on GitHub · Back to index