Files
ps5upload/client/vite.config.ts
T
phantomptrandClaude Opus 5.5 11827039d3 Android: rounded split buttons, Home tiles that fit a phone, a Payloads search box
- The build rewrote start/end corners and positions with :lang(ar,fa,…) language
  lists, which Chromium before 141 (Android's WebView) drops: split buttons were
  square and start/end-placed controls sat wrong. Each list is now split into
  one language per check (postcss/langLists.mjs, run on the built CSS).
- Home's action tiles stack the icon above the label on a phone; the labels broke
  mid-word.
- Payloads' search box takes its own row on a phone instead of shrinking to nothing.
- After Resend helper, pairing keeps checking for a minute, not 16 s.
- Reverts the Android blur change: the doubled title was the emulator's software
  rendering, gone with its GPU on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 17:05:48 -07:00

123 lines
5.1 KiB
TypeScript

import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { defineConfig, type Plugin } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
// @ts-expect-error plain .mjs helper shared with its vitest test, no type declarations
import { splitLangLists } from "./postcss/langLists.mjs";
/**
* The FAQ and What's New screens show the repo-root FAQ.md and CHANGELOG.md (lib/bundledDoc.ts).
* Imported as `../../../FAQ.md?raw`, the dev server served them as raw markdown instead of
* modules (they sit outside the client folder), so both screens failed there. As virtual modules
* they go through the normal pipeline in dev and in builds alike.
*/
function bundledDocs(): Plugin {
const files: Record<string, string> = {
"virtual:doc/faq": "../FAQ.md",
"virtual:doc/changelog": "../CHANGELOG.md",
};
return {
name: "ps5upload-bundled-docs",
resolveId(id) {
return id in files ? `\0${id}` : undefined;
},
load(id) {
if (!id.startsWith("\0virtual:doc/")) return undefined;
const file = fileURLToPath(new URL(files[id.slice(1)], import.meta.url));
this.addWatchFile(file);
return `export default ${JSON.stringify(readFileSync(file, "utf8"))};`;
},
};
}
// @ts-expect-error process is a nodejs global
const host = process.env.TAURI_DEV_HOST;
// The React runtime packages that go in their own long-lived vendor chunk.
const REACT_PACKAGES =
/[\\/]node_modules[\\/](react|react-dom|react-router|scheduler)[\\/]/;
// Dev server port (live reload uses the next one up). Desktop dev uses 1420;
// `make run-android` picks its own so both can run at once.
// @ts-expect-error process is a nodejs global
const port = Number(process.env.PS5UPLOAD_VITE_PORT) || 1420;
/** One language per `:lang()` in the built CSS (postcss/langLists.mjs says why). */
function oneLangPerSelector(): Plugin {
return {
name: "ps5upload-one-lang-per-selector",
apply: "build",
generateBundle(_, bundle) {
for (const file of Object.values(bundle)) {
if (file.type === "asset" && file.fileName.endsWith(".css") && typeof file.source === "string") {
file.source = splitLangLists(file.source);
}
}
},
};
}
export default defineConfig({
plugins: [react(), tailwindcss(), bundledDocs(), oneLangPerSelector()],
clearScreen: false,
base: process.env.VITE_BASE_URL || "./",
server: {
port,
strictPort: true,
// An explicit IPv4 address, not "localhost": Vite 8 binds the first address localhost
// resolves to, which on macOS is ::1 alone. The desktop WebView then could not load
// devUrl and `make run-client` opened a blank dark window (Chromium fell back to ::1,
// so the page looked fine in a browser). devUrl and playwright.config use 127.0.0.1 too.
host: host || "127.0.0.1",
hmr: host
? {
protocol: "ws",
host,
port: port + 1,
}
: undefined,
},
build: {
outDir: "dist",
emptyOutDir: true,
// Pin a conservative JS/CSS target. Tauri renders in a fixed WebView
// per platform, and the Android System WebView in particular can be
// an old Chromium. Without this, Vite ships its modern default
// (ES2020+ optional-chaining / nullish / logical-assignment that the
// v8/rolldown upgrade left un-lowered) and an older Android WebView
// renders the first screen, then crashes on `??=` / `?.` → the app
// "opens then terminates". safari13 (~ES2019) down-levels all of it
// and is safe for every WebView we ship to (Android Chromium,
// WebView2, WKWebView, WebKitGTK). Mirrors Tauri's recommended config.
target:
process.env.TAURI_ENV_PLATFORM === "windows" ? "chrome105" : "safari13",
chunkSizeWarningLimit: 900,
rollupOptions: {
// Silence rolldown's informational "[PLUGIN_TIMINGS] … significant time
// in @tailwindcss/vite:generate:build" note. Tailwind v4 scans the whole
// source tree to generate utilities, so its codegen is legitimately the
// slowest plugin — that's expected, not a problem to fix, and the note is
// just build noise. (rolldown input option, passed through by
// rolldown-vite; not in Vite's RollupOptions types yet.)
// @ts-expect-error checks is a rolldown passthrough not typed by Vite
checks: { pluginTimings: false },
output: {
manualChunks(id) {
if (!id.includes("node_modules")) return;
// Exact package names: a bare "react" substring also caught
// lucide-react and anything else with react in its path.
if (REACT_PACKAGES.test(id)) return "vendor-react";
return "vendor";
},
},
},
},
test: {
// Fail any test that reaches the network. See src/test-setup.ts for
// why: unmocked API wrappers silently hit a running dev engine.
setupFiles: ["./src/test-setup.ts"],
// Playwright owns real-browser journeys; Vitest must not import those
// files into its jsdom/node runner.
exclude: ["e2e/**", "**/node_modules/**", "**/.git/**"],
},
});