From 6dfdd80d29fc40d862197052c885a2b7e148bce0 Mon Sep 17 00:00:00 2001 From: Florian Witteler Date: Fri, 15 Dec 2023 15:55:44 +0100 Subject: [PATCH 1/3] chore: user file-watcher on parent folder the filewatcher on a file dies silently when the watched file gets deleted and the file lies in a bind-mount-volume in a docker-container on a mac --- cli/src/main/scala/Main.scala | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/cli/src/main/scala/Main.scala b/cli/src/main/scala/Main.scala index 46167c7..02e10b5 100644 --- a/cli/src/main/scala/Main.scala +++ b/cli/src/main/scala/Main.scala @@ -6,7 +6,7 @@ import typings.node.{fsMod, pathMod} import scala.scalajs.js import scala.scalajs.js.JSConverters._ -import scala.scalajs.js.timers +import scala.scalajs.js.{|, timers} object Main { @@ -57,6 +57,10 @@ object Main { var watcher: Option[fsMod.FSWatcher] = None var lastTimeout: Option[timers.SetTimeoutHandle] = None + val jsFilePath = pathMod.parse(config.jsFileName) + val jsFileName = jsFilePath.base + val jsParentFolder = jsFilePath.dir + def run(): Unit = setHandler(config) match { case Right(()) => () @@ -74,11 +78,16 @@ object Main { try { val w: fsMod.FSWatcher = fsMod.watch( - filename = config.jsFileName, - listener = { (_, _) => - println(s"${config.mode}> File changed, resetting...") - run() - watch() // since the file might have been deleted, reinitialize the watcher + filename = jsParentFolder, + listener = { (event, filename) => + println(s"watcher triggered. event: $event, filename: ${filename}") + val parsedFilePath = pathMod.parse(filename) + val parsedFilename = parsedFilePath.base + if(parsedFilename == jsFileName) { + println(s"${config.mode}> File changed, resetting...") + run() + watch() // since the file might have been deleted, reinitialize the watcher + } }, ) @@ -142,7 +151,7 @@ object Main { Either .catchNonFatal(requireUncached(pathMod.resolve(config.jsFileName))) .left - .map(exception => s"Error when requiring js file: ${exception}") + .map(exception => s"Error when requiring js file: $exception") exportedHandler <- requiredJs .selectDynamic(config.exportName) @@ -167,11 +176,11 @@ object Main { Either.catchNonFatal(function(a, b)) match { case Right(r) => r.`catch`[R]({ (error: Any) => - println(s"${mode}> Error in function promise: $error") + println(s"$mode> Error in function promise: $error") js.Promise.reject(error) }: js.Function1[Any, js.Thenable[R]]) case Left(e) => - println(s"${mode}> Error in function: $e") + println(s"$mode> Error in function: $e") throw e } } From b10de69175a13b6e92166d4f1d2623e2c04045b2 Mon Sep 17 00:00:00 2001 From: Florian Witteler Date: Fri, 15 Dec 2023 16:00:42 +0100 Subject: [PATCH 2/3] Update cli/src/main/scala/Main.scala Co-authored-by: johannes karoff --- cli/src/main/scala/Main.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/main/scala/Main.scala b/cli/src/main/scala/Main.scala index 02e10b5..dd10489 100644 --- a/cli/src/main/scala/Main.scala +++ b/cli/src/main/scala/Main.scala @@ -80,7 +80,7 @@ object Main { val w: fsMod.FSWatcher = fsMod.watch( filename = jsParentFolder, listener = { (event, filename) => - println(s"watcher triggered. event: $event, filename: ${filename}") + println(s"${config.mode}> File watcher triggered. Event: ${event}, Filename: ${filename}") val parsedFilePath = pathMod.parse(filename) val parsedFilename = parsedFilePath.base if(parsedFilename == jsFileName) { From a33f2fb01b925d88545c2df984029ee28c2f7ecc Mon Sep 17 00:00:00 2001 From: johannes karoff Date: Fri, 15 Dec 2023 16:13:02 +0100 Subject: [PATCH 3/3] debounce --- cli/src/main/scala/Main.scala | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/cli/src/main/scala/Main.scala b/cli/src/main/scala/Main.scala index dd10489..31bdf4e 100644 --- a/cli/src/main/scala/Main.scala +++ b/cli/src/main/scala/Main.scala @@ -6,7 +6,7 @@ import typings.node.{fsMod, pathMod} import scala.scalajs.js import scala.scalajs.js.JSConverters._ -import scala.scalajs.js.{|, timers} +import scala.scalajs.js.timers object Main { @@ -54,24 +54,29 @@ object Main { } def watch(config: Config.Handler): Unit = { - var watcher: Option[fsMod.FSWatcher] = None - var lastTimeout: Option[timers.SetTimeoutHandle] = None + var watcher: Option[fsMod.FSWatcher] = None + var lastTimeoutRun: Option[timers.SetTimeoutHandle] = None + var lastTimeoutWatch: Option[timers.SetTimeoutHandle] = None val jsFilePath = pathMod.parse(config.jsFileName) val jsFileName = jsFilePath.base val jsParentFolder = jsFilePath.dir - def run(): Unit = + def run(): Unit = { + lastTimeoutRun.foreach(timers.clearTimeout) + lastTimeoutRun = None + setHandler(config) match { case Right(()) => () case Left(error) => println(s"${config.mode}> Error: $error") retry() } + } def watch(): Unit = { - lastTimeout.foreach(timers.clearTimeout) - lastTimeout = None + lastTimeoutWatch.foreach(timers.clearTimeout) + lastTimeoutWatch = None watcher.foreach(_.close()) watcher = None @@ -83,10 +88,13 @@ object Main { println(s"${config.mode}> File watcher triggered. Event: ${event}, Filename: ${filename}") val parsedFilePath = pathMod.parse(filename) val parsedFilename = parsedFilePath.base - if(parsedFilename == jsFileName) { + if (parsedFilename == jsFileName) { println(s"${config.mode}> File changed, resetting...") - run() - watch() // since the file might have been deleted, reinitialize the watcher + lastTimeoutRun.foreach(timers.clearTimeout) + lastTimeoutRun = Some(timers.setTimeout(1000) { + run() + watch() // since the file might have been deleted, reinitialize the watcher + }) } }, ) @@ -109,8 +117,8 @@ object Main { def retry(msg: String = ""): Unit = { println(s"${if (msg.nonEmpty) s"$msg " else ""}Retrying...") - lastTimeout.foreach(timers.clearTimeout) - lastTimeout = Some(timers.setTimeout(2000)(watch())) + lastTimeoutWatch.foreach(timers.clearTimeout) + lastTimeoutWatch = Some(timers.setTimeout(2000)(watch())) } watch()