11import colors from 'picocolors'
22import type { ViteDevServer } from './server'
33import { isDefined } from './utils'
4+ import type { PreviewServer } from './preview'
5+ import { openBrowser } from './server/openBrowser'
46
5- export type BindShortcutsOptions = {
7+ export type BindShortcutsOptions < Server = ViteDevServer | PreviewServer > = {
68 /**
79 * Print a one line hint to the terminal.
810 */
911 print ?: boolean
10- customShortcuts ?: ( CLIShortcut | undefined | null ) [ ]
12+ customShortcuts ?: ( CLIShortcut < Server > | undefined | null ) [ ]
1113}
1214
13- export type CLIShortcut = {
15+ export type CLIShortcut < Server = ViteDevServer | PreviewServer > = {
1416 key : string
1517 description : string
16- action ( server : ViteDevServer ) : void | Promise < void >
18+ action ( server : Server ) : void | Promise < void >
1719}
1820
19- export function bindShortcuts (
20- server : ViteDevServer ,
21- opts : BindShortcutsOptions ,
21+ export function bindShortcuts < Server extends ViteDevServer | PreviewServer > (
22+ server : Server ,
23+ opts ? : BindShortcutsOptions < Server > ,
2224) : void {
2325 if ( ! server . httpServer || ! process . stdin . isTTY || process . env . CI ) {
2426 return
2527 }
26- server . _shortcutsOptions = opts
2728
28- if ( opts . print ) {
29+ const isDev = isDevServer ( server )
30+
31+ if ( isDev ) {
32+ server . _shortcutsOptions = opts
33+ }
34+
35+ if ( opts ?. print ) {
2936 server . config . logger . info (
3037 colors . dim ( colors . green ( ' ➜' ) ) +
3138 colors . dim ( ' press ' ) +
@@ -34,16 +41,25 @@ export function bindShortcuts(
3441 )
3542 }
3643
37- const shortcuts = ( opts . customShortcuts ?? [ ] )
44+ const shortcuts = ( opts ? .customShortcuts ?? [ ] )
3845 . filter ( isDefined )
39- . concat ( BASE_SHORTCUTS )
46+ // @ts -expect-error passing the right types, but typescript can't detect it
47+ . concat ( isDev ? BASE_DEV_SHORTCUTS : BASE_PREVIEW_SHORTCUTS )
4048
4149 let actionRunning = false
4250
4351 const onInput = async ( input : string ) => {
4452 // ctrl+c or ctrl+d
4553 if ( input === '\x03' || input === '\x04' ) {
46- await server . close ( ) . finally ( ( ) => process . exit ( 1 ) )
54+ try {
55+ if ( isDev ) {
56+ await server . close ( )
57+ } else {
58+ server . httpServer . close ( )
59+ }
60+ } finally {
61+ process . exit ( 1 )
62+ }
4763 return
4864 }
4965
@@ -81,7 +97,13 @@ export function bindShortcuts(
8197 } )
8298}
8399
84- const BASE_SHORTCUTS : CLIShortcut [ ] = [
100+ function isDevServer (
101+ server : ViteDevServer | PreviewServer ,
102+ ) : server is ViteDevServer {
103+ return 'pluginContainer' in server
104+ }
105+
106+ const BASE_DEV_SHORTCUTS : CLIShortcut < ViteDevServer > [ ] = [
85107 {
86108 key : 'r' ,
87109 description : 'restart the server' ,
@@ -119,3 +141,25 @@ const BASE_SHORTCUTS: CLIShortcut[] = [
119141 } ,
120142 } ,
121143]
144+
145+ const BASE_PREVIEW_SHORTCUTS : CLIShortcut < PreviewServer > [ ] = [
146+ {
147+ key : 'o' ,
148+ description : 'open in browser' ,
149+ action ( server ) {
150+ const url = server . resolvedUrls . local [ 0 ]
151+ openBrowser ( url , true , server . config . logger )
152+ } ,
153+ } ,
154+ {
155+ key : 'q' ,
156+ description : 'quit' ,
157+ action ( server ) {
158+ try {
159+ server . httpServer . close ( )
160+ } finally {
161+ process . exit ( )
162+ }
163+ } ,
164+ } ,
165+ ]
0 commit comments