@@ -313,32 +313,72 @@ initAutoReloadMonitor <- function(dir) {
313
313
" .*\\ .(r|html?|js|css|png|jpe?g|gif)$"
314
314
)
315
315
316
- lastValue <- NULL
317
- check_for_update <- function (paths ) {
318
- paths <- grep(
319
- filePattern ,
320
- paths ,
321
- ignore.case = TRUE ,
322
- value = TRUE
323
- )
324
-
325
- if (length(paths ) == 0 ) {
326
- return ()
316
+
317
+ if (is_installed(" watcher" )) {
318
+ check_for_update <- function (paths ) {
319
+ paths <- grep(
320
+ filePattern ,
321
+ paths ,
322
+ ignore.case = TRUE ,
323
+ value = TRUE
324
+ )
325
+
326
+ if (length(paths ) == 0 ) {
327
+ return ()
328
+ }
329
+
330
+ cachedAutoReloadLastChanged $ set()
331
+ autoReloadCallbacks $ invoke()
332
+ }
333
+
334
+ # [garrick, 2025-02-20] Shiny <= v1.10.0 used `invalidateLater()` with an
335
+ # autoreload.interval in ms. {watcher} instead uses a latency parameter in
336
+ # seconds, which serves a similar purpose and that I'm keeping for backcompat.
337
+ latency <- getOption(" shiny.autoreload.interval" , 250 ) / 1000
338
+ watcher <- watcher :: watcher(dir , check_for_update , latency = latency )
339
+ watcher $ start()
340
+ onStop(watcher $ stop )
341
+ } else {
342
+ # Fall back to legacy observer behavior
343
+ if (! isFALSE(getOption(" shiny.autoreload.legacy_warning" , TRUE ))) {
344
+ cli :: cli_warn(
345
+ c(
346
+ " Using legacy autoreload file watching. Please install {.pkg watcher} for a more performant autoreload file watcher." ,
347
+ " i" = " Set {.run options(shiny.autoreload.legacy_warning = FALSE)} to suppress this warning."
348
+ ),
349
+ .frequency = " regularly" ,
350
+ .frequency_id = " shiny.autoreload.legacy_warning"
351
+ )
327
352
}
328
353
329
- cachedAutoReloadLastChanged $ set()
330
- autoReloadCallbacks $ invoke()
354
+ lastValue <- NULL
355
+ observeLabel <- paste0(" File Auto-Reload - '" , basename(dir ), " '" )
356
+ watcher <- observe(label = observeLabel , {
357
+ files <- sort_c(
358
+ list.files(dir , pattern = filePattern , recursive = TRUE , ignore.case = TRUE )
359
+ )
360
+ times <- file.info(files )$ mtime
361
+ names(times ) <- files
362
+
363
+ if (is.null(lastValue )) {
364
+ # First run
365
+ lastValue <<- times
366
+ } else if (! identical(lastValue , times )) {
367
+ # We've changed!
368
+ lastValue <<- times
369
+ cachedAutoReloadLastChanged $ set()
370
+ autoReloadCallbacks $ invoke()
371
+ }
372
+
373
+ invalidateLater(getOption(" shiny.autoreload.interval" , 500 ))
374
+ })
375
+
376
+ onStop(watcher $ destroy )
377
+
378
+ watcher $ destroy
331
379
}
332
380
333
- # [garrick, 2025-02-20] Shiny <= v1.10.0 used `invalidateLater()` with an
334
- # autoreload.interval in ms. {watcher} instead uses a latency parameter in
335
- # seconds, which serves a similar purpose and that I'm keeping for backcompat.
336
- latency <- getOption(" shiny.autoreload.interval" , 250 ) / 1000
337
- watcher <- watcher :: watcher(dir , check_for_update , latency = latency )
338
- watcher $ start()
339
- onStop(watcher $ stop )
340
-
341
- watcher
381
+ invisible (watcher )
342
382
}
343
383
344
384
# ' Load an app's supporting R files
0 commit comments