From 8d3d69da9d0aabbb644b11eba05eeae8dc292513 Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 29 Dec 2025 14:27:52 -0600 Subject: [PATCH] feat(web): add cache busting with version-based asset loading - Inject git hash via Vite plugin for cache-busting WASM/JS assets - Enable Emscripten assertions for better runtime error messages - Log Emscripten runtime init for debugging filesystem readiness - Expand dockerignore to exclude web build artifacts --- .cargo/config.toml | 2 ++ .dockerignore | 8 ++++++ pacman/web.build.ts | 6 +++-- web/pages/index/+Page.tsx | 12 +++++++-- web/vite-env.d.ts | 11 +++++++++ web/vite.config.ts | 51 +++++++++++++++++++++++++++++++++++++-- 6 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 web/vite-env.d.ts diff --git a/.cargo/config.toml b/.cargo/config.toml index 0e17494..ac97986 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -7,6 +7,8 @@ rustflags = [ "link-args=-sUSE_SDL=2 -sUSE_SDL_IMAGE=2 -sUSE_SDL_MIXER=2 -sUSE_OGG=1 -sUSE_SDL_GFX=2 -sUSE_SDL_TTF=2 -sSDL2_IMAGE_FORMATS=['png']", "-C", "link-args=--preload-file pacman/assets/game/", + "-C", + "link-args=-sASSERTIONS=1", ] runner = "node" diff --git a/.dockerignore b/.dockerignore index 43de79c..db7776b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,6 +6,14 @@ /pacman/assets /assets +# Web/Node artifacts +node_modules +/web/node_modules +/web/dist +.next +.nuxt +.cache + # Development files /.git /*.md diff --git a/pacman/web.build.ts b/pacman/web.build.ts index 7501a8c..3f18e26 100644 --- a/pacman/web.build.ts +++ b/pacman/web.build.ts @@ -40,7 +40,7 @@ const os: Os = match(platform()) }); /** - * Build the application with Emscripten, generate the CSS, and copy the files into 'dist'. + * Build the application with Emscripten and copy the files into 'dist'. * * @param release - Whether to build in release mode. * @param env - The environment variables to inject into build commands. @@ -88,7 +88,7 @@ async function build(release: boolean, env: Record | null) { ); // Copy the files to the dist folder - logger.debug("Copying Emscripten build artifacts into web/dist"); + logger.debug("Copying Emscripten build artifacts into web/public"); await Promise.all( files.map(async ({ optional, src, dest }) => { match({ optional, exists: await fs.exists(src) }) @@ -109,6 +109,8 @@ async function build(release: boolean, env: Record | null) { .otherwise(async () => await fs.copyFile(src, dest)); }) ); + + logger.info("Emscripten build complete"); } // (Tailwind-related code removed; this script is now focused solely on the Emscripten build) diff --git a/web/pages/index/+Page.tsx b/web/pages/index/+Page.tsx index fe0941a..b5eb0ea 100644 --- a/web/pages/index/+Page.tsx +++ b/web/pages/index/+Page.tsx @@ -63,12 +63,20 @@ export default function Page() { return; } + // Get version from build-time injected environment variable + const version = import.meta.env.VITE_PACMAN_VERSION; + console.log(`Loading Pacman with version: ${version}`); + win.Module = { canvas, locateFile: (path: string) => { - return path.startsWith("/") ? path : `/${path}`; + const normalizedPath = path.startsWith("/") ? path : `/${path}`; + return `${normalizedPath}?v=${version}`; }, preRun: [], + onRuntimeInitialized: () => { + console.log("Emscripten runtime initialized, filesystem ready"); + }, // Emscripten calls this on fatal errors (abort/trap/etc) onAbort: (what: unknown) => { const message = typeof what === "string" ? what : "WebAssembly execution aborted"; @@ -78,7 +86,7 @@ export default function Page() { }; const script = document.createElement("script"); - script.src = "/pacman.js"; + script.src = `/pacman.js?v=${version}`; script.async = false; // Handle script load errors diff --git a/web/vite-env.d.ts b/web/vite-env.d.ts new file mode 100644 index 0000000..a25e317 --- /dev/null +++ b/web/vite-env.d.ts @@ -0,0 +1,11 @@ +/// + +interface ImportMetaEnv { + readonly VITE_PACMAN_VERSION: string; + readonly VITE_API_URL: string; + readonly VITE_API_TARGET: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/web/vite.config.ts b/web/vite.config.ts index 8c231e2..cc9b705 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -1,11 +1,58 @@ import tailwindcss from "@tailwindcss/vite"; import react from "@vitejs/plugin-react"; import vike from "vike/plugin"; -import { defineConfig } from "vite"; +import { defineConfig, Plugin } from "vite"; import path from "path"; +import { execSync } from "child_process"; + +/** + * Vite plugin that injects the Pacman version hash at build time. + * Uses git commit hash in production/dev, falls back to timestamp if git unavailable. + */ +function pacmanVersionPlugin(): Plugin { + let version: string; + + function getVersion(mode: string): string { + // Development mode uses fixed "dev" string + if (mode === "development") { + return "dev"; + } + + // Try to get git commit hash + try { + const hash = execSync("git rev-parse --short HEAD", { + encoding: "utf8", + stdio: ["pipe", "pipe", "pipe"], + }).trim(); + + if (hash) { + return hash; + } + } catch { + // Git not available or command failed + } + + // Fallback to timestamp + return Date.now().toString(36); + } + + return { + name: "pacman-version", + config(_, { mode }) { + version = getVersion(mode); + console.log(`[pacman-version] Using version: ${version}`); + + return { + define: { + "import.meta.env.VITE_PACMAN_VERSION": JSON.stringify(version), + }, + }; + }, + }; +} export default defineConfig({ - plugins: [vike(), react(), tailwindcss()], + plugins: [pacmanVersionPlugin(), vike(), react(), tailwindcss()], resolve: { alias: { "@": path.resolve(__dirname, "."),