hot reload, search refactor begin

This commit is contained in:
Simon Martens
2025-02-25 19:23:00 +01:00
parent f35c738cee
commit 4d65b71563
24 changed files with 706 additions and 202 deletions

View File

@@ -120,20 +120,21 @@ func (app *App) Serve() error {
// INFO: hot reloading for poor people
if app.MAConfig.Debug {
watcher, err := fsnotify.NewWatcher()
watcher, err := EngineWatcher(engine)
if err != nil {
return fmt.Errorf("Failed to create watcher: %w.", err)
}
defer watcher.Close()
go app.watchFN(watcher, engine)
if err := watcher.Add(LAYOUT_DIR); err != nil {
return fmt.Errorf("Failed to watch layout directory: %w.", err)
app.PB.Logger().Error("Failed to create watcher, continuing without", "error", err)
} else {
watcher.AddRecursive(LAYOUT_DIR)
watcher.AddRecursive(ROUTES_DIR)
engine.Debug()
rwatcher, err := RefreshWatcher(engine)
if err != nil {
app.PB.Logger().Error("Failed to create watcher, continuing without", "error", err)
} else {
rwatcher.Add("./views/assets")
}
}
if err := watcher.Add(ROUTES_DIR); err != nil {
return fmt.Errorf("Failed to watch routes directory: %w.", err)
}
}
app.PB.OnBootstrap().BindFunc(func(e *core.BootstrapEvent) error {

136
app/watch.go Normal file
View File

@@ -0,0 +1,136 @@
package app
import (
"io/fs"
"log"
"os"
"path/filepath"
"time"
"github.com/Theodor-Springmann-Stiftung/musenalm/templating"
"github.com/fsnotify/fsnotify"
)
const (
WATCHER_DEBOUNCE = 300 * time.Millisecond
)
// INFO: this is hot reload for poor people
type Watcher struct {
*fsnotify.Watcher
}
func RefreshWatcher(engine *templating.Engine) (*Watcher, error) {
watcher := Watcher{}
w, err := fsnotify.NewWatcher()
if err != nil {
return nil, err
}
watcher.Watcher = w
done := make(chan bool)
go func() {
var reloadTimer *time.Timer
for {
select {
case event := <-watcher.Events:
if event.Op&(fsnotify.Create|fsnotify.Write|fsnotify.Remove|fsnotify.Rename) != 0 {
if reloadTimer != nil {
reloadTimer.Stop()
}
reloadTimer = time.AfterFunc(WATCHER_DEBOUNCE, func() {
log.Println("Changes detected, reloading templates...")
engine.Refresh()
})
}
if event.Op&fsnotify.Create == fsnotify.Create {
fi, statErr := os.Stat(event.Name)
if statErr == nil && fi.IsDir() {
_ = watcher.Add(event.Name)
log.Printf("Now watching new directory: %s", event.Name)
}
}
case err := <-watcher.Errors:
if err != nil {
log.Printf("fsnotify error: %v\n", err)
}
case <-done:
watcher.Close()
return
}
}
}()
return &watcher, nil
}
func EngineWatcher(engine *templating.Engine) (*Watcher, error) {
watcher := Watcher{}
w, err := fsnotify.NewWatcher()
if err != nil {
return nil, err
}
watcher.Watcher = w
done := make(chan bool)
go func() {
var reloadTimer *time.Timer
for {
select {
case event := <-watcher.Events:
if event.Op&(fsnotify.Create|fsnotify.Write|fsnotify.Remove|fsnotify.Rename) != 0 {
if reloadTimer != nil {
reloadTimer.Stop()
}
reloadTimer = time.AfterFunc(WATCHER_DEBOUNCE, func() {
log.Println("Changes detected, reloading templates...")
engine.Reload()
})
}
if event.Op&fsnotify.Create == fsnotify.Create {
fi, statErr := os.Stat(event.Name)
if statErr == nil && fi.IsDir() {
_ = watcher.Add(event.Name)
log.Printf("Now watching new directory: %s", event.Name)
}
}
case err := <-watcher.Errors:
if err != nil {
log.Printf("fsnotify error: %v\n", err)
}
case <-done:
watcher.Close()
return
}
}
}()
return &watcher, nil
}
func (w *Watcher) AddRecursive(root string) error {
return filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
werr := w.Add(path)
if werr != nil {
return werr
}
log.Printf("Now watching directory: %s", path)
}
return nil
})
}