From 6be4af58b4859c201054771eaaa1f3fb1ce7d6c0 Mon Sep 17 00:00:00 2001 From: Aaron Gutierrez Date: Fri, 17 Apr 2026 22:35:23 -0700 Subject: [PATCH] Proxy to cloudfront for local development without all the images --- vite.config.ts | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/vite.config.ts b/vite.config.ts index 6784bc1..dd15591 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,9 +1,60 @@ import { defineConfig } from "vite-plus"; import react from "@vitejs/plugin-react"; +import { stat } from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; const rootDir = path.dirname(fileURLToPath(import.meta.url)); +const imageRootDir = path.resolve(rootDir, "img"); +const imageFallbackBase = "https://ski.aarongutierrez.com"; + +const fileExists = async (filename: string): Promise => { + try { + await stat(filename); + return true; + } catch { + return false; + } +}; + +const imageFallbackMiddleware = async ( + req: { method?: string; url?: string }, + res: { statusCode: number; setHeader: (name: string, value: string) => void; end: () => void }, + next: () => void, +): Promise => { + if ((req.method !== "GET" && req.method !== "HEAD") || !req.url) { + next(); + return; + } + + const requestUrl = new URL(req.url, "http://localhost"); + const pathname = decodeURIComponent(requestUrl.pathname); + if (!pathname.startsWith("/img/")) { + next(); + return; + } + + const relativePath = pathname.slice(1); + const localFile = path.resolve(rootDir, relativePath); + const relativeToImageRoot = path.relative(imageRootDir, localFile); + const isWithinImageRoot = + relativeToImageRoot !== "" && + relativeToImageRoot !== ".." && + !relativeToImageRoot.startsWith(`..${path.sep}`) && + !path.isAbsolute(relativeToImageRoot); + + if (!isWithinImageRoot || (await fileExists(localFile))) { + next(); + return; + } + + const fallbackUrl = new URL(pathname, imageFallbackBase); + fallbackUrl.search = requestUrl.search; + + res.statusCode = 302; + res.setHeader("Location", fallbackUrl.toString()); + res.end(); +}; export default defineConfig({ staged: { @@ -28,6 +79,15 @@ export default defineConfig({ } }, }, + { + name: "image-fallback-to-production", + configureServer(server) { + server.middlewares.use(imageFallbackMiddleware); + }, + configurePreviewServer(server) { + server.middlewares.use(imageFallbackMiddleware); + }, + }, ], resolve: { alias: {