@marko/run 0.1.4 → 0.1.5

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,6 +5,7 @@ import { createMiddleware } from "@marko/run/adapter/middleware";
5
5
  import { fetch } from "@marko/run/router";
6
6
  import { dirname } from 'path';
7
7
  import { fileURLToPath } from 'url';
8
+ import zlib from 'zlib';
8
9
 
9
10
  const __dirname = dirname(fileURLToPath(import.meta.url));
10
11
 
@@ -12,6 +13,7 @@ const { PORT = 3456 } = process.env;
12
13
 
13
14
  const middleware = createMiddleware(fetch);
14
15
  const compress = compression({
16
+ flush: zlib.constants.Z_PARTIAL_FLUSH,
15
17
  threshold: 500,
16
18
  });
17
19
  const staticServe = createStaticServe(__dirname, {
@@ -1,4 +1,4 @@
1
- import { ViteDevServer } from "vite";
1
+ import { InlineConfig, ViteDevServer } from "vite";
2
2
  import type { NodeMiddleware } from "./middleware";
3
3
  export declare function createViteDevMiddleware<T>(devServer: ViteDevServer, load: (prev: T | undefined) => Promise<T>, factory: (value: T) => NodeMiddleware): NodeMiddleware;
4
- export declare function createDevServer(configFile?: string): Promise<import("vite").Connect.Server>;
4
+ export declare function createDevServer(config?: InlineConfig): Promise<ViteDevServer>;
@@ -59,9 +59,9 @@ function createViteDevMiddleware(devServer, load, factory) {
59
59
  }
60
60
  };
61
61
  }
62
- async function createDevServer(configFile) {
62
+ async function createDevServer(config2) {
63
63
  const devServer = await (0, import_vite.createServer)({
64
- configFile,
64
+ ...config2,
65
65
  appType: "custom",
66
66
  server: { middlewareMode: true }
67
67
  });
@@ -73,7 +73,8 @@ async function createDevServer(configFile) {
73
73
  async () => await devServer.ssrLoadModule("@marko/run/router"),
74
74
  (module2) => createMiddleware(module2.fetch, { devServer })
75
75
  );
76
- return devServer.middlewares.use(middleware);
76
+ devServer.middlewares.use(middleware);
77
+ return devServer;
77
78
  }
78
79
 
79
80
  // src/vite/utils/server.ts
@@ -90,14 +91,14 @@ async function parseEnv(envFile) {
90
91
  function loadEnv(envFile) {
91
92
  (0, import_dotenv.config)({ path: envFile });
92
93
  }
93
- async function spawnServer(cmd, port = 0, env, cwd = process.cwd(), wait = 3e4) {
94
+ async function spawnServer(cmd, args = [], port = 0, env, cwd = process.cwd(), wait = 3e4) {
94
95
  if (port <= 0) {
95
96
  port = await getAvailablePort();
96
97
  }
97
98
  if (typeof env === "string") {
98
99
  env = await parseEnv(env);
99
100
  }
100
- const proc = import_child_process.default.spawn(cmd, {
101
+ const proc = import_child_process.default.spawn(cmd, args, {
101
102
  cwd,
102
103
  shell: true,
103
104
  stdio: "inherit",
@@ -108,22 +109,29 @@ async function spawnServer(cmd, port = 0, env, cwd = process.cwd(), wait = 3e4)
108
109
  proc.unref();
109
110
  proc.kill();
110
111
  };
112
+ try {
113
+ await waitForServer(port, wait);
114
+ } catch (err) {
115
+ close();
116
+ throw err;
117
+ }
118
+ return {
119
+ port,
120
+ close
121
+ };
122
+ }
123
+ async function waitForServer(port, wait = 0) {
111
124
  let remaining = wait > 0 ? wait : Infinity;
112
125
  while (!await isPortInUse(port)) {
113
126
  if (remaining >= 100) {
114
127
  remaining -= 100;
115
128
  await sleep(100);
116
129
  } else {
117
- close();
118
130
  throw new Error(
119
131
  `site-write: timeout while wating for server to start on port "${port}".`
120
132
  );
121
133
  }
122
134
  }
123
- return {
124
- port,
125
- close
126
- };
127
135
  }
128
136
  async function isPortInUse(port) {
129
137
  return new Promise((resolve) => {
@@ -147,6 +155,7 @@ function sleep(ms) {
147
155
  }
148
156
 
149
157
  // src/adapter/index.ts
158
+ var import_parse_node_args = __toESM(require("parse-node-args"), 1);
150
159
  var import_meta = {};
151
160
  var __dirname = (0, import_url.fileURLToPath)(new URL(".", import_meta.url));
152
161
  function adapter() {
@@ -156,20 +165,33 @@ function adapter() {
156
165
  const entry = import_path.default.join(__dirname, "default-entry");
157
166
  return entry;
158
167
  },
159
- async startDev(configFile, port, envFile) {
168
+ async startDev(config2, { port = 3e3, envFile }) {
169
+ const { root, configFile } = config2;
160
170
  envFile && await loadEnv(envFile);
161
- const server = await createDevServer(configFile);
171
+ const devServer = await createDevServer({
172
+ root,
173
+ configFile
174
+ });
162
175
  return new Promise((resolve) => {
163
- const listener = server.listen(port, () => {
176
+ const listener = devServer.middlewares.listen(port, () => {
164
177
  const address = listener.address();
165
178
  console.log(`Dev server started: http://localhost:${address.port}`);
166
- resolve();
179
+ resolve({
180
+ port,
181
+ async close() {
182
+ await devServer.close();
183
+ }
184
+ });
167
185
  });
168
186
  });
169
187
  },
170
- async startPreview(_dir, entry, port, envFile) {
171
- const server = await spawnServer(`node ${entry}`, port, envFile);
188
+ async startPreview(entry, options) {
189
+ const { port, envFile } = options;
190
+ const { nodeArgs } = (0, import_parse_node_args.default)(options.args);
191
+ const args = [...nodeArgs, entry];
192
+ const server = await spawnServer("node", args, port, envFile);
172
193
  console.log(`Preview server started: http://localhost:${server.port}`);
194
+ return server;
173
195
  }
174
196
  };
175
197
  }
@@ -1,5 +1,6 @@
1
1
  import type { Adapter } from "../vite";
2
+ import { type SpawnedServer } from "../vite/utils/server";
2
3
  export { createDevServer, createViteDevMiddleware } from "./dev-server";
3
- export type { Adapter };
4
- export type { NodePlatformInfo } from './middleware';
4
+ export type { Adapter, SpawnedServer };
5
+ export type { NodePlatformInfo } from "./middleware";
5
6
  export default function adapter(): Adapter;
@@ -27,9 +27,9 @@ function createViteDevMiddleware(devServer, load, factory) {
27
27
  }
28
28
  };
29
29
  }
30
- async function createDevServer(configFile) {
30
+ async function createDevServer(config2) {
31
31
  const devServer = await createServer({
32
- configFile,
32
+ ...config2,
33
33
  appType: "custom",
34
34
  server: { middlewareMode: true }
35
35
  });
@@ -41,7 +41,8 @@ async function createDevServer(configFile) {
41
41
  async () => await devServer.ssrLoadModule("@marko/run/router"),
42
42
  (module) => createMiddleware(module.fetch, { devServer })
43
43
  );
44
- return devServer.middlewares.use(middleware);
44
+ devServer.middlewares.use(middleware);
45
+ return devServer;
45
46
  }
46
47
 
47
48
  // src/vite/utils/server.ts
@@ -58,14 +59,14 @@ async function parseEnv(envFile) {
58
59
  function loadEnv(envFile) {
59
60
  config({ path: envFile });
60
61
  }
61
- async function spawnServer(cmd, port = 0, env, cwd = process.cwd(), wait = 3e4) {
62
+ async function spawnServer(cmd, args = [], port = 0, env, cwd = process.cwd(), wait = 3e4) {
62
63
  if (port <= 0) {
63
64
  port = await getAvailablePort();
64
65
  }
65
66
  if (typeof env === "string") {
66
67
  env = await parseEnv(env);
67
68
  }
68
- const proc = cp.spawn(cmd, {
69
+ const proc = cp.spawn(cmd, args, {
69
70
  cwd,
70
71
  shell: true,
71
72
  stdio: "inherit",
@@ -76,22 +77,29 @@ async function spawnServer(cmd, port = 0, env, cwd = process.cwd(), wait = 3e4)
76
77
  proc.unref();
77
78
  proc.kill();
78
79
  };
80
+ try {
81
+ await waitForServer(port, wait);
82
+ } catch (err) {
83
+ close();
84
+ throw err;
85
+ }
86
+ return {
87
+ port,
88
+ close
89
+ };
90
+ }
91
+ async function waitForServer(port, wait = 0) {
79
92
  let remaining = wait > 0 ? wait : Infinity;
80
93
  while (!await isPortInUse(port)) {
81
94
  if (remaining >= 100) {
82
95
  remaining -= 100;
83
96
  await sleep(100);
84
97
  } else {
85
- close();
86
98
  throw new Error(
87
99
  `site-write: timeout while wating for server to start on port "${port}".`
88
100
  );
89
101
  }
90
102
  }
91
- return {
92
- port,
93
- close
94
- };
95
103
  }
96
104
  async function isPortInUse(port) {
97
105
  return new Promise((resolve) => {
@@ -115,6 +123,7 @@ function sleep(ms) {
115
123
  }
116
124
 
117
125
  // src/adapter/index.ts
126
+ import parseNodeArgs from "parse-node-args";
118
127
  var __dirname = fileURLToPath(new URL(".", import.meta.url));
119
128
  function adapter() {
120
129
  return {
@@ -123,20 +132,33 @@ function adapter() {
123
132
  const entry = path.join(__dirname, "default-entry");
124
133
  return entry;
125
134
  },
126
- async startDev(configFile, port, envFile) {
135
+ async startDev(config2, { port = 3e3, envFile }) {
136
+ const { root, configFile } = config2;
127
137
  envFile && await loadEnv(envFile);
128
- const server = await createDevServer(configFile);
138
+ const devServer = await createDevServer({
139
+ root,
140
+ configFile
141
+ });
129
142
  return new Promise((resolve) => {
130
- const listener = server.listen(port, () => {
143
+ const listener = devServer.middlewares.listen(port, () => {
131
144
  const address = listener.address();
132
145
  console.log(`Dev server started: http://localhost:${address.port}`);
133
- resolve();
146
+ resolve({
147
+ port,
148
+ async close() {
149
+ await devServer.close();
150
+ }
151
+ });
134
152
  });
135
153
  });
136
154
  },
137
- async startPreview(_dir, entry, port, envFile) {
138
- const server = await spawnServer(`node ${entry}`, port, envFile);
155
+ async startPreview(entry, options) {
156
+ const { port, envFile } = options;
157
+ const { nodeArgs } = parseNodeArgs(options.args);
158
+ const args = [...nodeArgs, entry];
159
+ const server = await spawnServer("node", args, port, envFile);
139
160
  console.log(`Preview server started: http://localhost:${server.port}`);
161
+ return server;
140
162
  }
141
163
  };
142
164
  }
@@ -1,11 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli/index.ts
4
+ import sade from "sade";
5
+
6
+ // src/cli/commands.ts
4
7
  import path3 from "path";
5
8
  import fs4 from "fs";
6
9
  import { fileURLToPath as fileURLToPath2 } from "url";
7
10
  import { build as viteBuild, resolveConfig } from "vite";
8
- import sade from "sade";
9
11
 
10
12
  // src/vite/utils/config.ts
11
13
  var PluginConfigKey = "__MARKO_RUN_PLUGIN_CONFIG__";
@@ -21,7 +23,7 @@ var getExternalPluginOptions = (viteConfig) => getConfig(viteConfig, PluginConfi
21
23
  var setExternalPluginOptions = (viteConfig, value) => setConfig(viteConfig, PluginConfigKey, value);
22
24
  var setExternalAdapterOptions = (viteConfig, value) => setConfig(viteConfig, AdapterConfigKey, value);
23
25
 
24
- // src/cli/index.ts
26
+ // src/cli/commands.ts
25
27
  import { MemoryStore } from "@marko/vite";
26
28
 
27
29
  // src/vite/utils/server.ts
@@ -35,15 +37,15 @@ async function parseEnv(envFile) {
35
37
  return parse(content);
36
38
  }
37
39
  }
38
- async function spawnServer(cmd, port = 0, env, cwd2 = process.cwd(), wait = 3e4) {
40
+ async function spawnServer(cmd, args = [], port = 0, env, cwd = process.cwd(), wait = 3e4) {
39
41
  if (port <= 0) {
40
42
  port = await getAvailablePort();
41
43
  }
42
44
  if (typeof env === "string") {
43
45
  env = await parseEnv(env);
44
46
  }
45
- const proc = cp.spawn(cmd, {
46
- cwd: cwd2,
47
+ const proc = cp.spawn(cmd, args, {
48
+ cwd,
47
49
  shell: true,
48
50
  stdio: "inherit",
49
51
  windowsHide: true,
@@ -53,22 +55,29 @@ async function spawnServer(cmd, port = 0, env, cwd2 = process.cwd(), wait = 3e4)
53
55
  proc.unref();
54
56
  proc.kill();
55
57
  };
58
+ try {
59
+ await waitForServer(port, wait);
60
+ } catch (err) {
61
+ close();
62
+ throw err;
63
+ }
64
+ return {
65
+ port,
66
+ close
67
+ };
68
+ }
69
+ async function waitForServer(port, wait = 0) {
56
70
  let remaining = wait > 0 ? wait : Infinity;
57
71
  while (!await isPortInUse(port)) {
58
72
  if (remaining >= 100) {
59
73
  remaining -= 100;
60
74
  await sleep(100);
61
75
  } else {
62
- close();
63
76
  throw new Error(
64
77
  `site-write: timeout while wating for server to start on port "${port}".`
65
78
  );
66
79
  }
67
80
  }
68
- return {
69
- port,
70
- close
71
- };
72
81
  }
73
82
  async function isPortInUse(port) {
74
83
  return new Promise((resolve) => {
@@ -96,7 +105,7 @@ import path2 from "path";
96
105
  import crypto from "crypto";
97
106
  import fs3 from "fs";
98
107
  import glob from "glob";
99
- import { mergeConfig, resolvePackageData } from "vite";
108
+ import { mergeConfig } from "vite";
100
109
  import markoVitePlugin, { FileStore } from "@marko/vite";
101
110
 
102
111
  // src/vite/constants.ts
@@ -129,9 +138,9 @@ import path from "path";
129
138
  import * as t from "@babel/types";
130
139
 
131
140
  // src/vite/utils/log.ts
141
+ import zlib from "node:zlib";
132
142
  import Table from "cli-table3";
133
143
  import kleur from "kleur";
134
- import { gzipSizeSync } from "gzip-size";
135
144
  import format from "human-format";
136
145
  var HttpVerbColors = {
137
146
  get: kleur.green,
@@ -152,6 +161,7 @@ async function resolveAdapter(root, options, log) {
152
161
  if (adapter !== void 0) {
153
162
  return adapter;
154
163
  }
164
+ const { resolvePackageData } = await import("vite");
155
165
  const pkg = resolvePackageData(".", root);
156
166
  if (pkg) {
157
167
  const dependecies = { ...pkg.data.dependecies, ...pkg.data.devDependencies };
@@ -173,48 +183,12 @@ async function resolveAdapter(root, options, log) {
173
183
  return module.default();
174
184
  }
175
185
 
176
- // src/cli/index.ts
186
+ // src/cli/commands.ts
177
187
  var __dirname2 = fileURLToPath2(new URL(".", import.meta.url));
178
- var cwd = process.cwd();
179
188
  var defaultPort = +process.env.PORT || 3e3;
180
189
  var defaultConfigFileBases = ["serve.config", "vite.config"];
181
190
  var defaultConfigFileExts = [".js", ".cjs", ".mjs", ".ts", ".mts"];
182
- var prog = sade("marko-run").version("0.0.1").option(
183
- "-c, --config",
184
- `Provide path to a Vite config file (by default looks for a file starting with ${defaultConfigFileBases.join(
185
- " or "
186
- )} with one of these extensions: ${defaultConfigFileExts.join(", ")})`
187
- ).option("-e, --env", "Provide path to a dotenv file");
188
- prog.command("preview [entry]").describe("Start a production-like server for already-built app files").option(
189
- "-o, --output",
190
- "Directory to serve files from, and write asset files to if `--build` (default: )"
191
- ).option(
192
- "-p, --port",
193
- "Port the server should listen on (defaults: `$PORT` env variable or 3000)"
194
- ).option("-f, --file", "Output file to start").action(async (entry, opts) => {
195
- process.env.NODE_ENV = "production";
196
- const config2 = await getViteConfig(cwd, opts.config);
197
- await build(entry, config2, opts.output, false, opts.env);
198
- await preview(opts.entry, config2, opts.port, opts.output, opts.env);
199
- });
200
- prog.command("dev [entry]", "", { default: true }).describe("Start development server in watch mode").option(
201
- "-p, --port",
202
- "Port the dev server should listen on (defaults: 'preview.port' in config, or `$PORT` env variable, or 3000)"
203
- ).example("dev --config vite.config.js").action(async (entry, opts) => {
204
- const cmd = opts._.length ? `${entry} ${opts._.join(" ")}` : entry ? `node ${entry}` : void 0;
205
- const config2 = await getViteConfig(cwd, opts.config);
206
- await dev(cmd, config2, opts.port, opts.env);
207
- });
208
- prog.command("build [entry]").describe("Build the application (without serving it)").option(
209
- "-o, --output",
210
- "Directory to write built files (default: 'build.outDir' in Vite config)"
211
- ).option("--skip-client", "Skip the client-side build").example("build --config vite.config.js").action(async (entry, opts) => {
212
- process.env.NODE_ENV = "production";
213
- const config2 = await getViteConfig(cwd, opts.config);
214
- await build(entry, config2, opts.ouput, opts["skip-client"], opts.env);
215
- });
216
- prog.parse(process.argv);
217
- async function preview(entry, configFile, port, outDir, envFile) {
191
+ async function preview(entry, cwd, configFile, port, outDir, envFile, args = []) {
218
192
  const resolvedConfig = await resolveConfig(
219
193
  { root: cwd, configFile, logLevel: "silent", build: { outDir } },
220
194
  "serve"
@@ -233,9 +207,16 @@ async function preview(entry, configFile, port, outDir, envFile) {
233
207
  if (envFile) {
234
208
  envFile = path3.resolve(cwd, envFile);
235
209
  }
236
- await adapter.startPreview(dir, entryFile, port, envFile);
210
+ const options = {
211
+ cwd,
212
+ dir,
213
+ args,
214
+ port,
215
+ envFile
216
+ };
217
+ return await adapter.startPreview(entryFile, options);
237
218
  }
238
- async function dev(cmd, configFile, port, envFile) {
219
+ async function dev(cmd, cwd, configFile, port, envFile, args = []) {
239
220
  const resolvedConfig = await resolveConfig(
240
221
  { root: cwd, configFile, logLevel: "silent" },
241
222
  "build"
@@ -247,7 +228,7 @@ async function dev(cmd, configFile, port, envFile) {
247
228
  envFile = path3.resolve(cwd, envFile);
248
229
  }
249
230
  if (cmd) {
250
- await spawnServer(cmd, port, envFile);
231
+ return await spawnServer(cmd, args, port, envFile, cwd);
251
232
  } else {
252
233
  const adapter = await resolveAdapter2(resolvedConfig);
253
234
  if (!adapter) {
@@ -258,12 +239,17 @@ async function dev(cmd, configFile, port, envFile) {
258
239
  throw new Error(
259
240
  `Adapter '${adapter.name}' does not support 'serve' command`
260
241
  );
261
- } else {
262
- await adapter.startDev(configFile, port, envFile);
263
242
  }
243
+ const options = {
244
+ cwd,
245
+ args,
246
+ port,
247
+ envFile
248
+ };
249
+ return await adapter.startDev({ root: cwd, configFile }, options);
264
250
  }
265
251
  }
266
- async function build(entry, configFile, outDir, skipClient = false, envFile) {
252
+ async function build(entry, cwd, configFile, outDir, envFile) {
267
253
  var _a;
268
254
  const resolvedConfig = await resolveConfig(
269
255
  { root: cwd, configFile, logLevel: "silent" },
@@ -311,15 +297,13 @@ async function build(entry, configFile, outDir, skipClient = false, envFile) {
311
297
  }
312
298
  }
313
299
  });
314
- if (!skipClient) {
315
- await viteBuild({
316
- ...buildConfig,
317
- build: {
318
- ...buildConfig.build,
319
- sourcemap: true
320
- }
321
- });
322
- }
300
+ await viteBuild({
301
+ ...buildConfig,
302
+ build: {
303
+ ...buildConfig.build,
304
+ sourcemap: true
305
+ }
306
+ });
323
307
  }
324
308
  function findFileWithExt(dir, base, extensions = defaultConfigFileExts) {
325
309
  for (const ext of extensions) {
@@ -353,3 +337,51 @@ async function resolveAdapter2(config2) {
353
337
  }
354
338
  return resolveAdapter(config2.root, options);
355
339
  }
340
+
341
+ // src/cli/index.ts
342
+ var prog = sade("marko-run").version("0.0.1").option(
343
+ "-c, --config",
344
+ `Provide path to a Vite config file (by default looks for a file starting with ${defaultConfigFileBases.join(
345
+ " or "
346
+ )} with one of these extensions: ${defaultConfigFileExts.join(", ")})`
347
+ ).option("-e, --env", "Provide path to a dotenv file");
348
+ prog.command("preview [entry]").describe("Start a production-like server for already-built app files").option(
349
+ "-o, --output",
350
+ "Directory to serve files from, and write asset files to if `--build` (default: 'build.outDir' in Vite config)"
351
+ ).option(
352
+ "-p, --port",
353
+ "Port the server should listen on (defaults: `$PORT` env variable or 3000)"
354
+ ).option("-f, --file", "Output file to start").action(async (entry, opts) => {
355
+ process.env.NODE_ENV = "production";
356
+ const cwd = process.cwd();
357
+ const args = process.argv.slice(entry ? 4 : 3);
358
+ const config2 = await getViteConfig(cwd, opts.config);
359
+ await build(entry, cwd, config2, opts.output, opts.env);
360
+ await preview(
361
+ opts.file,
362
+ cwd,
363
+ config2,
364
+ opts.port,
365
+ opts.output,
366
+ opts.env,
367
+ args
368
+ );
369
+ });
370
+ prog.command("dev [entry]", "", { default: true }).describe("Start development server in watch mode").option(
371
+ "-p, --port",
372
+ "Port the dev server should listen on (defaults: 'preview.port' in config, or `$PORT` env variable, or 3000)"
373
+ ).example("dev --config vite.config.js").action(async (entry, opts) => {
374
+ const cwd = process.cwd();
375
+ const args = process.argv.slice(entry ? 4 : 3);
376
+ const config2 = await getViteConfig(cwd, opts.config);
377
+ await dev(entry, cwd, config2, opts.port, opts.env, args);
378
+ });
379
+ prog.command("build [entry]").describe("Build the application (without serving it)").option(
380
+ "-o, --output",
381
+ "Directory to write built files (default: 'build.outDir' in Vite config)"
382
+ ).example("build --config vite.config.js").action(async (entry, opts) => {
383
+ const cwd = process.cwd();
384
+ const config2 = await getViteConfig(cwd, opts.config);
385
+ await build(entry, cwd, config2, opts.ouput, opts.env);
386
+ });
387
+ prog.parse(process.argv);
@@ -0,0 +1 @@
1
+ <!doctype html><html lang=en><head><meta charset=UTF-8><title>@marko/run Test Fixture</title><script async type="module" crossorigin src="/assets/__marko-run__route__index.marko-3cfb730f.js"></script></head><body><div id=app>Page rendered</div></body></html>
@@ -5,7 +5,7 @@ declare global {
5
5
  const NotMatched: unique symbol;
6
6
  interface Route extends AnyRoute {
7
7
  }
8
- interface Context extends AnyContext<Route> {
8
+ interface Context extends AnyContext {
9
9
  }
10
10
  type Handler<Params extends ParamsObject = {}, Meta = unknown> = HandlerLike<AnyRoute<Params, Meta, string>>;
11
11
  function route<Params extends ParamsObject = {}, Meta = unknown>(handler: Handler<Params, Meta>): typeof handler;
@@ -829,7 +829,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
829
829
  if (terminal || (dynamic == null ? void 0 : dynamic.route)) {
830
830
  closeCount++;
831
831
  writer.writeBlockStart(`if (!${index} || ${index} === len) {`);
832
- let value = `pathname.slice(${offset}, ${index} ? -1 : len)`;
832
+ let value = `decodeURIComponent(pathname.slice(${offset}, ${index} ? -1 : len))`;
833
833
  if (dynamic == null ? void 0 : dynamic.route) {
834
834
  const segment = `s${next}`;
835
835
  writer.writeLines(`const ${segment} = ${value};`);
@@ -868,7 +868,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
868
868
  writer.writeBlockStart(`if (${index} && ${index} !== len) {`);
869
869
  closeCount++;
870
870
  }
871
- let value = `pathname.slice(${offset}, ${index} - 1)`;
871
+ let value = `decodeURIComponent(pathname.slice(${offset}, ${index} - 1))`;
872
872
  if ((dynamic == null ? void 0 : dynamic.static) || (dynamic == null ? void 0 : dynamic.dynamic)) {
873
873
  const segment = `s${next}`;
874
874
  writer.writeLines(`const ${segment} = ${value};`);
@@ -880,11 +880,12 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
880
880
  writer.writeBlockStart(`switch (${value}.toLowerCase()) {`);
881
881
  }
882
882
  for (const child of children) {
883
+ const decodedKey = decodeURIComponent(child.key);
883
884
  if (useSwitch) {
884
- writer.writeBlockStart(`case '${child.key}': {`);
885
+ writer.writeBlockStart(`case '${decodedKey}': {`);
885
886
  } else {
886
887
  writer.writeBlockStart(
887
- `if (${value}.toLowerCase() === '${child.key}') {`
888
+ `if (${value}.toLowerCase() === '${decodedKey}') {`
888
889
  );
889
890
  }
890
891
  const nextOffset = typeof offset === "string" ? index : offset + child.key.length + 1;
@@ -914,6 +915,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
914
915
  }
915
916
  }
916
917
  function wrapPropertyName(name) {
918
+ name = decodeURIComponent(name);
917
919
  return /^[^A-Za-z_$]|[^A-Za-z0-9$_]/.test(name) ? `'${name}'` : name;
918
920
  }
919
921
  function renderParamsInfo(params, pathIndex) {
@@ -1014,7 +1016,10 @@ interface NoMeta {}
1014
1016
  const routeType = `Route${route.index}`;
1015
1017
  const pathType = `\`${route.path.replace(
1016
1018
  /\/\$(\$?)([^\/]*)/,
1017
- (_, catchAll, name) => catchAll ? `/:${name || "rest"}*` : `/:${name}`
1019
+ (_, catchAll, name) => {
1020
+ name = decodeURIComponent(name);
1021
+ return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
1022
+ }
1018
1023
  )}\``;
1019
1024
  const paramsType = (params == null ? void 0 : params.length) ? renderParamsInfoType(params) : "NoParams";
1020
1025
  let metaType = "NoMeta";
@@ -1022,10 +1027,10 @@ interface NoMeta {}
1022
1027
  const isGet = page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"));
1023
1028
  const isPost = (_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post");
1024
1029
  if (isGet || isPost) {
1025
- const path3 = route.path.replace(
1026
- /\$(\$?)([^/]+)/g,
1027
- (_, s, name) => s ? `\${...${name}}` : `\${${name}}`
1028
- );
1030
+ const path3 = route.path.replace(/\$(\$?)([^/]+)/g, (_, catchAll, name) => {
1031
+ name = decodeURIComponent(name);
1032
+ return catchAll ? `\${...${name}}` : `\${${name}}`;
1033
+ });
1029
1034
  const splatIndex = path3.indexOf("/${...");
1030
1035
  if (splatIndex >= 0) {
1031
1036
  const path22 = path3.slice(0, splatIndex) || "/";
@@ -1236,9 +1241,9 @@ function getExportIdentifiers(astProgramNode) {
1236
1241
  }
1237
1242
 
1238
1243
  // src/vite/utils/log.ts
1244
+ var import_node_zlib = __toESM(require("node:zlib"), 1);
1239
1245
  var import_cli_table3 = __toESM(require("cli-table3"), 1);
1240
1246
  var import_kleur = __toESM(require("kleur"), 1);
1241
- var import_gzip_size = require("gzip-size");
1242
1247
  var import_human_format = __toESM(require("human-format"), 1);
1243
1248
  var HttpVerbColors = {
1244
1249
  get: import_kleur.default.green,
@@ -1324,17 +1329,20 @@ function computeRouteSize(route, bundle) {
1324
1329
  }
1325
1330
  return [0, 0];
1326
1331
  }
1327
- function byteSize(str) {
1328
- return new Blob([str]).size;
1332
+ function gzipSize(source) {
1333
+ return import_node_zlib.default.gzipSync(source, { level: 9 }).length;
1334
+ }
1335
+ function byteSize(source) {
1336
+ return new Blob([source]).size;
1329
1337
  }
1330
1338
  function computeChunkSize(chunk, bundle, seen = /* @__PURE__ */ new Set()) {
1331
1339
  if (chunk.type === "asset") {
1332
1340
  return [
1333
1341
  byteSize(chunk.source),
1334
- (0, import_gzip_size.gzipSizeSync)(chunk.source)
1342
+ gzipSize(chunk.source)
1335
1343
  ];
1336
1344
  }
1337
- const size = [byteSize(chunk.code), (0, import_gzip_size.gzipSizeSync)(chunk.code)];
1345
+ const size = [byteSize(chunk.code), gzipSize(chunk.code)];
1338
1346
  for (const id of chunk.imports) {
1339
1347
  if (!seen.has(id)) {
1340
1348
  const [bytes, compBytes] = computeChunkSize(bundle[id], bundle, seen);
@@ -1424,7 +1432,7 @@ function markoRun(opts = {}) {
1424
1432
  const filepath = import_path2.default.join(typesDir, "routes.d.ts");
1425
1433
  const data = await renderRouteTypeInfo(
1426
1434
  routes,
1427
- import_path2.default.relative(typesDir, routesDir),
1435
+ import_path2.default.relative(typesDir, resolvedRoutesDir),
1428
1436
  adapter
1429
1437
  );
1430
1438
  if (data !== typesFile || !import_fs2.default.existsSync(filepath)) {
@@ -1537,6 +1545,9 @@ function markoRun(opts = {}) {
1537
1545
  define: isBuild ? {
1538
1546
  "process.env.NODE_ENV": "'production'"
1539
1547
  } : void 0,
1548
+ ssr: {
1549
+ noExternal: /@marko\/run/
1550
+ },
1540
1551
  build: {
1541
1552
  emptyOutDir: isSSRBuild
1542
1553
  }
@@ -1774,7 +1785,8 @@ async function resolveAdapter(root, options, log) {
1774
1785
  if (adapter !== void 0) {
1775
1786
  return adapter;
1776
1787
  }
1777
- const pkg = (0, import_vite.resolvePackageData)(".", root);
1788
+ const { resolvePackageData } = await import("vite");
1789
+ const pkg = resolvePackageData(".", root);
1778
1790
  if (pkg) {
1779
1791
  const dependecies = { ...pkg.data.dependecies, ...pkg.data.devDependencies };
1780
1792
  for (const name of Object.keys(dependecies)) {
@@ -1809,14 +1821,14 @@ async function parseEnv(envFile) {
1809
1821
  function loadEnv(envFile) {
1810
1822
  (0, import_dotenv.config)({ path: envFile });
1811
1823
  }
1812
- async function spawnServer(cmd, port = 0, env, cwd = process.cwd(), wait = 3e4) {
1824
+ async function spawnServer(cmd, args = [], port = 0, env, cwd = process.cwd(), wait = 3e4) {
1813
1825
  if (port <= 0) {
1814
1826
  port = await getAvailablePort();
1815
1827
  }
1816
1828
  if (typeof env === "string") {
1817
1829
  env = await parseEnv(env);
1818
1830
  }
1819
- const proc = import_child_process.default.spawn(cmd, {
1831
+ const proc = import_child_process.default.spawn(cmd, args, {
1820
1832
  cwd,
1821
1833
  shell: true,
1822
1834
  stdio: "inherit",
@@ -1827,22 +1839,29 @@ async function spawnServer(cmd, port = 0, env, cwd = process.cwd(), wait = 3e4)
1827
1839
  proc.unref();
1828
1840
  proc.kill();
1829
1841
  };
1842
+ try {
1843
+ await waitForServer(port, wait);
1844
+ } catch (err) {
1845
+ close();
1846
+ throw err;
1847
+ }
1848
+ return {
1849
+ port,
1850
+ close
1851
+ };
1852
+ }
1853
+ async function waitForServer(port, wait = 0) {
1830
1854
  let remaining = wait > 0 ? wait : Infinity;
1831
1855
  while (!await isPortInUse(port)) {
1832
1856
  if (remaining >= 100) {
1833
1857
  remaining -= 100;
1834
1858
  await sleep(100);
1835
1859
  } else {
1836
- close();
1837
1860
  throw new Error(
1838
1861
  `site-write: timeout while wating for server to start on port "${port}".`
1839
1862
  );
1840
1863
  }
1841
1864
  }
1842
- return {
1843
- port,
1844
- close
1845
- };
1846
1865
  }
1847
1866
  async function isPortInUse(port) {
1848
1867
  return new Promise((resolve) => {
@@ -3,7 +3,7 @@ import path2 from "path";
3
3
  import crypto from "crypto";
4
4
  import fs2 from "fs";
5
5
  import glob from "glob";
6
- import { mergeConfig, resolvePackageData } from "vite";
6
+ import { mergeConfig } from "vite";
7
7
  import markoVitePlugin, { FileStore } from "@marko/vite";
8
8
 
9
9
  // src/vite/constants.ts
@@ -792,7 +792,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
792
792
  if (terminal || (dynamic == null ? void 0 : dynamic.route)) {
793
793
  closeCount++;
794
794
  writer.writeBlockStart(`if (!${index} || ${index} === len) {`);
795
- let value = `pathname.slice(${offset}, ${index} ? -1 : len)`;
795
+ let value = `decodeURIComponent(pathname.slice(${offset}, ${index} ? -1 : len))`;
796
796
  if (dynamic == null ? void 0 : dynamic.route) {
797
797
  const segment = `s${next}`;
798
798
  writer.writeLines(`const ${segment} = ${value};`);
@@ -831,7 +831,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
831
831
  writer.writeBlockStart(`if (${index} && ${index} !== len) {`);
832
832
  closeCount++;
833
833
  }
834
- let value = `pathname.slice(${offset}, ${index} - 1)`;
834
+ let value = `decodeURIComponent(pathname.slice(${offset}, ${index} - 1))`;
835
835
  if ((dynamic == null ? void 0 : dynamic.static) || (dynamic == null ? void 0 : dynamic.dynamic)) {
836
836
  const segment = `s${next}`;
837
837
  writer.writeLines(`const ${segment} = ${value};`);
@@ -843,11 +843,12 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
843
843
  writer.writeBlockStart(`switch (${value}.toLowerCase()) {`);
844
844
  }
845
845
  for (const child of children) {
846
+ const decodedKey = decodeURIComponent(child.key);
846
847
  if (useSwitch) {
847
- writer.writeBlockStart(`case '${child.key}': {`);
848
+ writer.writeBlockStart(`case '${decodedKey}': {`);
848
849
  } else {
849
850
  writer.writeBlockStart(
850
- `if (${value}.toLowerCase() === '${child.key}') {`
851
+ `if (${value}.toLowerCase() === '${decodedKey}') {`
851
852
  );
852
853
  }
853
854
  const nextOffset = typeof offset === "string" ? index : offset + child.key.length + 1;
@@ -877,6 +878,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
877
878
  }
878
879
  }
879
880
  function wrapPropertyName(name) {
881
+ name = decodeURIComponent(name);
880
882
  return /^[^A-Za-z_$]|[^A-Za-z0-9$_]/.test(name) ? `'${name}'` : name;
881
883
  }
882
884
  function renderParamsInfo(params, pathIndex) {
@@ -977,7 +979,10 @@ interface NoMeta {}
977
979
  const routeType = `Route${route.index}`;
978
980
  const pathType = `\`${route.path.replace(
979
981
  /\/\$(\$?)([^\/]*)/,
980
- (_, catchAll, name) => catchAll ? `/:${name || "rest"}*` : `/:${name}`
982
+ (_, catchAll, name) => {
983
+ name = decodeURIComponent(name);
984
+ return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
985
+ }
981
986
  )}\``;
982
987
  const paramsType = (params == null ? void 0 : params.length) ? renderParamsInfoType(params) : "NoParams";
983
988
  let metaType = "NoMeta";
@@ -985,10 +990,10 @@ interface NoMeta {}
985
990
  const isGet = page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"));
986
991
  const isPost = (_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post");
987
992
  if (isGet || isPost) {
988
- const path3 = route.path.replace(
989
- /\$(\$?)([^/]+)/g,
990
- (_, s, name) => s ? `\${...${name}}` : `\${${name}}`
991
- );
993
+ const path3 = route.path.replace(/\$(\$?)([^/]+)/g, (_, catchAll, name) => {
994
+ name = decodeURIComponent(name);
995
+ return catchAll ? `\${...${name}}` : `\${${name}}`;
996
+ });
992
997
  const splatIndex = path3.indexOf("/${...");
993
998
  if (splatIndex >= 0) {
994
999
  const path22 = path3.slice(0, splatIndex) || "/";
@@ -1199,9 +1204,9 @@ function getExportIdentifiers(astProgramNode) {
1199
1204
  }
1200
1205
 
1201
1206
  // src/vite/utils/log.ts
1207
+ import zlib from "node:zlib";
1202
1208
  import Table from "cli-table3";
1203
1209
  import kleur from "kleur";
1204
- import { gzipSizeSync } from "gzip-size";
1205
1210
  import format from "human-format";
1206
1211
  var HttpVerbColors = {
1207
1212
  get: kleur.green,
@@ -1287,17 +1292,20 @@ function computeRouteSize(route, bundle) {
1287
1292
  }
1288
1293
  return [0, 0];
1289
1294
  }
1290
- function byteSize(str) {
1291
- return new Blob([str]).size;
1295
+ function gzipSize(source) {
1296
+ return zlib.gzipSync(source, { level: 9 }).length;
1297
+ }
1298
+ function byteSize(source) {
1299
+ return new Blob([source]).size;
1292
1300
  }
1293
1301
  function computeChunkSize(chunk, bundle, seen = /* @__PURE__ */ new Set()) {
1294
1302
  if (chunk.type === "asset") {
1295
1303
  return [
1296
1304
  byteSize(chunk.source),
1297
- gzipSizeSync(chunk.source)
1305
+ gzipSize(chunk.source)
1298
1306
  ];
1299
1307
  }
1300
- const size = [byteSize(chunk.code), gzipSizeSync(chunk.code)];
1308
+ const size = [byteSize(chunk.code), gzipSize(chunk.code)];
1301
1309
  for (const id of chunk.imports) {
1302
1310
  if (!seen.has(id)) {
1303
1311
  const [bytes, compBytes] = computeChunkSize(bundle[id], bundle, seen);
@@ -1386,7 +1394,7 @@ function markoRun(opts = {}) {
1386
1394
  const filepath = path2.join(typesDir, "routes.d.ts");
1387
1395
  const data = await renderRouteTypeInfo(
1388
1396
  routes,
1389
- path2.relative(typesDir, routesDir),
1397
+ path2.relative(typesDir, resolvedRoutesDir),
1390
1398
  adapter
1391
1399
  );
1392
1400
  if (data !== typesFile || !fs2.existsSync(filepath)) {
@@ -1499,6 +1507,9 @@ function markoRun(opts = {}) {
1499
1507
  define: isBuild ? {
1500
1508
  "process.env.NODE_ENV": "'production'"
1501
1509
  } : void 0,
1510
+ ssr: {
1511
+ noExternal: /@marko\/run/
1512
+ },
1502
1513
  build: {
1503
1514
  emptyOutDir: isSSRBuild
1504
1515
  }
@@ -1736,6 +1747,7 @@ async function resolveAdapter(root, options, log) {
1736
1747
  if (adapter !== void 0) {
1737
1748
  return adapter;
1738
1749
  }
1750
+ const { resolvePackageData } = await import("vite");
1739
1751
  const pkg = resolvePackageData(".", root);
1740
1752
  if (pkg) {
1741
1753
  const dependecies = { ...pkg.data.dependecies, ...pkg.data.devDependencies };
@@ -1771,14 +1783,14 @@ async function parseEnv(envFile) {
1771
1783
  function loadEnv(envFile) {
1772
1784
  config({ path: envFile });
1773
1785
  }
1774
- async function spawnServer(cmd, port = 0, env, cwd = process.cwd(), wait = 3e4) {
1786
+ async function spawnServer(cmd, args = [], port = 0, env, cwd = process.cwd(), wait = 3e4) {
1775
1787
  if (port <= 0) {
1776
1788
  port = await getAvailablePort();
1777
1789
  }
1778
1790
  if (typeof env === "string") {
1779
1791
  env = await parseEnv(env);
1780
1792
  }
1781
- const proc = cp.spawn(cmd, {
1793
+ const proc = cp.spawn(cmd, args, {
1782
1794
  cwd,
1783
1795
  shell: true,
1784
1796
  stdio: "inherit",
@@ -1789,22 +1801,29 @@ async function spawnServer(cmd, port = 0, env, cwd = process.cwd(), wait = 3e4)
1789
1801
  proc.unref();
1790
1802
  proc.kill();
1791
1803
  };
1804
+ try {
1805
+ await waitForServer(port, wait);
1806
+ } catch (err) {
1807
+ close();
1808
+ throw err;
1809
+ }
1810
+ return {
1811
+ port,
1812
+ close
1813
+ };
1814
+ }
1815
+ async function waitForServer(port, wait = 0) {
1792
1816
  let remaining = wait > 0 ? wait : Infinity;
1793
1817
  while (!await isPortInUse(port)) {
1794
1818
  if (remaining >= 100) {
1795
1819
  remaining -= 100;
1796
1820
  await sleep(100);
1797
1821
  } else {
1798
- close();
1799
1822
  throw new Error(
1800
1823
  `site-write: timeout while wating for server to start on port "${port}".`
1801
1824
  );
1802
1825
  }
1803
1826
  }
1804
- return {
1805
- port,
1806
- close
1807
- };
1808
1827
  }
1809
1828
  async function isPortInUse(port) {
1810
1829
  return new Promise((resolve) => {
@@ -1,19 +1,31 @@
1
1
  import type { RoutableFileType, HttpVerb, RoutableFileTypes } from "./constants";
2
2
  import type { Options as MarkoViteOptions } from "@marko/vite";
3
- import type { ResolvedConfig, UserConfig } from "vite";
3
+ import type { ResolvedConfig, UserConfig, InlineConfig } from "vite";
4
+ import type { SpawnedServer } from "./utils/server";
4
5
  export type { RoutableFileType, HttpVerb };
5
6
  export type StartServer = (port?: number) => Promise<void>;
6
7
  export interface AdapterConfig {
7
8
  [name: PropertyKey]: any;
8
9
  }
10
+ export interface StartOptions {
11
+ cwd: string;
12
+ args: string[];
13
+ port?: number;
14
+ envFile?: string;
15
+ }
16
+ export interface StartDevOptions extends StartOptions {
17
+ }
18
+ export interface StartPreviewOptions extends StartOptions {
19
+ dir: string;
20
+ }
9
21
  export interface Adapter {
10
22
  readonly name: string;
11
23
  configure?(config: AdapterConfig): void;
12
24
  pluginOptions?(options: Options): Promise<Options> | Options | undefined;
13
25
  viteConfig?(config: UserConfig): Promise<UserConfig> | UserConfig | undefined;
14
26
  getEntryFile?(): Promise<string> | string;
15
- startDev?(configFile: string, port: number, envFile?: string): Promise<void> | void;
16
- startPreview?(dir: string, entry?: string, port?: number, envFile?: string): Promise<void> | void;
27
+ startDev?(config: InlineConfig, options: StartDevOptions): Promise<SpawnedServer> | SpawnedServer;
28
+ startPreview?(entry: string | undefined, options: StartPreviewOptions): Promise<SpawnedServer> | SpawnedServer;
17
29
  buildEnd?(config: ResolvedConfig, routes: Route[], builtEntries: string[], sourceEntries: string[]): Promise<void> | void;
18
30
  typeInfo?(writer: (data: string) => void): Promise<string> | string;
19
31
  }
@@ -1,9 +1,10 @@
1
1
  export interface SpawnedServer {
2
2
  port: number;
3
- close(): void;
3
+ close(): Promise<void> | void;
4
4
  }
5
5
  export declare function parseEnv(envFile: string): Promise<import("dotenv").DotenvParseOutput | undefined>;
6
6
  export declare function loadEnv(envFile: string): void;
7
- export declare function spawnServer(cmd: string, port?: number, env?: string | Record<string, string>, cwd?: string, wait?: number): Promise<SpawnedServer>;
7
+ export declare function spawnServer(cmd: string, args?: string[], port?: number, env?: string | Record<string, string>, cwd?: string, wait?: number): Promise<SpawnedServer>;
8
+ export declare function waitForServer(port: number, wait?: number): Promise<void>;
8
9
  export declare function isPortInUse(port: number): Promise<boolean>;
9
10
  export declare function getAvailablePort(): Promise<number>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marko/run",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "The Marko application framework.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/marko-js/run/tree/main/packages/run",
@@ -20,11 +20,10 @@
20
20
  "marko-run": "./dist/cli/index.mjs"
21
21
  },
22
22
  "scripts": {
23
- "mocha": "cross-env NODE_ENV=test mocha \"./src/**/__tests__/*.test.ts\"",
24
- "test": "npm run mocha",
25
- "test:watch": "npm run mocha -- --watch",
23
+ "test": "cross-env NODE_ENV=test mocha \"./src/**/__tests__/*.test.ts\"",
24
+ "test:watch": "npm test -- --watch",
26
25
  "test:inspect": "npm test -- --inspect",
27
- "test:update": "npm run mocha -- --update",
26
+ "test:update": "npm test -- --update",
28
27
  "build": "tsc -b && tsx scripts/build.ts"
29
28
  },
30
29
  "exports": {
@@ -83,17 +82,26 @@
83
82
  },
84
83
  "devDependencies": {
85
84
  "@babel/types": "^7.19.0",
85
+ "@marko/fixture-snapshots": "^2.1.7",
86
+ "@marko/testing-library": "^6.1.2",
86
87
  "@types/glob": "^8.0.1",
87
88
  "@types/human-format": "^1.0.0",
89
+ "@types/jsdom": "^21.1.0",
88
90
  "@types/mocha": "^9.1.1",
89
91
  "@types/node": "^18.11.18",
90
92
  "acorn": "^8.8.0",
91
93
  "cross-env": "^7.0.3",
92
94
  "esbuild": "^0.15.7",
95
+ "jsdom": "^21.1.1",
93
96
  "marko": "^5.23.0",
94
- "mocha": "^10.0.0",
97
+ "mocha": "^10.2.0",
95
98
  "mocha-snap": "^4.3.0",
99
+ "playwright": "^1.29.1",
96
100
  "prettier": "^2.7.1",
101
+ "ts-mocha": "^10.0.0",
102
+ "ts-node": "^10.9.1",
103
+ "tslib": "^2.5.0",
104
+ "tsm": "^2.3.0",
97
105
  "tsx": "^3.9.0",
98
106
  "typescript": "^4.7.4"
99
107
  },
@@ -103,9 +111,9 @@
103
111
  "compression": "^1.7.4",
104
112
  "dotenv": "^16.0.3",
105
113
  "glob": "^8.1.0",
106
- "gzip-size": "^7.0.0",
107
114
  "human-format": "^1.0.0",
108
115
  "kleur": "^4.1.5",
116
+ "parse-node-args": "^1.1.2",
109
117
  "sade": "^1.8.1",
110
118
  "serve-static": "^1.15.0",
111
119
  "strip-ansi": "^7.0.1",