diff --git a/packages/studio/vite.config.ts b/packages/studio/vite.config.ts
index af603816f3..724eb5ab1b 100644
--- a/packages/studio/vite.config.ts
+++ b/packages/studio/vite.config.ts
@@ -162,9 +162,16 @@ function devProjectApi(): Plugin {
if (req.method === "GET" && rest === "/preview") {
try {
const bundler = await getBundler();
- const bundled = bundler
+ let bundled = bundler
? await bundler(projectDir)
: readFileSync(join(projectDir, "index.html"), "utf-8");
+ // Inject so relative asset paths resolve through /preview/ route
+ const baseTag = ``;
+ if (bundled.includes("
")) {
+ bundled = bundled.replace("", `${baseTag}`);
+ } else {
+ bundled = baseTag + bundled;
+ }
res.writeHead(200, {
"Content-Type": "text/html; charset=utf-8",
"Cache-Control": "no-store",
@@ -274,13 +281,29 @@ ${content}
return;
}
const isText = /\.(html|css|js|json|svg|txt)$/i.test(subPath);
- const contentType = subPath.endsWith(".html")
- ? "text/html"
- : subPath.endsWith(".js")
- ? "text/javascript"
- : subPath.endsWith(".css")
- ? "text/css"
- : "application/octet-stream";
+ const mimeTypes: Record = {
+ ".html": "text/html",
+ ".js": "text/javascript",
+ ".css": "text/css",
+ ".json": "application/json",
+ ".svg": "image/svg+xml",
+ ".png": "image/png",
+ ".jpg": "image/jpeg",
+ ".jpeg": "image/jpeg",
+ ".webp": "image/webp",
+ ".gif": "image/gif",
+ ".mp4": "video/mp4",
+ ".webm": "video/webm",
+ ".mp3": "audio/mpeg",
+ ".wav": "audio/wav",
+ ".m4a": "audio/mp4",
+ ".ogg": "audio/ogg",
+ ".woff2": "font/woff2",
+ ".woff": "font/woff",
+ ".ttf": "font/ttf",
+ };
+ const ext = "." + subPath.split(".").pop()?.toLowerCase();
+ const contentType = mimeTypes[ext] ?? "application/octet-stream";
res.writeHead(200, { "Content-Type": contentType });
res.end(readFileSync(file, isText ? "utf-8" : undefined));
return;