fluxion-ts 0.5.1 → 0.6.1
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 +46 -1
- package/dist/index.cjs +97 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.mjs +97 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
Fluxion is a filesystem-routing dynamic server for Node.js.
|
|
14
14
|
|
|
15
|
-
- Route files from a dynamic directory
|
|
15
|
+
- Route files from a dynamic directory by chokidar or native `fs.watch`
|
|
16
16
|
- Load API handlers by extension, default: `.ts`
|
|
17
17
|
- Serve other files as static resources
|
|
18
18
|
- Run the business server in worker processes
|
|
@@ -283,6 +283,7 @@ interface FluxionOptions {
|
|
|
283
283
|
port: number;
|
|
284
284
|
reloadDelay?: number;
|
|
285
285
|
metaPort?: number;
|
|
286
|
+
nativeWatcher?: boolean;
|
|
286
287
|
injections?: InjectionConfig[];
|
|
287
288
|
moduleDir?: string;
|
|
288
289
|
workerOptions?: Partial<WorkerOptions>;
|
|
@@ -318,6 +319,28 @@ Primary meta API port. Defaults to `port + 1` and must be different from `port`.
|
|
|
318
319
|
|
|
319
320
|
Debounce delay for file re-registration. Defaults to `300` and must be at least `50`.
|
|
320
321
|
|
|
322
|
+
### `nativeWatcher`
|
|
323
|
+
|
|
324
|
+
Use native file watcher (`fs.watch`) instead of chokidar. Defaults to `false`.
|
|
325
|
+
|
|
326
|
+
When set to `true`, Fluxion uses Node.js built-in `fs.watch()` for file watching. When `false` (default), it uses `chokidar` for better cross-platform compatibility.
|
|
327
|
+
|
|
328
|
+
**Trade-offs:**
|
|
329
|
+
|
|
330
|
+
- `chokidar` (default): Better cross-platform support, more stable, handles edge cases
|
|
331
|
+
- `fs.watch`: Native implementation, lighter weight, but may have platform-specific quirks
|
|
332
|
+
|
|
333
|
+
Example:
|
|
334
|
+
|
|
335
|
+
```ts
|
|
336
|
+
fluxion({
|
|
337
|
+
dir: './dynamicDirectory',
|
|
338
|
+
host: '127.0.0.1',
|
|
339
|
+
port: 3000,
|
|
340
|
+
nativeWatcher: true, // use native fs.watch instead of chokidar
|
|
341
|
+
});
|
|
342
|
+
```
|
|
343
|
+
|
|
321
344
|
### `apiExts`
|
|
322
345
|
|
|
323
346
|
Extensions registered as API handlers. Defaults to:
|
|
@@ -428,6 +451,28 @@ Primary meta API port. Defaults to `port + 1` and must be different from `port`.
|
|
|
428
451
|
|
|
429
452
|
Debounce delay for file re-registration. Defaults to `300` and must be at least `50`.
|
|
430
453
|
|
|
454
|
+
### `nativeWatcher`
|
|
455
|
+
|
|
456
|
+
Use native file watcher (`fs.watch`) instead of chokidar. Defaults to `false`.
|
|
457
|
+
|
|
458
|
+
When set to `true`, Fluxion uses Node.js built-in `fs.watch()` for file watching. When `false` (default), it uses `chokidar` for better cross-platform compatibility.
|
|
459
|
+
|
|
460
|
+
**Trade-offs:**
|
|
461
|
+
|
|
462
|
+
- `chokidar` (default): Better cross-platform support, more stable, handles edge cases
|
|
463
|
+
- `fs.watch`: Native implementation, lighter weight, but may have platform-specific quirks
|
|
464
|
+
|
|
465
|
+
Example:
|
|
466
|
+
|
|
467
|
+
```ts
|
|
468
|
+
fluxion({
|
|
469
|
+
dir: './dynamicDirectory',
|
|
470
|
+
host: '127.0.0.1',
|
|
471
|
+
port: 3000,
|
|
472
|
+
nativeWatcher: true, // use native fs.watch instead of chokidar
|
|
473
|
+
});
|
|
474
|
+
```
|
|
475
|
+
|
|
431
476
|
### `apiExts`
|
|
432
477
|
|
|
433
478
|
Extensions registered as API handlers. Defaults to:
|
package/dist/index.cjs
CHANGED
|
@@ -355,7 +355,7 @@ function normalizeOptions(options) {
|
|
|
355
355
|
'**/.nyc_output/**',
|
|
356
356
|
'**/*.tmp',
|
|
357
357
|
'**/*.temp',
|
|
358
|
-
], https, } = options;
|
|
358
|
+
], https, nativeWatcher = false, } = options;
|
|
359
359
|
const logger = options.logger ?? 'one-line';
|
|
360
360
|
expectLoggerOption(logger);
|
|
361
361
|
expect.isString(dir, 'FluxionOptions.dir must be a string');
|
|
@@ -397,6 +397,7 @@ function normalizeOptions(options) {
|
|
|
397
397
|
include,
|
|
398
398
|
apiInclude,
|
|
399
399
|
exclude,
|
|
400
|
+
nativeWatcher,
|
|
400
401
|
https: normalizeHttpsOptions(https, moduleDir),
|
|
401
402
|
};
|
|
402
403
|
}
|
|
@@ -2854,6 +2855,99 @@ class FluxionWatcher {
|
|
|
2854
2855
|
}
|
|
2855
2856
|
}
|
|
2856
2857
|
|
|
2858
|
+
class FluxionNativeWatcher {
|
|
2859
|
+
constructor(cx) {
|
|
2860
|
+
this.timer = null;
|
|
2861
|
+
this.watcher = null;
|
|
2862
|
+
this.filesChanged = new Set();
|
|
2863
|
+
this.cx = cx;
|
|
2864
|
+
}
|
|
2865
|
+
/**
|
|
2866
|
+
* Recursively register all files in the options directory.
|
|
2867
|
+
*/
|
|
2868
|
+
init() {
|
|
2869
|
+
const dirPath = path$1.isAbsolute(this.cx.options.dir)
|
|
2870
|
+
? this.cx.options.dir
|
|
2871
|
+
: path$1.join(process.cwd(), this.cx.options.dir);
|
|
2872
|
+
const registerRecursive = (dir, relativePath) => {
|
|
2873
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
2874
|
+
for (const entry of entries) {
|
|
2875
|
+
const entryPath = path$1.join(dir, entry.name);
|
|
2876
|
+
const entryRelativePath = path$1.join(relativePath, entry.name);
|
|
2877
|
+
if (entry.isDirectory()) {
|
|
2878
|
+
registerRecursive(entryPath, entryRelativePath);
|
|
2879
|
+
}
|
|
2880
|
+
else if (entry.isFile()) {
|
|
2881
|
+
try {
|
|
2882
|
+
this.cx.router.register(entryRelativePath);
|
|
2883
|
+
}
|
|
2884
|
+
catch (err) {
|
|
2885
|
+
this.cx.logger.error(`Error registering [${entryRelativePath}]: ${err.message}`);
|
|
2886
|
+
}
|
|
2887
|
+
}
|
|
2888
|
+
}
|
|
2889
|
+
};
|
|
2890
|
+
if (fs.existsSync(dirPath)) {
|
|
2891
|
+
registerRecursive(dirPath, '');
|
|
2892
|
+
this.cx.logger.info(`Initial registration complete for directory: ${this.cx.options.dir}`);
|
|
2893
|
+
}
|
|
2894
|
+
else {
|
|
2895
|
+
this.cx.logger.warn(`Directory does not exist: ${this.cx.options.dir}`);
|
|
2896
|
+
}
|
|
2897
|
+
return this;
|
|
2898
|
+
}
|
|
2899
|
+
/**
|
|
2900
|
+
* Since all actions are mapped to `rename` and `change` (WatchEventType).
|
|
2901
|
+
*
|
|
2902
|
+
* We could only record every file and reload them all.
|
|
2903
|
+
*/
|
|
2904
|
+
start() {
|
|
2905
|
+
this.init();
|
|
2906
|
+
this.watcher = fs
|
|
2907
|
+
.watch(this.cx.options.dir, { recursive: true }, (_eventType, filename) => {
|
|
2908
|
+
if (!filename) {
|
|
2909
|
+
return;
|
|
2910
|
+
}
|
|
2911
|
+
this.filesChanged.add(filename);
|
|
2912
|
+
if (!this.timer) {
|
|
2913
|
+
this.timer = setTimeout(() => {
|
|
2914
|
+
this.filesChanged.forEach((p, _, s) => {
|
|
2915
|
+
try {
|
|
2916
|
+
this.cx.router.register(p);
|
|
2917
|
+
}
|
|
2918
|
+
catch (err) {
|
|
2919
|
+
this.cx.logger.error(`Error refreshing handlers: ${err.message}`);
|
|
2920
|
+
}
|
|
2921
|
+
finally {
|
|
2922
|
+
s.delete(p);
|
|
2923
|
+
}
|
|
2924
|
+
});
|
|
2925
|
+
this.timer = null;
|
|
2926
|
+
}, this.cx.options.reloadDelay);
|
|
2927
|
+
}
|
|
2928
|
+
})
|
|
2929
|
+
.on('error', (err) => {
|
|
2930
|
+
this.cx.logger.error(`Watcher error: ${err.message}`);
|
|
2931
|
+
this.cx.logger.error(`Restarting watcher...`);
|
|
2932
|
+
this.stop().start();
|
|
2933
|
+
});
|
|
2934
|
+
this.cx.logger.info(`Watcher started on directory: ${this.cx.options.dir}`);
|
|
2935
|
+
return this;
|
|
2936
|
+
}
|
|
2937
|
+
stop() {
|
|
2938
|
+
if (this.watcher) {
|
|
2939
|
+
this.watcher.close();
|
|
2940
|
+
this.watcher = null;
|
|
2941
|
+
}
|
|
2942
|
+
if (this.timer) {
|
|
2943
|
+
clearTimeout(this.timer);
|
|
2944
|
+
this.timer = null;
|
|
2945
|
+
}
|
|
2946
|
+
this.filesChanged.clear();
|
|
2947
|
+
return this;
|
|
2948
|
+
}
|
|
2949
|
+
}
|
|
2950
|
+
|
|
2857
2951
|
const balanced = (a, b, str) => {
|
|
2858
2952
|
const ma = a instanceof RegExp ? maybeMatch(a, str) : a;
|
|
2859
2953
|
const mb = b instanceof RegExp ? maybeMatch(b, str) : b;
|
|
@@ -5378,7 +5472,8 @@ async function fluxion(options) {
|
|
|
5378
5472
|
// Replace logger with worker logger that prefixes PID
|
|
5379
5473
|
context.logger = createWorkerLogger(context.logger, process.pid);
|
|
5380
5474
|
// Only worker creates the watcher
|
|
5381
|
-
context.
|
|
5475
|
+
const Watcher = context.options.nativeWatcher ? FluxionNativeWatcher : FluxionWatcher;
|
|
5476
|
+
context.watcher = new Watcher(context).start();
|
|
5382
5477
|
initWorker(context);
|
|
5383
5478
|
}
|
|
5384
5479
|
}
|