socket-function 0.125.0 → 0.126.0

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.
@@ -5,10 +5,12 @@ module.allowclient = true;
5
5
  import { SocketFunction } from "../SocketFunction";
6
6
  import { cache, lazy } from "../src/caching";
7
7
  import * as fs from "fs";
8
+ import crypto from "crypto";
8
9
  import debugbreak from "debugbreak";
9
10
  import { isNode } from "../src/misc";
10
11
  import { magenta, red } from "../src/formatting/logColors";
11
12
  import { formatTime } from "../src/formatting/format";
13
+ import { batchFunction } from "../src/batching";
12
14
 
13
15
  /** Enables some hot reload functionality.
14
16
  * - Triggers a refresh clientside
@@ -46,6 +48,8 @@ declare global {
46
48
  * - Also useful if you want files to hotreload clientside, but not serverside.
47
49
  */
48
50
  noserverhotreload?: boolean;
51
+
52
+ watchAdditionalFiles?: string[];
49
53
  }
50
54
  }
51
55
  var isHotReloading: (() => boolean) | undefined;
@@ -75,9 +79,41 @@ const hotReloadModule = cache((module: NodeJS.Module) => {
75
79
  interval = 10;
76
80
  fast = true;
77
81
  }
78
- fs.watchFile(module.filename, { persistent: false, interval }, (curr, prev) => {
79
- if (curr.mtime.getTime() === prev.mtime.getTime()) return;
80
- console.log(`Hot reloading due to change: ${module.filename}`);
82
+
83
+ let lastHashes = new Map<string, string>();
84
+ function getHash(path: string) {
85
+ try {
86
+ let contents = fs.readFileSync(path, "utf8");
87
+ return crypto.createHash("sha256").update(contents).digest("hex");
88
+ } catch {
89
+ return "";
90
+ }
91
+ }
92
+
93
+ watchFile(module.filename);
94
+ for (let path of module.watchAdditionalFiles || []) {
95
+ watchFile(path);
96
+ }
97
+
98
+ function watchFile(path: string) {
99
+ lastHashes.set(path, getHash(path));
100
+ fs.watchFile(path, { persistent: false, interval }, (curr, prev) => {
101
+ let newHash = getHash(path);
102
+ if (newHash === lastHashes.get(path)) return;
103
+ lastHashes.set(path, newHash);
104
+ if (path === module.filename) {
105
+ console.log(`Hot reloading ${module.filename} due to change`);
106
+ } else {
107
+ console.log(`Hot reloading ${module.filename} due to change in ${path}`);
108
+ }
109
+ doHotReload(curr.mtimeMs);
110
+ });
111
+ }
112
+
113
+
114
+
115
+ // IMPORTANT! changeTime is for benchmarking how long we took to hotreload (and nothing else)
116
+ function doHotReload(changeTime: number) {
81
117
  module.updateContents?.();
82
118
  if (isNode() && !module.noserverhotreload) {
83
119
  if (
@@ -104,34 +140,44 @@ const hotReloadModule = cache((module: NodeJS.Module) => {
104
140
  callback([module]);
105
141
  }
106
142
  }
143
+ //module.sourceSHA256;
144
+ // crypto.createHash("sha256").update(contents).digest("hex")
107
145
  if (module.allowclient) {
108
146
  triggerClientSideReload({
109
147
  files: [module.filename],
110
- changeTime: curr.mtimeMs,
148
+ changeTime,
111
149
  fast,
112
150
  });
113
151
  }
114
- });
152
+ }
115
153
  });
116
154
  let reloadTriggering = false;
117
155
  let clientWatcherNodes = new Set<string>();
156
+ let pendingTriggerFiles = new Set<string>();
118
157
  function triggerClientSideReload(config: {
119
158
  files: string[];
120
159
  changeTime: number;
121
160
  fast?: boolean;
122
161
  }) {
162
+ for (let file of config.files) {
163
+ pendingTriggerFiles.add(file);
164
+ }
123
165
  if (reloadTriggering) return;
124
166
  reloadTriggering = true;
125
167
  setTimeout(async () => {
126
168
  reloadTriggering = false;
169
+ let files = Array.from(pendingTriggerFiles);
170
+ pendingTriggerFiles.clear();
127
171
  for (let clientNodeId of clientWatcherNodes) {
128
- console.log(`Notifying client of hot reload: ${clientNodeId}`);
129
- HotReloadController.nodes[clientNodeId].fileUpdated(config.files, config.changeTime).catch(() => {
172
+ console.log(`Notifying client of hot reload: ${clientNodeId}`, files);
173
+ HotReloadController.nodes[clientNodeId].fileUpdated(files, config.changeTime).catch(() => {
130
174
  console.log(`Removing erroring client: ${clientNodeId}`);
131
175
  clientWatcherNodes.delete(clientNodeId);
132
176
  });
133
177
  }
134
- }, config.fast ? 10 : 300);
178
+ // We need to wait, otherwise batched updates fail, WHICH, can result in updates while reloading,
179
+ // which causes missed updates.
180
+ }, config.fast ? 50 : 300);
135
181
  }
136
182
 
137
183
  class HotReloadControllerBase {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "socket-function",
3
- "version": "0.125.0",
3
+ "version": "0.126.0",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "dependencies": {