Hot reload
HotReloader watches a template file on disk. When you save it, the screen's template tree is rebuilt from the new XML, keeping your controller and its refs, so the data on screen stays as it was. It can watch a theme JSON file too.
It is a development tool. Ship templates as text or binary and leave the reloader out of release builds.
Use it
Your project needs the fs system and permissions: { fs: true }. HotReloader and newHotReloader come from the package root:
ts
import { Files } from "fs";
import { Controller, DEFAULT_STAGE, HotReloader, Ref, Screen, TemplateRegistry, newHotReloader } from "willowui";
const XML_PATH: string = moduleDir + "/ui/main.xml";
class MainScreen implements Controller {
title: Ref<string> = new Ref<string>("Edit ui/main.xml and save");
reloader: HotReloader | null = null;
onCreate(screen: Screen): void {
const reg: TemplateRegistry = new TemplateRegistry();
Files.readText(XML_PATH).then((xml: string): void => {
reg.registerXML("main", xml);
screen.add(reg.instantiate("main", this, screen));
newHotReloader(reg, screen, this, "main", XML_PATH).then((hr: HotReloader): void => {
this.reloader = hr;
});
});
}
onUpdate(dt: float): void {}
onDispose(): void {
const hr: HotReloader | null = this.reloader;
if (hr != null) { (hr as HotReloader).stop(); }
}
lookupRef(path: string): any {
if (path == "title") { return this.title; }
return null;
}
callMethod(name: string): boolean { return false; }
}
DEFAULT_STAGE.setScene(engine.root2d);
DEFAULT_STAGE.add(new Screen().withController(new MainScreen()));
App.onFrame((dt: float): void => { DEFAULT_STAGE.update(dt); });newHotReloader(registry, screen, controller, templateName, xmlPath) reads the file, then starts watching it.
What a reload does
- The file is polled every 50 ms (ThicketScript has no file-watch API). A change counts once the file's size and timestamps have been stable for 200 ms, so an editor's save-in-steps triggers one reload, not several.
- If the bytes are the same as before, nothing happens.
- The XML is recompiled. If it has an error, the error is reported and the old tree stays on screen, so a typo never blanks the screen.
- The screen's template tree is cleared (its bindings stopped, its components disposed) and the new template is instantiated with the same controller.
Raw willow nodes added with screen.addNode survive a reload, because only components are cleared. Anything a controller built in code alongside the template is removed with the rest of the screen's components, so build such pieces inside the template, or re-add them.
Themes
await reloader.watchTheme(jsonPath) also watches a theme JSON file. On a change it recompiles the theme and applies it to every top-level component of the screen. Images the theme names (atlas pages, nine-slices) are not re-read, only the JSON.
Methods
| Method | Use |
|---|---|
stop() | Stop watching. Call it in onDispose. |
reload() | Reload the template now (returns a Promise). |
reloadTheme() | Reload the theme now (returns a Promise). |
watchTheme(path) | Start watching a theme file. |