Use when adding, referencing, or serving static assets (images, fonts, videos, 3D models) through the R2 CDN pipeline with type-safe imports
Static assets are content-hashed, synced to Cloudflare R2, and served via CDN. All asset references MUST be type-safe through the generated manifest.
1. Add file → assets/{folder}/{file}
2. Generate → pnpm fe:assets:gen
3. Use in code → Assets_getAssetUrl("folder/file.png")
4. Sync to R2 → pnpm fe:assets:push
Every step is mandatory. Skipping step 2 causes TypeScript errors. Skipping step 4 means assets won't load in deployed environments.
spark/frontend/my-vite-app/
├── assets/ # Source assets (committed to git)
│ ├── logo.svg
│ └── Page_Login/
│ ├── carousel-bg.png
│ └── slide-1.png
├── scripts/
│ ├── generate-asset-manifest.js # Step 2: generates types
│ └── sync-assets-to-r2.js # Step 4: uploads to R2
└── src/types/
└── assets.types.ts # Auto-generated (DO NOT edit manually)
<!-- Last created: 2026-02-08 -->Folder convention: Organize by page or feature, matching the Page_ naming convention (e.g., assets/Page_Login/, assets/Page_Dashboard/). Shared assets go in the root assets/ folder.
import { Assets_getAssetUrl, type Assets_AssetPath } from "@/types/assets.types";
// ✅ Type-safe — autocomplete + compile-time validation
const url = Assets_getAssetUrl("Page_Login/slide-1.png");
// ✅ Type-safe in data structures
const slides: { image: Assets_AssetPath }[] = [
{ image: "Page_Login/slide-1.png" },
];
// ✅ Background images
<div style={{ backgroundImage: `url(${Assets_getAssetUrl("Page_Login/carousel-bg.png")})` }} />
// ✅ Image elements
<img src={Assets_getAssetUrl("logo.svg")} alt="Spark" />
assets.types.ts)| Export | Purpose |
|---|---|
Assets_AssetPath | Union type of all valid asset paths |
Assets_MANIFEST | Map: original path → hashed R2 key |
Assets_METADATA | Map: path → { hash, size, mimeType } |
Assets_getAssetUrl(path) | Full URL (dev: /assets/..., prod: CDN) |
Assets_getHashedPath(path) | Hashed R2 key only |
Assets_getMetadata(path) | Metadata for an asset |
| Environment | URL pattern |
|---|---|
| Development | /assets/{original-path} (Vite dev server) |
| Production | {VITE_CDN_BASE_URL}/{env}/assets/{hashed-filename} |
Content hashing (logo.0206c431.svg) provides automatic cache busting — 1-year immutable cache headers on R2.
pnpm fe:assets:gen # Regenerate assets.types.ts from assets/ folder
pnpm fe:assets:push # Sync to R2 (interactive env prompt, or --env production)
"/assets/logo.svg" → ✅ Assets_getAssetUrl("logo.svg")assets.types.ts manually → ✅ Run pnpm fe:assets:gen<img src={require(...)}> or Vite import for assets → ✅ Use Assets_getAssetUrl()assets/ folder → ✅ All static assets go through the pipelineImages (PNG, JPG, GIF, WebP, SVG, AVIF), Fonts (WOFF, TTF, OTF), Videos (MP4, WebM, MOV, AVI), Audio (MP3, WAV, OGG, FLAC, M4A), 3D Models (GLB, GLTF, FBX, OBJ, USDZ), Documents (PDF, TXT, CSV, JSON, XML).
VITE_CDN_BASE_URL configuration