1- import type {
2- EnvironmentModuleNode ,
3- FSWatcher ,
4- PluginOption ,
5- ViteDevServer ,
6- } from "vite" ;
1+ import type { EnvironmentModuleNode , FSWatcher , PluginOption , ViteDevServer } from "vite" ;
2+ import { debounce } from "../../utils/debounce.ts" ;
73import { VITE_ENVIRONMENTS } from "../constants.ts" ;
84import { moduleId } from "./index.ts" ;
95import type { BaseFileSystemRouter } from "./router.ts" ;
106
11- interface CompiledRouter {
12- removeRoute ( path : string ) : void ;
13- addRoute ( path : string ) : void ;
14- updateRoute ( path : string ) : void ;
15- addEventListener ( event : "reload" , handler : ( ) => void ) : void ;
16- removeEventListener ( event : "reload" , handler : ( ) => void ) : void ;
17- }
18-
19- function setupWatcher ( watcher : FSWatcher , routes : CompiledRouter ) : void {
7+ function setupWatcher ( watcher : FSWatcher , routes : BaseFileSystemRouter ) : void {
208 watcher . on ( "unlink" , path => routes . removeRoute ( path ) ) ;
219 watcher . on ( "add" , path => routes . addRoute ( path ) ) ;
2210 watcher . on ( "change" , path => routes . updateRoute ( path ) ) ;
2311}
2412
2513function createRoutesReloader (
2614 server : ViteDevServer ,
27- routes : CompiledRouter ,
15+ routes : BaseFileSystemRouter ,
2816 environment : "client" | "ssr" ,
29- ) : ( ) => void {
30- routes . addEventListener ( "reload" , handleRoutesReload ) ;
31- return ( ) => routes . removeEventListener ( "reload" , handleRoutesReload ) ;
17+ ) {
18+ const devEnv = server . environments [ environment ] ! ;
19+ if ( ! devEnv ?. moduleGraph ) return ;
20+
21+ /**
22+ * Debounce catches multiple route changes in a row
23+ * Short timeout for inexpensive invalidations11
24+ */
25+ const invalidateModule = debounce ( ( mod : EnvironmentModuleNode ) => {
26+ devEnv . moduleGraph . invalidateModule ( mod ) ;
27+ } , 0 ) ;
3228
33- function handleRoutesReload ( ) : void {
34- const envName =
35- environment === "ssr" ? VITE_ENVIRONMENTS . server : VITE_ENVIRONMENTS . client ;
36- const devEnv = server . environments [ envName ] ;
37- if ( ! devEnv ?. moduleGraph ) return ;
29+ /**
30+ * Long debounce timeout for expensive reloads
31+ */
32+ const reloadModule = debounce ( ( mod : EnvironmentModuleNode ) => {
33+ devEnv . reloadModule ( mod ) ;
34+ } , 200 ) ;
3835
39- const mod : EnvironmentModuleNode | undefined =
40- devEnv . moduleGraph . getModuleById ( moduleId ) ;
41- if ( mod ) {
42- const seen = new Set < EnvironmentModuleNode > ( ) ;
43- devEnv . moduleGraph . invalidateModule ( mod , seen ) ;
36+ return routes . on ( "reload" , function handleRoutesReload ( evt ) : void {
37+ const mod = devEnv . moduleGraph . getModuleById ( moduleId ) ! ;
38+ if ( ! mod ) {
39+ devEnv . hot . send ( { type : "full-reload" } ) ;
40+ return ;
4441 }
4542
46- if ( environment !== "ssr" ) {
47- if ( mod ) {
48- devEnv . reloadModule ( mod ) ;
49- } else if ( devEnv . hot ) {
50- devEnv . hot . send ( { type : "full-reload" } ) ;
51- }
43+ if ( environment === VITE_ENVIRONMENTS . client && evt . detail . type !== "update" ) {
44+ // Client has to be reloaded when routes are added or removed
45+ reloadModule ( mod ) ;
46+ } else {
47+ invalidateModule ( mod ) ;
5248 }
53- }
49+ } ) ;
5450}
5551
5652export const fileSystemWatcher = (
@@ -59,11 +55,11 @@ export const fileSystemWatcher = (
5955 const plugin : PluginOption = {
6056 name : "fs-watcher" ,
6157 async configureServer ( server : ViteDevServer ) {
62- Object . keys ( routers ) . forEach ( environment => {
63- const router = ( globalThis as any ) . ROUTERS [ environment ] ;
58+ for ( const environment of [ VITE_ENVIRONMENTS . server , VITE_ENVIRONMENTS . client ] ) {
59+ const router = routers [ environment ] ;
6460 setupWatcher ( server . watcher , router ) ;
65- createRoutesReloader ( server , router , environment as keyof typeof routers ) ;
66- } ) ;
61+ createRoutesReloader ( server , router , environment ) ;
62+ }
6763 } ,
6864 } ;
6965 return plugin ;
0 commit comments