koguma 2.3.3 → 2.3.4
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/cli/log.ts +12 -5
- package/cli/wrangler.ts +3 -70
- package/package.json +1 -1
- package/src/admin/_bundle.ts +1 -1
- package/src/vite.js +15 -18
- package/src/vite.ts +35 -43
package/src/vite.js
CHANGED
|
@@ -3,34 +3,31 @@ import { createHash } from "node:crypto";
|
|
|
3
3
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
function kogumaHMR(options = {}) {
|
|
6
|
-
const HASH_FILENAME = "dbhash";
|
|
7
6
|
const HASH_DIR = options.kogumaDir ?? ".koguma";
|
|
8
|
-
const
|
|
9
|
-
const
|
|
7
|
+
const HASH_FILE = "dbhash";
|
|
8
|
+
const HASH_SUBPATH = `${HASH_DIR}/${HASH_FILE}`;
|
|
10
9
|
return {
|
|
11
10
|
name: "koguma-hmr",
|
|
12
11
|
configureServer(server) {
|
|
13
12
|
const root = server.config.root;
|
|
14
13
|
const hashDir = join(root, HASH_DIR);
|
|
15
14
|
const hashPath = join(root, HASH_SUBPATH);
|
|
16
|
-
|
|
15
|
+
const wranglerDir = join(root, HASH_DIR, ".wrangler");
|
|
16
|
+
if (!existsSync(hashDir))
|
|
17
|
+
mkdirSync(hashDir, { recursive: true });
|
|
18
|
+
server.watcher.add(hashDir);
|
|
17
19
|
server.watcher.on("change", (file) => {
|
|
18
|
-
if (
|
|
20
|
+
if (file.startsWith(wranglerDir) && file.endsWith(".sqlite")) {
|
|
21
|
+
try {
|
|
22
|
+
const hash = createHash("sha256").update(readFileSync(file)).digest("hex");
|
|
23
|
+
writeFileSync(hashPath, hash);
|
|
24
|
+
} catch {}
|
|
19
25
|
return;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
writeFileSync(hashPath, hash);
|
|
25
|
-
} catch {}
|
|
26
|
+
}
|
|
27
|
+
if (file === hashPath) {
|
|
28
|
+
server.ws.send({ type: "full-reload" });
|
|
29
|
+
}
|
|
26
30
|
});
|
|
27
|
-
server.watcher.add(hashPath);
|
|
28
|
-
},
|
|
29
|
-
handleHotUpdate({ file, server }) {
|
|
30
|
-
if (file.endsWith(HASH_FILENAME) && file.includes(HASH_DIR)) {
|
|
31
|
-
server.ws.send({ type: "full-reload" });
|
|
32
|
-
return [];
|
|
33
|
-
}
|
|
34
31
|
},
|
|
35
32
|
config() {
|
|
36
33
|
return {
|
package/src/vite.ts
CHANGED
|
@@ -15,18 +15,6 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
|
15
15
|
import { join } from 'node:path';
|
|
16
16
|
import type { Plugin } from 'vite';
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
* Watches the wrangler local D1 SQLite file and triggers a full browser reload
|
|
20
|
-
* when content actually changes. Rather than watching the binary SQLite directly
|
|
21
|
-
* (which churns 3-4× per operation due to WAL writes), it writes a SHA-256 hash
|
|
22
|
-
* of the DB to `.koguma/dbhash` and watches that text file as the reload trigger.
|
|
23
|
-
*
|
|
24
|
-
* Also suppresses Vite HMR for the `content/` directory, since those edits sync
|
|
25
|
-
* through koguma's own file watcher → D1 → API, not through the Vite module graph.
|
|
26
|
-
*
|
|
27
|
-
* Pair with the `server.proxy` pointing `/api` to `http://localhost:8787` so the
|
|
28
|
-
* browser refetches fresh content on each reload.
|
|
29
|
-
*/
|
|
30
18
|
export interface KogumaHMROptions {
|
|
31
19
|
/**
|
|
32
20
|
* Path to the .koguma directory, relative to the Vite project root.
|
|
@@ -36,13 +24,18 @@ export interface KogumaHMROptions {
|
|
|
36
24
|
kogumaDir?: string;
|
|
37
25
|
}
|
|
38
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Watches the wrangler local D1 SQLite file and triggers a full browser reload
|
|
29
|
+
* when content changes. Uses a SHA-256 hash file in .koguma/dbhash to debounce
|
|
30
|
+
* the multiple WAL writes that SQLite generates per D1 operation.
|
|
31
|
+
*
|
|
32
|
+
* Also suppresses Vite HMR for content/ since those changes sync through
|
|
33
|
+
* koguma's own pipeline → D1 → API, not through the Vite module graph.
|
|
34
|
+
*/
|
|
39
35
|
export function kogumaHMR(options: KogumaHMROptions = {}): Plugin {
|
|
40
|
-
const HASH_FILENAME = 'dbhash';
|
|
41
36
|
const HASH_DIR = options.kogumaDir ?? '.koguma';
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
// Glob passed to chokidar — must NOT go through path.resolve or the ** breaks
|
|
45
|
-
const SQLITE_GLOB = `**/${HASH_DIR}/.wrangler/state/v3/d1/**/*.sqlite`;
|
|
37
|
+
const HASH_FILE = 'dbhash';
|
|
38
|
+
const HASH_SUBPATH = `${HASH_DIR}/${HASH_FILE}`;
|
|
46
39
|
|
|
47
40
|
return {
|
|
48
41
|
name: 'koguma-hmr',
|
|
@@ -51,38 +44,37 @@ export function kogumaHMR(options: KogumaHMROptions = {}): Plugin {
|
|
|
51
44
|
const root = server.config.root;
|
|
52
45
|
const hashDir = join(root, HASH_DIR);
|
|
53
46
|
const hashPath = join(root, HASH_SUBPATH);
|
|
47
|
+
const wranglerDir = join(root, HASH_DIR, '.wrangler');
|
|
48
|
+
|
|
49
|
+
// Ensure .koguma exists so chokidar can watch it
|
|
50
|
+
if (!existsSync(hashDir)) mkdirSync(hashDir, { recursive: true });
|
|
54
51
|
|
|
55
|
-
//
|
|
56
|
-
|
|
52
|
+
// Watch .koguma/ directory — covers both the SQLite files inside
|
|
53
|
+
// .wrangler/ and the dbhash file we write ourselves.
|
|
54
|
+
server.watcher.add(hashDir);
|
|
57
55
|
|
|
58
56
|
server.watcher.on('change', (file: string) => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
// SQLite changed → compute hash and write dbhash file.
|
|
58
|
+
// The next change event for dbhash will trigger the reload.
|
|
59
|
+
if (file.startsWith(wranglerDir) && file.endsWith('.sqlite')) {
|
|
60
|
+
try {
|
|
61
|
+
const hash = createHash('sha256')
|
|
62
|
+
.update(readFileSync(file))
|
|
63
|
+
.digest('hex');
|
|
64
|
+
writeFileSync(hashPath, hash);
|
|
65
|
+
} catch {
|
|
66
|
+
// SQLite may be locked mid-write — next write will succeed
|
|
67
|
+
}
|
|
63
68
|
return;
|
|
64
|
-
try {
|
|
65
|
-
const hash = createHash('sha256')
|
|
66
|
-
.update(readFileSync(file))
|
|
67
|
-
.digest('hex');
|
|
68
|
-
if (!existsSync(hashDir)) mkdirSync(hashDir, { recursive: true });
|
|
69
|
-
writeFileSync(hashPath, hash);
|
|
70
|
-
} catch {
|
|
71
|
-
// SQLite may be locked mid-write — the next write will succeed
|
|
72
69
|
}
|
|
73
|
-
});
|
|
74
70
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (file.endsWith(HASH_FILENAME) && file.includes(HASH_DIR)) {
|
|
83
|
-
server.ws.send({ type: 'full-reload' });
|
|
84
|
-
return [];
|
|
85
|
-
}
|
|
71
|
+
// dbhash changed → new content is in D1 → reload the page.
|
|
72
|
+
// We send directly from here rather than via handleHotUpdate because
|
|
73
|
+
// handleHotUpdate only fires for files in Vite's module graph.
|
|
74
|
+
if (file === hashPath) {
|
|
75
|
+
server.ws.send({ type: 'full-reload' });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
86
78
|
},
|
|
87
79
|
|
|
88
80
|
config() {
|