Skip to content

Commit 35e2de5

Browse files
committed
Fix vercel build
1 parent 370ac2e commit 35e2de5

File tree

5 files changed

+87
-15
lines changed

5 files changed

+87
-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: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,74 @@
11
import { Hono } from "hono";
2+
import { readFileSync, readdirSync, existsSync } from "fs";
3+
import { resolve, dirname } from "path";
24
import api from "./api/api";
35

46
const app = new Hono();
57

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

9-
export default app;
54+
// SPA fallback - serve index.html for client-side routing
55+
// Static files are served by Vercel CDN from public/
56+
app.get("*", (c) => {
57+
const path = c.req.path;
58+
59+
// Skip if it looks like a static file request
60+
if (path.includes(".") && !path.endsWith(".html")) {
61+
return c.notFound();
62+
}
1063

64+
// Serve index.html for SPA routes
65+
try {
66+
const indexPath = resolve(process.cwd(), "public", "index.html");
67+
const html = readFileSync(indexPath, "utf-8");
68+
return c.html(html);
69+
} catch {
70+
return c.notFound();
71+
}
72+
});
73+
74+
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)