Skip to content

Commit 6b64126

Browse files
committed
Enable worktree-based development with auto port detection
- Add findFreePort() to auto-detect available ports 3000-3099 - If PORT env var is set, use it explicitly (fail if busy) - If PORT is unset, auto-find next free port starting from 3000 - Write .port file so tooling can discover running instance - Update Playwright config to read PORT from env var - Add .env, .env.local, .port to .gitignore for per-worktree isolation This enables multiple independent instances to run on the same machine, each in its own git worktree with automatic port allocation.
1 parent 86bc2a4 commit 6b64126

File tree

3 files changed

+32
-6
lines changed

3 files changed

+32
-6
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,10 @@ explore-site.mjs
1010
public/js/app.js
1111
public/js/app.js.map
1212

13+
# Per-worktree environment config
14+
.env
15+
.env.local
16+
.port
17+
1318
# Local Netlify folder
1419
.netlify

playwright.config.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import { defineConfig } from '@playwright/test';
22

3+
const PORT = Number(process.env.PORT) || 3000;
4+
35
export default defineConfig({
46
testDir: './e2e',
57
timeout: 15000,
68
use: {
7-
baseURL: 'http://localhost:3000',
9+
baseURL: `http://localhost:${PORT}`,
810
headless: true,
911
},
1012
webServer: {
11-
command: 'bun run start',
12-
port: 3000,
13+
command: `PORT=${PORT} bun run start`,
14+
port: PORT,
1315
reuseExistingServer: true,
1416
},
1517
});

src/server.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,23 @@
1-
const PORT = Number(process.env.PORT) || 3000;
1+
const PREFERRED_PORT = Number(process.env.PORT) || 3000;
22
const PUBLIC_DIR = new URL("../public", import.meta.url).pathname;
33

4+
function findFreePort(start: number): number {
5+
for (let port = start; port < start + 100; port++) {
6+
try {
7+
const probe = Bun.serve({ port, fetch: () => new Response() });
8+
probe.stop(true);
9+
return port;
10+
} catch {
11+
// Port busy, try next
12+
}
13+
}
14+
throw new Error(`No free port found in range ${start}${start + 99}`);
15+
}
16+
17+
const PORT = process.env.PORT
18+
? PREFERRED_PORT // Explicit PORT: use exactly, fail if busy
19+
: findFreePort(PREFERRED_PORT); // No PORT set: auto-find free port
20+
421
const MIME_TYPES: Record<string, string> = {
522
".html": "text/html",
623
".css": "text/css",
@@ -51,7 +68,7 @@ function respond(body: BodyInit, contentType: string): Response {
5168
});
5269
}
5370

54-
Bun.serve({
71+
const server = Bun.serve({
5572
port: PORT,
5673
async fetch(req) {
5774
const url = new URL(req.url);
@@ -72,4 +89,6 @@ Bun.serve({
7289
},
7390
});
7491

75-
console.log(`EasyPDF Lite running at http://localhost:${PORT}`);
92+
// Write port file for tooling (Playwright, etc.) to discover the running instance
93+
await Bun.write(`${import.meta.dir}/../.port`, String(server.port));
94+
console.log(`EasyPDF Lite running at http://localhost:${server.port}`);

0 commit comments

Comments
 (0)