sueta / client / vite.config.ts
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import { readFileSync } from "node:fs";
import { defineConfig, type Plugin } from "vite";
import { VitePWA } from "vite-plugin-pwa";

const VERSION: number = JSON.parse(readFileSync(new URL("./version.json", import.meta.url), "utf8")).version;

// dist/version.json lets a running app ask "what version is live right now?"
// (it is deliberately NOT precached — see globPatterns — so the fetch hits the network)
const emitVersion: Plugin = {
  name: "emit-version",
  generateBundle() {
    this.emitFile({ type: "asset", fileName: "version.json", source: JSON.stringify({ version: VERSION }) });
  },
};

// base './' is load-bearing: the app is served both at https://chat.ardegazu.ro/
// and from IPFS gateway paths like /ipfs/<cid>/ — all asset URLs must be relative.
export default defineConfig({
  base: "./",
  build: { target: "es2022" },
  define: { __APP_VERSION__: JSON.stringify(VERSION) },
  server: {
    proxy: {
      // local dev: `go run ./server --dev` listens on :8080
      "/ws": { target: "ws://localhost:8080", ws: true },
      "/turn-credentials": { target: "http://localhost:8080" },
    },
  },
  plugins: [
    emitVersion,
    VitePWA({
      registerType: "prompt",
      includeAssets: ["icons/apple-touch-icon.png"],
      manifest: {
        name: "sueta",
        short_name: "sueta",
        description: "p2p end-to-end encrypted chat",
        start_url: "./",
        scope: "./",
        display: "standalone",
        background_color: "#0d1117",
        theme_color: "#0d1117",
        icons: [
          { src: "icons/icon-192.png", sizes: "192x192", type: "image/png" },
          { src: "icons/icon-512.png", sizes: "512x512", type: "image/png" },
          { src: "icons/icon-512-maskable.png", sizes: "512x512", type: "image/png", purpose: "maskable" },
        ],
      },
      workbox: {
        globPatterns: ["**/*.{js,css,html,png,svg,webmanifest}"],
        navigateFallback: "index.html",
        // prompt-mode update flow: the new SW must claim open pages, else
        // controllerchange never fires on first-visit pages and the one-tap
        // update banner can't reload into the new version
        clientsClaim: true,
        skipWaiting: false,
      },
    }),
  ],
});