Created
October 20, 2025 04:57
-
-
Save KonnorRogers/adf014a201af314940f96fd94d1ee071 to your computer and use it in GitHub Desktop.
Hanami file watcher for esbuild
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // config/assets.js | |
| import * as path from "node:path" | |
| import * as url from 'node:url'; | |
| import * as assets from "hanami-assets"; | |
| import chokidar from 'chokidar'; | |
| // ESM polyfill for __dirname | |
| const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); | |
| // To provide additional esbuild (https://esbuild.github.io) options, use the following: | |
| // | |
| // Read more at: https://guides.hanamirb.org/assets/customization/ | |
| // | |
| let watchMode = false | |
| const context = await assets.run({ | |
| esbuildOptionsFn: (args, esbuildOptions) => { | |
| // Add to esbuildOptions here. Use `args.watch` as a condition for different options for | |
| // compile vs watch. | |
| if (args.watch) { | |
| watchMode = true | |
| } | |
| return esbuildOptions; | |
| } | |
| }); | |
| if (watchMode) { | |
| function debounce(func, delay) { | |
| let timeoutId; // This will store the ID of the timeout | |
| return function(...args) { // Returns a new function that will be called | |
| const context = this; // Preserves the 'this' context | |
| clearTimeout(timeoutId); // Clear any existing timeout | |
| timeoutId = setTimeout(() => { // Set a new timeout | |
| func.apply(context, args); // Execute the original function after the delay | |
| }, delay); | |
| }; | |
| } | |
| const watchPath = path.resolve(path.join(__dirname, "..")) | |
| const watcher = chokidar.watch(watchPath, { | |
| persistent: true, | |
| ignored: (path, stats) => { | |
| // Careful...this watcher is watching *everything*, including slices, and any compiled files...you may want to scope this down...or scope down the watch path.. | |
| // Only watch `.rb` files. | |
| return stats?.isFile() && !path.endsWith('.rb') | |
| }, | |
| ignoreInitial: true, | |
| // This is usually only necessary for Docker. | |
| usePolling: true, | |
| }); | |
| async function handleFile(evt, path, ...args) { | |
| if (evt === "add") { | |
| console.log(`File ${path} has been added`) | |
| } else if (evt === "change") { | |
| console.log(`File ${path} has been changed`) | |
| } else if (evt === "unlink") { | |
| console.log(`File ${path} has been removed`) | |
| } | |
| console.log("Rebuilding...") | |
| await context.rebuild() | |
| console.log("Finished rebuilding.") | |
| } | |
| const debouncedFileHandler = debounce(handleFile, 100) | |
| const events = ["add", "change", "unlink"] | |
| events.forEach((evt) => { | |
| watcher.on(evt, async (path, ...args) => { | |
| debouncedFileHandler(evt, path, ...args) | |
| }) | |
| }) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment