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
This commit is contained in:
2025-12-29 14:27:52 -06:00
parent 3bb3908853
commit 8d3d69da9d
6 changed files with 84 additions and 6 deletions
+2
View File
@@ -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"
+8
View File
@@ -6,6 +6,14 @@
/pacman/assets
/assets
# Web/Node artifacts
node_modules
/web/node_modules
/web/dist
.next
.nuxt
.cache
# Development files
/.git
/*.md
+4 -2
View File
@@ -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<string, string> | 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<string, string> | 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)
+10 -2
View File
@@ -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
+11
View File
@@ -0,0 +1,11 @@
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_PACMAN_VERSION: string;
readonly VITE_API_URL: string;
readonly VITE_API_TARGET: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
+49 -2
View File
@@ -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, "."),