@junejs/cli 0.0.49 → 0.0.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/watch.ts +37 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@junejs/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.50",
|
|
4
4
|
"description": "The `june` CLI — dev / build / deploy / gen / info. A thin bin over @junejs/server.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"typecheck": "tsc --noEmit"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@junejs/core": ">=0.0.
|
|
24
|
-
"@junejs/server": ">=0.0.
|
|
23
|
+
"@junejs/core": ">=0.0.48",
|
|
24
|
+
"@junejs/server": ">=0.0.51"
|
|
25
25
|
},
|
|
26
26
|
"repository": {
|
|
27
27
|
"type": "git",
|
package/src/watch.ts
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// HMR belongs to the native runtime track; this is the Bun/Node host's story.
|
|
6
6
|
|
|
7
7
|
import { spawn, type ChildProcess } from "node:child_process";
|
|
8
|
-
import { watch } from "node:fs";
|
|
9
|
-
import { sep } from "node:path";
|
|
8
|
+
import { existsSync, watch } from "node:fs";
|
|
9
|
+
import { join, relative, resolve, sep } from "node:path";
|
|
10
10
|
|
|
11
11
|
const IGNORED_DIRS = new Set(["node_modules", ".git", "dist", ".june"]);
|
|
12
12
|
|
|
@@ -42,10 +42,10 @@ export function superviseDev(root: string): undefined {
|
|
|
42
42
|
});
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
const restart = async (file: string) => {
|
|
45
|
+
const restart = async (file: string, contentChanged: boolean) => {
|
|
46
46
|
if (restarting) return; // an edit mid-restart is picked up by the next save
|
|
47
47
|
restarting = true;
|
|
48
|
-
if (
|
|
48
|
+
if (contentChanged) {
|
|
49
49
|
// The frozen manifest must be fresh BEFORE the new server boots.
|
|
50
50
|
try {
|
|
51
51
|
const { generateContent } = await import("@junejs/server");
|
|
@@ -80,15 +80,44 @@ export function superviseDev(root: string): undefined {
|
|
|
80
80
|
c.kill();
|
|
81
81
|
};
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
// Debounced scheduling shared by the root watcher and any content-source watchers. `content`
|
|
84
|
+
// ORs across coalesced events, so an app edit landing right after a content edit can't cancel
|
|
85
|
+
// the pending regen.
|
|
86
|
+
let pending: { file: string; content: boolean } | undefined;
|
|
84
87
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
88
|
+
const schedule = (file: string, content: boolean) => {
|
|
89
|
+
pending = { file, content: content || (pending?.content ?? false) };
|
|
90
|
+
clearTimeout(timer);
|
|
91
|
+
timer = setTimeout(() => void restart(pending!.file, pending!.content), 80);
|
|
92
|
+
};
|
|
85
93
|
watch(root, { recursive: true }, (_event, file) => {
|
|
86
94
|
if (!file || ignoredPath(file)) return;
|
|
87
|
-
|
|
88
|
-
clearTimeout(timer);
|
|
89
|
-
timer = setTimeout(() => void restart(pending!), 80);
|
|
95
|
+
schedule(file, file.startsWith(`content${sep}`));
|
|
90
96
|
});
|
|
91
97
|
|
|
98
|
+
// Extra content sources (config `content.sources`) live OUTSIDE the app root — fs.watch(root)
|
|
99
|
+
// can't see them, so each gets its own watcher; any change there is a content change (regen +
|
|
100
|
+
// restart). Config is loaded tolerantly and async: if it can't load yet (a generated config
|
|
101
|
+
// importing app/_content.ts before the first freeze), sources simply aren't watched this run —
|
|
102
|
+
// the next `june dev` picks them up. A config edit that CHANGES the source list also needs a
|
|
103
|
+
// dev rerun (the supervisor process caches the config module).
|
|
104
|
+
void (async () => {
|
|
105
|
+
try {
|
|
106
|
+
const { loadJuneConfig } = await import("@junejs/server");
|
|
107
|
+
const config = await loadJuneConfig(root);
|
|
108
|
+
for (const s of config.content?.sources ?? []) {
|
|
109
|
+
const dir = resolve(root, s.dir);
|
|
110
|
+
if (!existsSync(dir)) continue; // gen fails loudly on this; nothing to watch here
|
|
111
|
+
watch(dir, { recursive: true }, (_event, file) => {
|
|
112
|
+
if (!file || ignoredPath(file)) return;
|
|
113
|
+
schedule(relative(root, join(dir, file)), true);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
} catch {
|
|
117
|
+
/* config not loadable yet — see above */
|
|
118
|
+
}
|
|
119
|
+
})();
|
|
120
|
+
|
|
92
121
|
for (const sig of ["SIGINT", "SIGTERM"] as const) {
|
|
93
122
|
process.on(sig, () => {
|
|
94
123
|
child?.kill(sig);
|