@t8/serve 0.1.39 → 0.2.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 CHANGED
@@ -9,28 +9,29 @@ Use cases:
9
9
 
10
10
  ## CLI
11
11
 
12
- ```sh
13
- npx @t8/serve [url|port] [*] [app_dir] [...assets_dirs] [-b [bundle_input_path] [bundle_output_path] [bundle_output_dir]] [--watch] [--minify]
14
- # * = SPA mode: serve all unmatched paths as "/"
15
12
  ```
13
+ npx @t8/serve <app_dir> [...optional flags]
16
14
 
17
- Examples:
15
+ Flag Usage notes
18
16
 
19
- ```sh
20
- npx @t8/serve 3000 app
21
- # - serve files from './app' at 'localhost:3000'
17
+ --bundle, -b -b [input_path [[output_path] [output_dir]]]
18
+ Defaults:
19
+ - input_path: "index.ts" (relative to <app_dir>)
20
+ - ouput_path: "index.js" (relative to <app_dir>/<output_dir>)
21
+ - output_dir: "dist"
22
+
23
+ --url, -u -u [<host>:]<port>
24
+ Default: "localhost:3000"
25
+
26
+ --spa, -s To switch to the SPA mode by handling all unmatched paths as "/".
22
27
 
23
- npx @t8/serve 3000 * app -b
24
- # - bundle './app/index.ts' to './app/dist/index.js' [-b]
25
- # - serve files from './app' at 'localhost:3000' in the SPA mode [*] (handling all unmatched paths as "/")
28
+ --dirs --dirs assets public
29
+ To serve files from the listed subdirectories of <app_dir>.
30
+ By default, files are served from <app_dir>.
26
31
 
27
- npx @t8/serve 3000 * app -b src/index.ts
28
- # - bundle './app/src/index.ts' to './app/dist/index.js'
29
- # - serve files from './app' at 'localhost:3000' in the SPA mode
32
+ --watch To rebuild the bundled code if the source code changes.
30
33
 
31
- npx @t8/serve 127.0.0.1:3000 app public dist -b
32
- # - bundle './app/index.ts' to './app/dist/index.js'
33
- # - serve files from './app/public' and './app/dist' at '127.0.0.1:3000'
34
+ --minify To minify the bundled code.
34
35
  ```
35
36
 
36
37
  <details>
@@ -39,7 +40,7 @@ npx @t8/serve 127.0.0.1:3000 app public dist -b
39
40
  ```
40
41
  // package.json
41
42
  "scripts": {
42
- "play": "npx @t8/serve 3000 * playground -b"
43
+ "play": "npx @t8/serve playground -s -b"
43
44
  }
44
45
  ```
45
46
 
@@ -76,7 +77,7 @@ webServer: {
76
77
  ```
77
78
  // package.json
78
79
  "scripts": {
79
- "play": "npx @t8/serve 3000 * playground -b src/index.tsx"
80
+ "play": "npx @t8/serve playground -s -b src/index.tsx"
80
81
  }
81
82
  ```
82
83
 
@@ -127,7 +128,7 @@ webServer: {
127
128
  {
128
129
  "name": "app",
129
130
  "scripts": {
130
- "start": "npx @t8/serve 80 . -b src/index.ts --watch"
131
+ "start": "npx @t8/serve . -u 80 -b src/index.ts --watch"
131
132
  }
132
133
  }
133
134
  ```
package/dist/index.d.ts CHANGED
@@ -22,8 +22,7 @@ type BundleConfig = {
22
22
  };
23
23
 
24
24
  type Config = {
25
- /** Server URL. */
26
- url?: string;
25
+ /** Server URL. */url?: string;
27
26
  /**
28
27
  * Server host.
29
28
  *
@@ -35,8 +34,7 @@ type Config = {
35
34
  *
36
35
  * @defaultValue 3000
37
36
  */
38
- port?: number;
39
- /** Application path. */
37
+ port?: number; /** Application path. */
40
38
  path?: string;
41
39
  /**
42
40
  * Public assets directories. If not provided, the application
@@ -47,12 +45,9 @@ type Config = {
47
45
  * Enables single-page application (SPA) mode. If `true`, all
48
46
  * unmatched URLs are served as "/".
49
47
  */
50
- spa?: boolean;
51
- /** Whether to rebuild whenever the bundled files change. */
52
- watch?: boolean;
53
- /** Whether the bundle should be minified. */
54
- minify?: boolean;
55
- /** Whether to log to the console. */
48
+ spa?: boolean; /** Whether to rebuild whenever the bundled files change. */
49
+ watch?: boolean; /** Whether the bundle should be minified. */
50
+ minify?: boolean; /** Whether to log to the console. */
56
51
  log?: boolean;
57
52
  /**
58
53
  * Bundle config.
@@ -62,8 +57,7 @@ type Config = {
62
57
  * If `true`, it's equivalent to `{ input: "index.ts", output: "index.js" }`.
63
58
  * If `string`, it's equivalent to `input` in `{ input, ouput: "index.js" }`.
64
59
  */
65
- bundle?: boolean | string | BundleConfig | undefined;
66
- /** Custom request handler. */
60
+ bundle?: boolean | string | BundleConfig | undefined; /** Custom request handler. */
67
61
  onRequest?: (req?: IncomingMessage, res?: ServerResponse<IncomingMessage>) => void | Promise<void>;
68
62
  };
69
63
 
package/dist/run.mjs CHANGED
@@ -1,4 +1,118 @@
1
1
  #!/usr/bin/env node
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __commonJS = (cb, mod) => function __require() {
9
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+
28
+ // node_modules/args-json/dist/index.cjs
29
+ var require_dist = __commonJS({
30
+ "node_modules/args-json/dist/index.cjs"(exports) {
31
+ function toCamelCase(x) {
32
+ let s = x.replace(/^[-_.\s~+]|[-_.\s~+]$/g, "");
33
+ if (!/[-_.\s~+]/.test(s)) return s.slice(0, 1).toLowerCase() + s.slice(1);
34
+ return s.toLowerCase().replace(/[-_.\s~+](\S)/g, (_, match) => match.toUpperCase());
35
+ }
36
+ function toKey(x) {
37
+ if (x) {
38
+ if (x.startsWith("--") && x.length > 2) return toCamelCase(x.slice(2));
39
+ if (x.startsWith("-") && x.length === 2) return toCamelCase(x.slice(1));
40
+ }
41
+ }
42
+ function split(x) {
43
+ let words = [], word = "";
44
+ let hasOpenSingleQuote = false;
45
+ let hasOpenDoubleQuote = false;
46
+ for (let i = 0; i < x.length; i++) {
47
+ let c = x[i];
48
+ if (/^\s/.test(c) && !hasOpenSingleQuote && !hasOpenDoubleQuote) {
49
+ if (word) words.push(word);
50
+ word = "";
51
+ continue;
52
+ }
53
+ if (c === "'" && x[i - 1] !== "\\") hasOpenSingleQuote = !hasOpenSingleQuote;
54
+ if (c === '"' && x[i - 1] !== "\\") hasOpenDoubleQuote = !hasOpenDoubleQuote;
55
+ word += c;
56
+ }
57
+ if (word) words.push(word);
58
+ return words;
59
+ }
60
+ function getDefaultInput() {
61
+ return typeof process === "undefined" ? [] : process.argv;
62
+ }
63
+ function parseArgs2(input, map) {
64
+ let normalizedInput;
65
+ let normalizedMap;
66
+ if (input === void 0) normalizedInput = getDefaultInput();
67
+ else if (typeof input === "string") normalizedInput = split(input);
68
+ else if (Array.isArray(input)) normalizedInput = input.map((x) => String(x));
69
+ else if (input !== null && typeof input === "object") {
70
+ normalizedInput = getDefaultInput();
71
+ normalizedMap = input;
72
+ } else normalizedInput = [];
73
+ normalizedInput = normalizedInput.flatMap((item) => {
74
+ let normalizedItem = item.trim();
75
+ let k = normalizedItem.indexOf("=");
76
+ if (k === -1) return normalizedItem;
77
+ return [normalizedItem.slice(0, k), normalizedItem.slice(k + 1)];
78
+ });
79
+ if (map) normalizedMap = map;
80
+ let key = "";
81
+ let parsedArgs = {};
82
+ for (let rawValue of normalizedInput) {
83
+ rawValue = rawValue.trim();
84
+ if (rawValue.startsWith('"') && rawValue.endsWith('"')) rawValue = rawValue.slice(1, -1);
85
+ else if (rawValue.startsWith("'") && rawValue.endsWith("'")) rawValue = rawValue.slice(1, -1);
86
+ let parsedKey = toKey(rawValue);
87
+ if (parsedKey !== void 0) {
88
+ let nextKey = normalizedMap?.[parsedKey] ?? parsedKey;
89
+ if (key && nextKey !== key && parsedArgs[key] === void 0) parsedArgs[key] = true;
90
+ key = nextKey;
91
+ continue;
92
+ }
93
+ let parsedValue;
94
+ if (rawValue) try {
95
+ parsedValue = JSON.parse(rawValue);
96
+ } catch {
97
+ parsedValue = rawValue;
98
+ }
99
+ else parsedValue = true;
100
+ let prevValue = parsedArgs[key];
101
+ let value;
102
+ if (prevValue === void 0) value = key === "" ? [parsedValue] : parsedValue;
103
+ else if (Array.isArray(prevValue)) value = [...prevValue, parsedValue];
104
+ else value = [prevValue, parsedValue];
105
+ parsedArgs[key] = value;
106
+ }
107
+ if (key && parsedArgs[key] === void 0) parsedArgs[key] = true;
108
+ return parsedArgs;
109
+ }
110
+ exports.parseArgs = parseArgs2;
111
+ }
112
+ });
113
+
114
+ // src/run.ts
115
+ var import_args_json = __toESM(require_dist(), 1);
2
116
 
3
117
  // src/serve.ts
4
118
  import { createReadStream } from "node:fs";
@@ -143,47 +257,23 @@ async function serve(config = {}) {
143
257
 
144
258
  // src/run.ts
145
259
  async function run() {
146
- let [url, ...args] = process.argv.slice(2);
147
- let spa = false;
148
- let watch = false;
149
- let minify = false;
150
- if (args[0] === "*") {
151
- spa = true;
152
- args.shift();
153
- }
154
- while (args.at(-1)?.startsWith("--")) {
155
- let arg = args.pop();
156
- switch (arg) {
157
- case "--watch":
158
- watch = true;
159
- break;
160
- case "--minify":
161
- minify = true;
162
- break;
163
- }
164
- }
165
- let bundleFlagIndex = args.indexOf("-b");
166
- let path = args[0];
167
- let dirs;
168
- let bundle2;
169
- if (bundleFlagIndex === -1) dirs = args.slice(1);
170
- else {
171
- dirs = args.slice(1, bundleFlagIndex);
172
- bundle2 = {
173
- input: args[bundleFlagIndex + 1] || void 0,
174
- output: args[bundleFlagIndex + 2] || void 0,
175
- dir: args[bundleFlagIndex + 3] || void 0
176
- };
177
- }
178
- await serve({
179
- url,
180
- path,
181
- dirs,
182
- spa,
260
+ let {
261
+ "": unkeyedArgs,
183
262
  bundle: bundle2,
184
- log: true,
185
- watch,
186
- minify
263
+ dirs,
264
+ ...args
265
+ } = (0, import_args_json.parseArgs)(process.argv.slice(2), {
266
+ b: "bundle",
267
+ u: "url",
268
+ s: "spa"
187
269
  });
270
+ let config = {
271
+ path: unkeyedArgs?.[0],
272
+ dirs: Array.isArray(dirs) ? dirs : dirs && [dirs],
273
+ bundle: Array.isArray(bundle2) ? { input: bundle2[0], output: bundle2[1], dir: bundle2[2] } : bundle2,
274
+ log: true,
275
+ ...args
276
+ };
277
+ await serve(config);
188
278
  }
189
279
  run();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@t8/serve",
3
- "version": "0.1.39",
3
+ "version": "0.2.1",
4
4
  "description": "Simple static file server + bundler, primarily for demo apps and tests, manual or automated",
5
5
  "keywords": [
6
6
  "node",
@@ -27,9 +27,10 @@
27
27
  "shape": "npx codeshape"
28
28
  },
29
29
  "devDependencies": {
30
- "@types/node": "^24.5.2"
30
+ "@types/node": "^25.0.3"
31
31
  },
32
32
  "dependencies": {
33
- "esbuild": "^0.27.1"
33
+ "args-json": "^1.2.10",
34
+ "esbuild": "^0.27.2"
34
35
  }
35
36
  }
package/src/run.ts CHANGED
@@ -1,57 +1,36 @@
1
1
  #!/usr/bin/env node
2
+ import { parseArgs } from "args-json";
2
3
  import type { Config } from "./Config.ts";
3
4
  import { serve } from "./serve.ts";
4
5
 
5
- async function run() {
6
- let [url, ...args] = process.argv.slice(2);
7
- let spa = false;
8
- let watch = false;
9
- let minify = false;
10
-
11
- if (args[0] === "*") {
12
- spa = true;
13
- args.shift();
14
- }
15
-
16
- while (args.at(-1)?.startsWith("--")) {
17
- let arg = args.pop();
18
-
19
- switch (arg) {
20
- case "--watch":
21
- watch = true;
22
- break;
23
- case "--minify":
24
- minify = true;
25
- break;
26
- }
27
- }
28
-
29
- let bundleFlagIndex = args.indexOf("-b");
30
- let path = args[0];
31
-
32
- let dirs: string[];
33
- let bundle: Config["bundle"];
34
-
35
- if (bundleFlagIndex === -1) dirs = args.slice(1);
36
- else {
37
- dirs = args.slice(1, bundleFlagIndex);
38
- bundle = {
39
- input: args[bundleFlagIndex + 1] || undefined,
40
- output: args[bundleFlagIndex + 2] || undefined,
41
- dir: args[bundleFlagIndex + 3] || undefined,
42
- };
43
- }
6
+ type CLIConfig = Omit<Config, "bundle" | "onRequest"> & {
7
+ ""?: string[];
8
+ bundle?: string | string[];
9
+ };
44
10
 
45
- await serve({
46
- url,
47
- path,
48
- dirs,
49
- spa,
11
+ async function run() {
12
+ let {
13
+ "": unkeyedArgs,
50
14
  bundle,
51
- log: true,
52
- watch,
53
- minify,
15
+ dirs,
16
+ ...args
17
+ } = parseArgs<CLIConfig>(process.argv.slice(2), {
18
+ b: "bundle",
19
+ u: "url",
20
+ s: "spa",
54
21
  });
22
+
23
+ let config: Config = {
24
+ path: unkeyedArgs?.[0],
25
+ dirs: Array.isArray(dirs) ? dirs : dirs && [dirs],
26
+ bundle: Array.isArray(bundle)
27
+ ? { input: bundle[0], output: bundle[1], dir: bundle[2] }
28
+ : bundle,
29
+ log: true,
30
+ ...args,
31
+ };
32
+
33
+ await serve(config);
55
34
  }
56
35
 
57
36
  run();