Skip to content

Commit d5d0df5

Browse files
committed
Fix vercel build
1 parent 370ac2e commit d5d0df5

File tree

5 files changed

+91
-15
lines changed

5 files changed

+91
-15
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,5 @@ next-env.d.ts
4242

4343
dist/
4444
release/
45-
public/
45+
public/
46+
.env*.local

scripts/build-browser.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ async function build() {
2222
return false;
2323
}
2424

25+
// Make paths absolute to root in index.html
26+
const indexPath = "./dist/browser/index.html";
27+
const indexHtml = await Bun.file(indexPath).text();
28+
await Bun.write(indexPath, indexHtml.replaceAll("./", "/"));
29+
2530
// Build worker separately with document shim for Prism/refractor
2631
const workerResult = await Bun.build({
2732
entrypoints: ["./src/browser/lib/diff-worker.ts"],

scripts/build-vercel.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
11
import { $ } from "bun";
2-
import { cp, mkdir } from "fs/promises";
2+
import { cp, mkdir, readdir } from "fs/promises";
33
import { resolve } from "path";
44

55
const rootDir = resolve(import.meta.dir, "..");
66
const publicDir = resolve(rootDir, "public");
7+
const browserDistDir = resolve(rootDir, "dist/browser");
78

89
// Clean and create public directory
910
await $`rm -rf ${publicDir}`;
1011
await mkdir(publicDir, { recursive: true });
1112

1213
// Build browser files
1314
console.log("Building browser...");
14-
await import("./build-browser.ts");
15+
await import("./build-browser");
1516

16-
// Copy browser build to public
17-
await cp(resolve(rootDir, "dist/browser"), publicDir, { recursive: true });
17+
// Copy browser build contents to public (served by Vercel CDN)
18+
const browserFiles = await readdir(browserDistDir);
19+
for (const file of browserFiles) {
20+
await cp(resolve(browserDistDir, file), resolve(publicDir, file), { recursive: true });
21+
}
1822
console.log("Copied browser files to public/");
1923

20-
// Copy src directory for Vercel's Hono detection
21-
await mkdir(resolve(publicDir, "src"), { recursive: true });
22-
await cp(resolve(rootDir, "src/index.ts"), resolve(publicDir, "src/index.ts"));
23-
await cp(resolve(rootDir, "src/api"), resolve(publicDir, "src/api"), { recursive: true });
24-
console.log("Copied server source to public/src/");
25-
26-
console.log("✅ Vercel build complete: public/");
24+
// Vercel auto-detects and compiles src/index.ts as the Hono server
25+
// SPA fallback is handled by rewrites in vercel.json
26+
console.log("✅ Vercel build complete!");
27+
console.log(" Static files: public/ (CDN)");
28+
console.log(" Server: src/index.ts (auto-compiled by Vercel)");

src/index.ts

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,78 @@
11
import { Hono } from "hono";
2+
import { readFileSync, readdirSync, existsSync } from "fs";
3+
import { resolve, dirname } from "path";
24
import api from "./api/api";
5+
import { serveStatic } from "@hono/node-server/serve-static";
36

47
const app = new Hono();
58

6-
// API routes
9+
10+
// Debug route to see filesystem structure on Vercel
11+
app.get("/_debug", (c) => {
12+
const listDir = (path: string, depth = 0): string[] => {
13+
const results: string[] = [];
14+
const indent = " ".repeat(depth);
15+
try {
16+
if (!existsSync(path)) {
17+
results.push(`${indent}[NOT FOUND: ${path}]`);
18+
return results;
19+
}
20+
const entries = readdirSync(path, { withFileTypes: true });
21+
for (const entry of entries.slice(0, 50)) { // Limit to 50 entries
22+
if (entry.isDirectory()) {
23+
results.push(`${indent}${entry.name}/`);
24+
if (depth < 2) { // Limit depth
25+
results.push(...listDir(resolve(path, entry.name), depth + 1));
26+
}
27+
} else {
28+
results.push(`${indent}${entry.name}`);
29+
}
30+
}
31+
} catch (e) {
32+
results.push(`${indent}[ERROR: ${e}]`);
33+
}
34+
return results;
35+
};
36+
37+
const cwd = process.cwd();
38+
const metaDirname = import.meta.dirname;
39+
40+
const info = {
41+
cwd,
42+
metaDirname,
43+
cwdContents: listDir(cwd),
44+
metaDirnameContents: listDir(metaDirname),
45+
publicFromCwd: listDir(resolve(cwd, "public")),
46+
parentDir: listDir(resolve(metaDirname, "..")),
47+
};
48+
49+
return c.json(info, 200, { "Content-Type": "application/json" });
50+
});
51+
52+
// API routes first
753
app.route("/", api);
854

9-
export default app;
55+
app.use("/*", serveStatic({ root: resolve(process.cwd(), "public") }));
1056

57+
58+
// SPA fallback - serve index.html for client-side routing
59+
// Static files are served by Vercel CDN from public/
60+
app.get("*", (c) => {
61+
const path = c.req.path;
62+
63+
// Skip if it looks like a static file request
64+
if (path.includes(".") && !path.endsWith(".html")) {
65+
return c.notFound();
66+
}
67+
68+
// Serve index.html for SPA routes
69+
try {
70+
const indexPath = resolve(process.cwd(), "public", "index.html");
71+
const html = readFileSync(indexPath, "utf-8");
72+
return c.html(html);
73+
} catch {
74+
return c.notFound();
75+
}
76+
});
77+
78+
export default app;

vercel.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"$schema": "https://openapi.vercel.sh/vercel.json",
33
"installCommand": "bun install",
44
"buildCommand": "bun run ./scripts/build-vercel.ts",
5-
"outputDirectory": "public"
5+
"bunVersion": "1.3"
66
}

0 commit comments

Comments
 (0)