-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathhotfs.ts
More file actions
124 lines (104 loc) · 2.43 KB
/
hotfs.ts
File metadata and controls
124 lines (104 loc) · 2.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import { join, move, signal, ensureSymlink } from "./deps.js";
let hotId = 0;
const HOT_FS_DEBUG = true;
const debounce = function (handler: any, timeout: number) {
let timeoutId: number;
return function () {
if (timeoutId != null) clearTimeout(timeoutId);
timeoutId = setTimeout(handler, timeout);
};
};
export class HotFs {
#dir: string;
#hotPrefix: string;
#onReload: Function;
#hotDir = "";
#debounce: number;
constructor({
dir,
onReload,
hotPrefix,
debounce = 500,
}: {
dir: string;
onReload: Function;
hotPrefix: string;
debounce?: number;
}) {
this.#hotPrefix = hotPrefix;
this.#dir = dir;
this.#debounce = debounce;
this.#onReload = onReload;
}
async init() {
await this._initFs();
this._initCleanup();
}
_initCleanup() {
const stopSignal = signal(
Deno.Signal.SIGINT,
Deno.Signal.SIGQUIT,
Deno.Signal.SIGTERM,
);
setTimeout(async () => {
for await (const _ of stopSignal) {
console.log(`HotFs "${this.#hotDir}" cleanup`);
await Deno.remove(this.#hotDir, { recursive: true });
Deno.exit();
}
}, 0);
}
async _initFs() {
this.#hotDir = this._nextHotDir();
await ensureSymlink(this.#dir, this.#hotDir);
}
_nextHotDir() {
const newHotId = hotId++;
const hotDir = `.${this.#hotPrefix}${newHotId}`;
const abs = join(Deno.cwd(), hotDir);
return abs;
}
async initWatch() {
const onFsChange = debounce(this._onFsChange, this.#debounce);
const watcher = Deno.watchFs([
this.#dir,
]);
for await (const event of watcher) {
onFsChange();
}
}
#reloading: Promise<any> | false = false;
#nextReload = false;
_onFsChange = async () => {
if (this.#nextReload) {
return;
}
let nextReload = false;
if (this.#reloading) {
this.#nextReload = true;
nextReload = true;
await this.#reloading;
}
this.#reloading = this._reload();
await this.#reloading;
this.#reloading = false;
if (nextReload) {
this.#nextReload = false;
}
};
async _reload() {
await this._invalidate();
await this.#onReload();
}
async _invalidate() {
if (HOT_FS_DEBUG) {
console.log(`HotFs invalidated`);
}
const nextHotDir = this._nextHotDir();
await move(this.#hotDir, nextHotDir);
this.#hotDir = nextHotDir;
}
getHotDir() {
return this.#hotDir;
}
}