@@ -25,6 +25,8 @@ import type {
2525 ThemeFSEventPayload ,
2626} from '@shopify/cli-kit/node/themes/types'
2727
28+ const FILE_EVENT_DEBOUNCE_TIME_IN_MS = 250
29+
2830const THEME_DIRECTORY_PATTERNS = [
2931 'assets/**/*.*' ,
3032 'config/**/*.json' ,
@@ -321,10 +323,29 @@ export function mountThemeFileSystem(root: string, options?: ThemeFileSystemOpti
321323 ignoreInitial : true ,
322324 } )
323325
326+ // Debounce file events per-file
327+ const pendingEvents = new Map < string , { eventName : 'add' | 'change' | 'unlink' ; timeout : NodeJS . Timeout } > ( )
328+
329+ const queueFsEvent = ( eventName : 'add' | 'change' | 'unlink' , filePath : string ) => {
330+ const fileKey = getKey ( filePath )
331+
332+ const pending = pendingEvents . get ( fileKey )
333+ if ( pending ) {
334+ clearTimeout ( pending . timeout )
335+ }
336+
337+ const timeout = setTimeout ( ( ) => {
338+ pendingEvents . delete ( fileKey )
339+ handleFsEvent ( eventName , themeId , adminSession , filePath )
340+ } , FILE_EVENT_DEBOUNCE_TIME_IN_MS )
341+
342+ pendingEvents . set ( fileKey , { eventName, timeout} )
343+ }
344+
324345 watcher
325- . on ( 'add' , handleFsEvent . bind ( null , 'add' , themeId , adminSession ) )
326- . on ( 'change' , handleFsEvent . bind ( null , 'change' , themeId , adminSession ) )
327- . on ( 'unlink' , handleFsEvent . bind ( null , 'unlink' , themeId , adminSession ) )
346+ . on ( 'add' , queueFsEvent . bind ( null , 'add' ) )
347+ . on ( 'change' , queueFsEvent . bind ( null , 'change' ) )
348+ . on ( 'unlink' , queueFsEvent . bind ( null , 'unlink' ) )
328349 } ,
329350 }
330351}
0 commit comments