@@ -20,7 +20,8 @@ import pty from '@lydell/node-pty';
2020const __filename = fileURLToPath ( import . meta. url ) ;
2121const __dirname = path . dirname ( __filename ) ;
2222
23- const HTTP_PORT = process . env . PORT || 8080 ;
23+ const DEV_MODE = process . argv . includes ( '--dev' ) ;
24+ const HTTP_PORT = process . env . PORT || ( DEV_MODE ? 8000 : 8080 ) ;
2425const WS_PORT = 3001 ;
2526
2627// ============================================================================
@@ -31,13 +32,25 @@ import { createRequire } from 'module';
3132const require = createRequire ( import . meta. url ) ;
3233
3334function findGhosttyWeb ( ) {
35+ // In dev mode, we use Vite - no need to find built assets
36+ if ( DEV_MODE ) {
37+ const repoRoot = path . join ( __dirname , '..' , '..' ) ;
38+ const wasmPath = path . join ( repoRoot , 'ghostty-vt.wasm' ) ;
39+ if ( ! fs . existsSync ( wasmPath ) ) {
40+ console . error ( 'Error: ghostty-vt.wasm not found.' ) ;
41+ console . error ( 'Run: bun run build:wasm' ) ;
42+ process . exit ( 1 ) ;
43+ }
44+ return { distPath : null , wasmPath, repoRoot } ;
45+ }
46+
3447 // First, check for local development (repo root dist/)
3548 const localDist = path . join ( __dirname , '..' , '..' , 'dist' ) ;
3649 const localJs = path . join ( localDist , 'ghostty-web.js' ) ;
3750 const localWasm = path . join ( __dirname , '..' , '..' , 'ghostty-vt.wasm' ) ;
3851
3952 if ( fs . existsSync ( localJs ) && fs . existsSync ( localWasm ) ) {
40- return { distPath : localDist , wasmPath : localWasm , isDev : true } ;
53+ return { distPath : localDist , wasmPath : localWasm , repoRoot : path . join ( __dirname , '..' , '..' ) } ;
4154 }
4255
4356 // Use require.resolve to find the installed ghostty-web package
@@ -49,7 +62,7 @@ function findGhosttyWeb() {
4962 const wasmPath = path . join ( ghosttyWebRoot , 'ghostty-vt.wasm' ) ;
5063
5164 if ( fs . existsSync ( path . join ( distPath , 'ghostty-web.js' ) ) && fs . existsSync ( wasmPath ) ) {
52- return { distPath, wasmPath, isDev : false } ;
65+ return { distPath, wasmPath, repoRoot : null } ;
5366 }
5467 } catch ( e ) {
5568 // require.resolve failed, package not found
@@ -62,7 +75,7 @@ function findGhosttyWeb() {
6275 process . exit ( 1 ) ;
6376}
6477
65- const { distPath, wasmPath, isDev } = findGhosttyWeb ( ) ;
78+ const { distPath, wasmPath, repoRoot } = findGhosttyWeb ( ) ;
6679
6780// ============================================================================
6881// HTML Template
@@ -193,8 +206,9 @@ const HTML_TEMPLATE = `<!doctype html>
193206 </div>
194207
195208 <script type="module">
196- import { Terminal, FitAddon } from '/dist/ghostty-web.js';
209+ import { init, Terminal, FitAddon } from '/dist/ghostty-web.js';
197210
211+ await init();
198212 const term = new Terminal({
199213 cols: 80,
200214 rows: 24,
@@ -560,24 +574,24 @@ function sendWebSocketFrame(socket, data) {
560574// Startup
561575// ============================================================================
562576
563- httpServer . listen ( HTTP_PORT , ( ) => {
577+ function printBanner ( url ) {
564578 console . log ( '\n' + '═' . repeat ( 60 ) ) ;
565- console . log ( ' 🚀 ghostty-web demo server' + ( isDev ? ' (dev mode)' : '' ) ) ;
579+ console . log ( ' 🚀 ghostty-web demo server' + ( DEV_MODE ? ' (dev mode)' : '' ) ) ;
566580 console . log ( '═' . repeat ( 60 ) ) ;
567- console . log ( `\n 📺 Open: http://localhost: ${ HTTP_PORT } ` ) ;
581+ console . log ( `\n 📺 Open: ${ url } ` ) ;
568582 console . log ( ` 📡 WebSocket PTY: ws://localhost:${ WS_PORT } /ws` ) ;
569583 console . log ( ` 🐚 Shell: ${ getShell ( ) } ` ) ;
570584 console . log ( ` 📁 Home: ${ homedir ( ) } ` ) ;
571- if ( isDev ) {
585+ if ( DEV_MODE ) {
586+ console . log ( ` 🔥 Hot reload enabled via Vite` ) ;
587+ } else if ( repoRoot ) {
572588 console . log ( ` 📦 Using local build: ${ distPath } ` ) ;
573589 }
574590 console . log ( '\n ⚠️ This server provides shell access.' ) ;
575591 console . log ( ' Only use for local development.\n' ) ;
576592 console . log ( '═' . repeat ( 60 ) ) ;
577593 console . log ( ' Press Ctrl+C to stop.\n' ) ;
578- } ) ;
579-
580- wsServer . listen ( WS_PORT ) ;
594+ }
581595
582596// Graceful shutdown
583597process . on ( 'SIGINT' , ( ) => {
@@ -588,3 +602,26 @@ process.on('SIGINT', () => {
588602 }
589603 process . exit ( 0 ) ;
590604} ) ;
605+
606+ // Start WebSocket PTY server (runs in both modes)
607+ wsServer . listen ( WS_PORT ) ;
608+
609+ // Start HTTP/Vite server
610+ if ( DEV_MODE ) {
611+ // Dev mode: use Vite for hot reload
612+ const { createServer } = await import ( 'vite' ) ;
613+ const vite = await createServer ( {
614+ root : repoRoot ,
615+ server : {
616+ port : HTTP_PORT ,
617+ strictPort : true ,
618+ } ,
619+ } ) ;
620+ await vite . listen ( ) ;
621+ printBanner ( `http://localhost:${ HTTP_PORT } /demo/` ) ;
622+ } else {
623+ // Production mode: static file server
624+ httpServer . listen ( HTTP_PORT , ( ) => {
625+ printBanner ( `http://localhost:${ HTTP_PORT } ` ) ;
626+ } ) ;
627+ }
0 commit comments