@web-ts-toolkit/express-runtime 0.7.0 → 0.9.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 +44 -14
- package/cli.js +251 -15
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -80,12 +80,12 @@ startLocalServer(app, {
|
|
|
80
80
|
|
|
81
81
|
### CLI — dev (local server)
|
|
82
82
|
|
|
83
|
-
The `
|
|
83
|
+
The `wtt-express-runtime dev` command runs any module that
|
|
84
84
|
default-exports an Express app (or an async function returning one) as a local
|
|
85
85
|
dev server:
|
|
86
86
|
|
|
87
87
|
```sh
|
|
88
|
-
npx
|
|
88
|
+
npx wtt-express-runtime dev ./dist/app.js --port 3000 --host localhost
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
```ts
|
|
@@ -103,6 +103,29 @@ For TypeScript app modules, run the CLI through `tsx`:
|
|
|
103
103
|
npx tsx ./node_modules/@web-ts-toolkit/express-runtime/dist/cli.js dev ./src/app.ts
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
+
#### CLI — dev with env, require, and watch
|
|
107
|
+
|
|
108
|
+
`--env` loads `.env` files into `process.env` (existing vars are not
|
|
109
|
+
overridden). `--require` preloads modules (e.g. `tsconfig-paths/register` for
|
|
110
|
+
TS path aliases) before the app module is loaded. `--watch` forks a child
|
|
111
|
+
process running the server and restarts it on file changes:
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
npx tsx ./node_modules/@web-ts-toolkit/express-runtime/dist/cli.js dev ./src/app.ts \
|
|
115
|
+
--env .env \
|
|
116
|
+
--require tsconfig-paths/register \
|
|
117
|
+
--watch ./src,./shared \
|
|
118
|
+
--ext ts,json
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
> `--env` parses `KEY=VALUE` lines (supports `export` prefix, quoted values,
|
|
122
|
+
> `#` comments). For advanced dotenv features (multiline, variable expansion),
|
|
123
|
+
> use `--require dotenv/config` instead.
|
|
124
|
+
>
|
|
125
|
+
> `--watch` uses Node 20+'s `fs.watch` with `{ recursive: true }` and forks the
|
|
126
|
+
> same CLI as a child process. On file change, the child receives `SIGTERM`,
|
|
127
|
+
> waits for it to exit, and respawns after the debounce delay (`--delay`).
|
|
128
|
+
|
|
106
129
|
> The `dev` command evaluates arbitrary code from `<app-module>` in the current
|
|
107
130
|
> process and inherits its privileges. Init logic (e.g. DB connections) should
|
|
108
131
|
> be placed at the top level of your app module since `dev` does not expose an
|
|
@@ -115,13 +138,13 @@ with `createServerlessHandler`, then bundles it with `tsup` into a
|
|
|
115
138
|
deployment-ready file:
|
|
116
139
|
|
|
117
140
|
```sh
|
|
118
|
-
npx
|
|
141
|
+
npx wtt-express-runtime build ./src/app.ts --out-dir netlify/functions
|
|
119
142
|
```
|
|
120
143
|
|
|
121
144
|
With an optional init hook (DB connections, cache warmup, etc.):
|
|
122
145
|
|
|
123
146
|
```sh
|
|
124
|
-
npx
|
|
147
|
+
npx wtt-express-runtime build ./src/app.ts --init ./src/init.ts --out-dir netlify/functions
|
|
125
148
|
```
|
|
126
149
|
|
|
127
150
|
```ts
|
|
@@ -146,8 +169,8 @@ responses — letting you smoke-test the exact `build` output without a
|
|
|
146
169
|
serverless platform:
|
|
147
170
|
|
|
148
171
|
```sh
|
|
149
|
-
npx
|
|
150
|
-
npx
|
|
172
|
+
npx wtt-express-runtime build ./src/app.ts --out-dir dist
|
|
173
|
+
npx wtt-express-runtime start ./dist/handler.js --port 9000 --env .env
|
|
151
174
|
```
|
|
152
175
|
|
|
153
176
|
The handler module must export a `handler` function (named or default) that
|
|
@@ -272,7 +295,7 @@ interface Logger {
|
|
|
272
295
|
|
|
273
296
|
## CLI
|
|
274
297
|
|
|
275
|
-
### `
|
|
298
|
+
### `wtt-express-runtime <command> <app-module> [options]`
|
|
276
299
|
|
|
277
300
|
Omitting `<command>` defaults to `dev` for backward compatibility.
|
|
278
301
|
|
|
@@ -291,6 +314,11 @@ Omitting `<command>` defaults to `dev` for backward compatibility.
|
|
|
291
314
|
| `--host <hostname>` | Hostname to bind (default: `process.env.HOST` or `0.0.0.0`) |
|
|
292
315
|
| `--no-signals` | Disable `SIGINT` / `SIGTERM` handler registration |
|
|
293
316
|
| `--shutdown-timeout <ms>` | Max ms to wait for in-flight requests (default: `5000`) |
|
|
317
|
+
| `--require <module>` | Module(s) to preload before app load (repeatable; comma-separated values supported) |
|
|
318
|
+
| `--env <path>` | Env file(s) to load before app load (repeatable; existing env vars are not overridden) |
|
|
319
|
+
| `--watch <paths>` | Comma-separated paths to watch for restart (repeatable; forks a child process) |
|
|
320
|
+
| `--ext <extensions>` | Comma-separated extensions to watch (default: `ts,js,mjs,cjs,json`) |
|
|
321
|
+
| `--delay <ms>` | Debounce ms before restarting on change (default: `500`) |
|
|
294
322
|
|
|
295
323
|
#### build options
|
|
296
324
|
|
|
@@ -307,13 +335,15 @@ Omitting `<command>` defaults to `dev` for backward compatibility.
|
|
|
307
335
|
|
|
308
336
|
#### start options
|
|
309
337
|
|
|
310
|
-
| Option | Description
|
|
311
|
-
| ------------------------- |
|
|
312
|
-
| `<handler-module>` | JS/CJS module path exporting `handler` (named or default) — the output of `build`
|
|
313
|
-
| `--port <number>` | Port or named pipe (default: `process.env.PORT` or `8080`)
|
|
314
|
-
| `--host <hostname>` | Hostname to bind (default: `process.env.HOST` or `0.0.0.0`)
|
|
315
|
-
| `--no-signals` | Disable `SIGINT` / `SIGTERM` handler registration
|
|
316
|
-
| `--shutdown-timeout <ms>` | Max ms to wait for in-flight requests (default: `5000`)
|
|
338
|
+
| Option | Description |
|
|
339
|
+
| ------------------------- | ------------------------------------------------------------------------------------------ |
|
|
340
|
+
| `<handler-module>` | JS/CJS module path exporting `handler` (named or default) — the output of `build` |
|
|
341
|
+
| `--port <number>` | Port or named pipe (default: `process.env.PORT` or `8080`) |
|
|
342
|
+
| `--host <hostname>` | Hostname to bind (default: `process.env.HOST` or `0.0.0.0`) |
|
|
343
|
+
| `--no-signals` | Disable `SIGINT` / `SIGTERM` handler registration |
|
|
344
|
+
| `--shutdown-timeout <ms>` | Max ms to wait for in-flight requests (default: `5000`) |
|
|
345
|
+
| `--require <module>` | Module(s) to preload before handler load (repeatable; comma-separated values supported) |
|
|
346
|
+
| `--env <path>` | Env file(s) to load before handler load (repeatable; existing env vars are not overridden) |
|
|
317
347
|
|
|
318
348
|
#### global options
|
|
319
349
|
|
package/cli.js
CHANGED
|
@@ -27,6 +27,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
var import_node_url = require("url");
|
|
28
28
|
var import_node_path = require("path");
|
|
29
29
|
var import_node_fs = require("fs");
|
|
30
|
+
var import_node_module = require("module");
|
|
31
|
+
var import_node_child_process = require("child_process");
|
|
30
32
|
|
|
31
33
|
// src/index.ts
|
|
32
34
|
var import_node_http = __toESM(require("http"));
|
|
@@ -194,6 +196,7 @@ function startLocalServer(app, options = {}) {
|
|
|
194
196
|
}
|
|
195
197
|
|
|
196
198
|
// src/cli-utils.ts
|
|
199
|
+
var import_meta = {};
|
|
197
200
|
var CLI_VERSION = "0.0.0-PLACEHOLDER";
|
|
198
201
|
function readValue(argv, index, name) {
|
|
199
202
|
const value = argv[index + 1];
|
|
@@ -203,13 +206,13 @@ function readValue(argv, index, name) {
|
|
|
203
206
|
return value;
|
|
204
207
|
}
|
|
205
208
|
function printHelp() {
|
|
206
|
-
console.log(`
|
|
209
|
+
console.log(`wtt-express-runtime
|
|
207
210
|
|
|
208
211
|
Run an Express app locally, bundle it as a serverless handler, or run the bundle.
|
|
209
212
|
|
|
210
213
|
Usage:
|
|
211
|
-
|
|
212
|
-
|
|
214
|
+
wtt-express-runtime <command> <app-module> [options]
|
|
215
|
+
wtt-express-runtime <app-module> [options] (alias for dev)
|
|
213
216
|
|
|
214
217
|
Commands:
|
|
215
218
|
dev Run the Express app as a local dev server
|
|
@@ -221,6 +224,11 @@ Dev options:
|
|
|
221
224
|
--host <hostname> Hostname to bind (default: process.env.HOST or 0.0.0.0)
|
|
222
225
|
--no-signals Disable SIGINT/SIGTERM handler registration
|
|
223
226
|
--shutdown-timeout <ms> Max ms to wait for in-flight requests (default: 5000)
|
|
227
|
+
--require <module> Module(s) to preload before app load (repeatable)
|
|
228
|
+
--env <path> Env file(s) to load (repeatable; existing env vars are not overridden)
|
|
229
|
+
--watch <paths> Comma-separated paths to watch for restart (repeatable; dev only)
|
|
230
|
+
--ext <extensions> Comma-separated extensions to watch (default: ts,js,mjs,cjs,json)
|
|
231
|
+
--delay <ms> Debounce ms before restarting on change (default: 500)
|
|
224
232
|
|
|
225
233
|
Build options:
|
|
226
234
|
--init <path> Init hook module (default export, async function)
|
|
@@ -236,23 +244,31 @@ Start options:
|
|
|
236
244
|
--host <hostname> Hostname to bind (default: process.env.HOST or 0.0.0.0)
|
|
237
245
|
--no-signals Disable SIGINT/SIGTERM handler registration
|
|
238
246
|
--shutdown-timeout <ms> Max ms to wait for in-flight requests (default: 5000)
|
|
247
|
+
--require <module> Module(s) to preload before handler load (repeatable)
|
|
248
|
+
--env <path> Env file(s) to load (repeatable; existing env vars are not overridden)
|
|
239
249
|
|
|
240
250
|
Global options:
|
|
241
251
|
-V, --version Show version
|
|
242
252
|
-h, --help Show this help message
|
|
243
253
|
|
|
244
254
|
Examples:
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
255
|
+
wtt-express-runtime dev ./dist/app.js
|
|
256
|
+
wtt-express-runtime dev ./dist/app.js --port 3000 --host localhost
|
|
257
|
+
wtt-express-runtime dev ./src/app.ts --env .env --require tsconfig-paths/register --watch ./src,./shared
|
|
258
|
+
wtt-express-runtime build ./src/app.ts --out-dir netlify/functions
|
|
259
|
+
wtt-express-runtime build ./src/app.ts --init ./src/init.ts --format esm
|
|
260
|
+
wtt-express-runtime start ./netlify/functions/handler.js --port 9000 --env .env
|
|
261
|
+
wtt-express-runtime build ./src/app.ts && wtt-express-runtime start ./dist/handler.js
|
|
251
262
|
|
|
252
263
|
Notes:
|
|
253
264
|
- In dev mode, the CLI evaluates arbitrary code from <app-module> in the current process.
|
|
254
265
|
- TypeScript app modules in dev mode require a TS loader. Run via tsx:
|
|
255
266
|
npx tsx ./node_modules/@web-ts-toolkit/express-runtime/dist/cli.js dev ./src/app.ts
|
|
267
|
+
Or use --require with a TS-aware loader module.
|
|
268
|
+
- --env files are parsed as KEY=VALUE; existing process.env entries are never overridden.
|
|
269
|
+
For advanced dotenv features (multiline, expansion), --require dotenv/config instead.
|
|
270
|
+
- --watch forks a child process running the same CLI without --watch. On file change,
|
|
271
|
+
the child is killed (SIGTERM) and respawned after the debounce delay.
|
|
256
272
|
- In build mode, tsup is required: pnpm add -D tsup
|
|
257
273
|
- In start mode, the bundled handler file must be a JS/CJS module whose "handler"
|
|
258
274
|
export (or default export) is a function: (event, context) => Promise<result>.
|
|
@@ -268,8 +284,23 @@ function isHelp(arg) {
|
|
|
268
284
|
function isSubcommand(arg) {
|
|
269
285
|
return arg === "dev" || arg === "build" || arg === "start";
|
|
270
286
|
}
|
|
287
|
+
var DEFAULT_WATCH_EXTENSIONS = ["ts", "js", "mjs", "cjs", "json"];
|
|
288
|
+
var DEFAULT_WATCH_DELAY = 500;
|
|
289
|
+
function parseRepeatable(argv, index, arg, list) {
|
|
290
|
+
const value = readValue(argv, index, arg);
|
|
291
|
+
for (const part of value.split(",")) {
|
|
292
|
+
const trimmed = part.trim();
|
|
293
|
+
if (trimmed) list.push(trimmed);
|
|
294
|
+
}
|
|
295
|
+
return index + 1;
|
|
296
|
+
}
|
|
271
297
|
function parseDevArgs(argv) {
|
|
272
298
|
const options = {};
|
|
299
|
+
const requireModules = [];
|
|
300
|
+
const envFiles = [];
|
|
301
|
+
const watchPaths = [];
|
|
302
|
+
let watchExt;
|
|
303
|
+
let watchDelay;
|
|
273
304
|
let appPath;
|
|
274
305
|
for (let index = 0; index < argv.length; index += 1) {
|
|
275
306
|
const arg = argv[index];
|
|
@@ -314,6 +345,61 @@ function parseDevArgs(argv) {
|
|
|
314
345
|
options.shutdownTimeout = Number(arg.slice("--shutdown-timeout=".length));
|
|
315
346
|
continue;
|
|
316
347
|
}
|
|
348
|
+
if (arg === "--require") {
|
|
349
|
+
index = parseRepeatable(argv, index, arg, requireModules);
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
if (arg.startsWith("--require=")) {
|
|
353
|
+
for (const part of arg.slice("--require=".length).split(",")) {
|
|
354
|
+
const trimmed = part.trim();
|
|
355
|
+
if (trimmed) requireModules.push(trimmed);
|
|
356
|
+
}
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
if (arg === "--env") {
|
|
360
|
+
index = parseRepeatable(argv, index, arg, envFiles);
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
if (arg.startsWith("--env=")) {
|
|
364
|
+
for (const part of arg.slice("--env=".length).split(",")) {
|
|
365
|
+
const trimmed = part.trim();
|
|
366
|
+
if (trimmed) envFiles.push(trimmed);
|
|
367
|
+
}
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
if (arg === "--watch") {
|
|
371
|
+
index = parseRepeatable(argv, index, arg, watchPaths);
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
if (arg.startsWith("--watch=")) {
|
|
375
|
+
for (const part of arg.slice("--watch=".length).split(",")) {
|
|
376
|
+
const trimmed = part.trim();
|
|
377
|
+
if (trimmed) watchPaths.push(trimmed);
|
|
378
|
+
}
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
if (arg === "--ext") {
|
|
382
|
+
watchExt = [];
|
|
383
|
+
index = parseRepeatable(argv, index, arg, watchExt);
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
if (arg.startsWith("--ext=")) {
|
|
387
|
+
watchExt = [];
|
|
388
|
+
for (const part of arg.slice("--ext=".length).split(",")) {
|
|
389
|
+
const trimmed = part.trim();
|
|
390
|
+
if (trimmed) watchExt.push(trimmed);
|
|
391
|
+
}
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
if (arg === "--delay") {
|
|
395
|
+
watchDelay = Number(readValue(argv, index, arg));
|
|
396
|
+
index += 1;
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
if (arg.startsWith("--delay=")) {
|
|
400
|
+
watchDelay = Number(arg.slice("--delay=".length));
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
317
403
|
if (!arg.startsWith("--")) {
|
|
318
404
|
if (appPath) {
|
|
319
405
|
throw new Error(`Unexpected positional argument: ${arg}. App module already set to ${appPath}`);
|
|
@@ -327,11 +413,29 @@ function parseDevArgs(argv) {
|
|
|
327
413
|
printHelp();
|
|
328
414
|
throw new Error("Missing required argument: <app-module>");
|
|
329
415
|
}
|
|
330
|
-
return {
|
|
416
|
+
return {
|
|
417
|
+
appPath,
|
|
418
|
+
options,
|
|
419
|
+
require: requireModules,
|
|
420
|
+
env: envFiles,
|
|
421
|
+
watch: watchPaths,
|
|
422
|
+
watchExt: watchExt ?? DEFAULT_WATCH_EXTENSIONS,
|
|
423
|
+
watchDelay: watchDelay ?? DEFAULT_WATCH_DELAY
|
|
424
|
+
};
|
|
331
425
|
}
|
|
332
426
|
function parseStartArgs(argv) {
|
|
427
|
+
for (const arg of argv) {
|
|
428
|
+
if (arg === "--watch" || arg.startsWith("--watch=") || arg === "--ext" || arg.startsWith("--ext=") || arg === "--delay" || arg.startsWith("--delay=")) {
|
|
429
|
+
throw new Error(`--watch/--ext/--delay are not supported with the start subcommand`);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
333
432
|
const result = parseDevArgs(argv);
|
|
334
|
-
return {
|
|
433
|
+
return {
|
|
434
|
+
handlerPath: result.appPath,
|
|
435
|
+
options: result.options,
|
|
436
|
+
require: result.require,
|
|
437
|
+
env: result.env
|
|
438
|
+
};
|
|
335
439
|
}
|
|
336
440
|
function parseBuildArgs(argv) {
|
|
337
441
|
let appPath;
|
|
@@ -494,6 +598,124 @@ async function loadApp(appPath) {
|
|
|
494
598
|
}
|
|
495
599
|
return resolveExport(exported, appPath);
|
|
496
600
|
}
|
|
601
|
+
function parseEnvFile(content) {
|
|
602
|
+
const result = {};
|
|
603
|
+
for (const line of content.split("\n")) {
|
|
604
|
+
let trimmed = line.trim();
|
|
605
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
606
|
+
if (trimmed.startsWith("export ")) trimmed = trimmed.slice("export ".length).trim();
|
|
607
|
+
const eqIndex = trimmed.indexOf("=");
|
|
608
|
+
if (eqIndex === -1) continue;
|
|
609
|
+
const key = trimmed.slice(0, eqIndex).trim();
|
|
610
|
+
let value = trimmed.slice(eqIndex + 1).trim();
|
|
611
|
+
if (value.length >= 2) {
|
|
612
|
+
const first = value[0];
|
|
613
|
+
const last = value[value.length - 1];
|
|
614
|
+
if (first === '"' && last === '"' || first === "'" && last === "'") {
|
|
615
|
+
value = value.slice(1, -1);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
result[key] = value;
|
|
619
|
+
}
|
|
620
|
+
return result;
|
|
621
|
+
}
|
|
622
|
+
function loadEnvFiles(paths) {
|
|
623
|
+
for (const p of paths) {
|
|
624
|
+
const absPath = (0, import_node_path.resolve)(process.cwd(), p);
|
|
625
|
+
if (!(0, import_node_fs.existsSync)(absPath)) {
|
|
626
|
+
throw new Error(`Env file not found: ${p}`);
|
|
627
|
+
}
|
|
628
|
+
const content = (0, import_node_fs.readFileSync)(absPath, "utf8");
|
|
629
|
+
const parsed = parseEnvFile(content);
|
|
630
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
631
|
+
if (process.env[key] === void 0) {
|
|
632
|
+
process.env[key] = value;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
var moduleRequire = (0, import_node_module.createRequire)(
|
|
638
|
+
typeof import_meta !== "undefined" && import_meta.url || (0, import_node_path.resolve)(process.cwd(), "x").replace(/x$/, "")
|
|
639
|
+
);
|
|
640
|
+
async function preloadModules(modules) {
|
|
641
|
+
for (const mod of modules) {
|
|
642
|
+
moduleRequire(mod);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
function buildChildArgs(args) {
|
|
646
|
+
const result = ["dev", args.appPath];
|
|
647
|
+
if (args.options.port !== void 0) result.push("--port", String(args.options.port));
|
|
648
|
+
if (args.options.host !== void 0) result.push("--host", args.options.host);
|
|
649
|
+
if (args.options.signals === false) result.push("--no-signals");
|
|
650
|
+
if (args.options.shutdownTimeout !== void 0)
|
|
651
|
+
result.push("--shutdown-timeout", String(args.options.shutdownTimeout));
|
|
652
|
+
for (const r of args.require) result.push("--require", r);
|
|
653
|
+
for (const e of args.env) result.push("--env", e);
|
|
654
|
+
return result;
|
|
655
|
+
}
|
|
656
|
+
function runWithWatch(args) {
|
|
657
|
+
const cliPath = process.argv[1];
|
|
658
|
+
const childArgv = buildChildArgs(args);
|
|
659
|
+
let child = null;
|
|
660
|
+
let restartTimer = null;
|
|
661
|
+
let isShuttingDown = false;
|
|
662
|
+
const restartDelay = args.watchDelay;
|
|
663
|
+
const spawnChild = () => {
|
|
664
|
+
child = (0, import_node_child_process.fork)(cliPath, childArgv, { stdio: "inherit" });
|
|
665
|
+
child.on("exit", (code) => {
|
|
666
|
+
child = null;
|
|
667
|
+
if (!isShuttingDown && code !== null && code !== 0) {
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
};
|
|
671
|
+
const killChild = () => {
|
|
672
|
+
return new Promise((resolve) => {
|
|
673
|
+
if (!child || !child.pid) {
|
|
674
|
+
resolve();
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
child.once("exit", () => resolve());
|
|
678
|
+
child.kill("SIGTERM");
|
|
679
|
+
});
|
|
680
|
+
};
|
|
681
|
+
const restart = async () => {
|
|
682
|
+
await killChild();
|
|
683
|
+
spawnChild();
|
|
684
|
+
};
|
|
685
|
+
const debouncedRestart = () => {
|
|
686
|
+
if (restartTimer) clearTimeout(restartTimer);
|
|
687
|
+
restartTimer = setTimeout(() => {
|
|
688
|
+
restartTimer = null;
|
|
689
|
+
void restart();
|
|
690
|
+
}, restartDelay);
|
|
691
|
+
};
|
|
692
|
+
for (const watchPath of args.watch) {
|
|
693
|
+
const absPath = (0, import_node_path.resolve)(process.cwd(), watchPath);
|
|
694
|
+
if (!(0, import_node_fs.existsSync)(absPath)) {
|
|
695
|
+
throw new Error(`Watch path not found: ${watchPath}`);
|
|
696
|
+
}
|
|
697
|
+
(0, import_node_fs.watch)(absPath, { recursive: true }, (_eventType, filename) => {
|
|
698
|
+
if (!filename) return;
|
|
699
|
+
const ext = (0, import_node_path.extname)(filename).slice(1).toLowerCase();
|
|
700
|
+
if (args.watchExt.includes(ext)) {
|
|
701
|
+
debouncedRestart();
|
|
702
|
+
}
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
const shutdown = () => {
|
|
706
|
+
isShuttingDown = true;
|
|
707
|
+
if (restartTimer) clearTimeout(restartTimer);
|
|
708
|
+
if (child && child.pid) {
|
|
709
|
+
child.once("exit", () => process.exit(0));
|
|
710
|
+
child.kill("SIGTERM");
|
|
711
|
+
} else {
|
|
712
|
+
process.exit(0);
|
|
713
|
+
}
|
|
714
|
+
};
|
|
715
|
+
process.on("SIGINT", shutdown);
|
|
716
|
+
process.on("SIGTERM", shutdown);
|
|
717
|
+
spawnChild();
|
|
718
|
+
}
|
|
497
719
|
var TEMP_ENTRY_FILENAME = ".express-runtime-build-entry.ts";
|
|
498
720
|
function generateServerlessEntry(appPath, initPath) {
|
|
499
721
|
const absAppPath = (0, import_node_path.resolve)(process.cwd(), appPath);
|
|
@@ -619,12 +841,26 @@ async function main() {
|
|
|
619
841
|
return;
|
|
620
842
|
}
|
|
621
843
|
if (parsedArgs.subcommand === "dev") {
|
|
622
|
-
const
|
|
623
|
-
|
|
844
|
+
const { dev } = parsedArgs;
|
|
845
|
+
if (dev.watch.length > 0) {
|
|
846
|
+
runWithWatch(dev);
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
if (dev.env.length > 0) {
|
|
850
|
+
loadEnvFiles(dev.env);
|
|
851
|
+
}
|
|
852
|
+
await preloadModules(dev.require);
|
|
853
|
+
const app = await loadApp(dev.appPath);
|
|
854
|
+
startLocalServer(app, { ...dev.options, exitAfterShutdown: true });
|
|
624
855
|
} else if (parsedArgs.subcommand === "start") {
|
|
625
|
-
const
|
|
856
|
+
const { start } = parsedArgs;
|
|
857
|
+
if (start.env.length > 0) {
|
|
858
|
+
loadEnvFiles(start.env);
|
|
859
|
+
}
|
|
860
|
+
await preloadModules(start.require);
|
|
861
|
+
const handler = await loadHandler(start.handlerPath);
|
|
626
862
|
const app = createServerlessAdapterApp(handler);
|
|
627
|
-
startLocalServer(app, { ...
|
|
863
|
+
startLocalServer(app, { ...start.options, exitAfterShutdown: true });
|
|
628
864
|
} else {
|
|
629
865
|
await buildServerless(parsedArgs.build);
|
|
630
866
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@web-ts-toolkit/express-runtime",
|
|
3
3
|
"description": "Express app factory plus serverless handler and local dev server helpers",
|
|
4
4
|
"homepage": "https://web-ts-toolkit.pages.dev/docs/packages/express-runtime",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.9.0",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"keywords": [
|
|
8
8
|
"express",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"module": "./index.mjs",
|
|
17
17
|
"types": "./index.d.ts",
|
|
18
18
|
"bin": {
|
|
19
|
-
"
|
|
19
|
+
"wtt-express-runtime": "./cli.js"
|
|
20
20
|
},
|
|
21
21
|
"exports": {
|
|
22
22
|
".": {
|