srv-it 0.3.0 → 0.4.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.
- package/README.md +2 -0
- package/package.json +1 -1
- package/src/server.js +47 -2
package/README.md
CHANGED
|
@@ -97,3 +97,5 @@ Highlights:
|
|
|
97
97
|
- HTML pages get an auto-injected websocket client for live reload.
|
|
98
98
|
- CSS changes refresh styles without full page reload unless `--no-css-inject` is enabled.
|
|
99
99
|
- If a folder has `index.html`, that file is served; otherwise a styled directory listing is shown.
|
|
100
|
+
- Watch mode always ignores `.git` and `node_modules`, and also skips common home cache/config paths (`~/.cache`, `~/.local/share`).
|
|
101
|
+
- If the OS watcher limit is reached (`ENOSPC`), srv-it keeps serving files and disables live reload instead of crashing.
|
package/package.json
CHANGED
package/src/server.js
CHANGED
|
@@ -11,6 +11,21 @@ const os = require('node:os');
|
|
|
11
11
|
const chalk = require('chalk');
|
|
12
12
|
const { WebSocketServer } = require('ws');
|
|
13
13
|
|
|
14
|
+
const BASE_WATCH_IGNORES = ['**/.git/**', '**/node_modules/**'];
|
|
15
|
+
|
|
16
|
+
function toGlobPath(value) {
|
|
17
|
+
return value.replace(/\\/g, '/');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getDefaultWatchIgnores() {
|
|
21
|
+
const home = toGlobPath(os.homedir());
|
|
22
|
+
return [
|
|
23
|
+
...BASE_WATCH_IGNORES,
|
|
24
|
+
`${home}/.cache/**`,
|
|
25
|
+
`${home}/.local/share/**`,
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
|
|
14
29
|
const LIVE_RELOAD_SNIPPET = `\n<script>\n(function(){\n if(!('WebSocket' in window)) return;\n function refreshCSS(){\n var links=[].slice.call(document.querySelectorAll('link[rel="stylesheet"],link:not([rel])'));\n links.forEach(function(link){\n var href=link.getAttribute('href');\n if(!href) return;\n var u=href.replace(/([?&])_srv=\\d+/,'').replace(/[?&]$/,'');\n var join=u.indexOf('?')>-1?'&':'?';\n link.setAttribute('href',u+join+'_srv='+Date.now());\n });\n }\n var proto=location.protocol==='https:'?'wss':'ws';\n var socket=new WebSocket(proto+'://'+location.host+'/__srv_ws');\n socket.onmessage=function(event){\n if(event.data==='refreshcss') refreshCSS();\n if(event.data==='reload') location.reload();\n };\n})();\n</script>\n`;
|
|
15
30
|
|
|
16
31
|
const STYLE_PRESETS = {
|
|
@@ -428,12 +443,29 @@ async function createSrvServer(options) {
|
|
|
428
443
|
});
|
|
429
444
|
|
|
430
445
|
const watchPaths = [root, ...(options.watch || []).map((x) => path.resolve(x))];
|
|
446
|
+
const ignore = [...getDefaultWatchIgnores(), ...((options.ignore || []).filter(Boolean))];
|
|
431
447
|
const watcher = chokidar.watch(watchPaths, {
|
|
432
448
|
ignoreInitial: true,
|
|
433
|
-
ignored:
|
|
449
|
+
ignored: Array.from(new Set(ignore)),
|
|
450
|
+
ignorePermissionErrors: true,
|
|
434
451
|
});
|
|
435
452
|
|
|
453
|
+
let liveReloadEnabled = true;
|
|
454
|
+
let watcherClosed = false;
|
|
455
|
+
|
|
456
|
+
const closeWatcher = async () => {
|
|
457
|
+
if (watcherClosed) {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
watcherClosed = true;
|
|
461
|
+
await watcher.close();
|
|
462
|
+
};
|
|
463
|
+
|
|
436
464
|
const sendReload = (changePath) => {
|
|
465
|
+
if (!liveReloadEnabled) {
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
|
|
437
469
|
const isCss = path.extname(changePath).toLowerCase() === '.css' && !options.noCssInject;
|
|
438
470
|
const message = isCss ? 'refreshcss' : 'reload';
|
|
439
471
|
for (const client of clients) {
|
|
@@ -451,9 +483,22 @@ async function createSrvServer(options) {
|
|
|
451
483
|
watcher.on('unlink', sendReload);
|
|
452
484
|
watcher.on('addDir', sendReload);
|
|
453
485
|
watcher.on('unlinkDir', sendReload);
|
|
486
|
+
watcher.on('error', async (error) => {
|
|
487
|
+
if (error && error.code === 'ENOSPC') {
|
|
488
|
+
liveReloadEnabled = false;
|
|
489
|
+
await closeWatcher();
|
|
490
|
+
console.error('[srv] live reload disabled: file watcher limit reached (ENOSPC).');
|
|
491
|
+
console.error('[srv] use --ignore to exclude noisy paths, or raise inotify limits on Linux.');
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
if (options.logLevel >= 1) {
|
|
496
|
+
console.error(`[srv] watcher error: ${error.message}`);
|
|
497
|
+
}
|
|
498
|
+
});
|
|
454
499
|
|
|
455
500
|
const closeAll = async () => {
|
|
456
|
-
await
|
|
501
|
+
await closeWatcher();
|
|
457
502
|
wss.close();
|
|
458
503
|
await new Promise((resolve) => server.close(resolve));
|
|
459
504
|
};
|