@marko/run 0.1.3 → 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;
@@ -680,17 +680,7 @@ function renderRouter(routes, options = {
680
680
  `import page${key} from '${virtualFilePrefix}/${markoRunFilePrefix}special__${key}.marko${serverEntryQuery}';`
681
681
  );
682
682
  }
683
- writer.writeLines(
684
- `
685
- const page404ResponseInit = {
686
- status: 404,
687
- headers: { "content-type": "text/html;charset=UTF-8" },
688
- };
689
- const page500ResponseInit = {
690
- status: 404,
691
- headers: { "content-type": "text/html;charset=UTF-8" },
692
- };`
693
- ).writeBlockStart(`export function match(method, pathname) {`).writeLines(
683
+ writer.writeLines("").writeBlockStart(`export function match(method, pathname) {`).writeLines(
694
684
  `if (!pathname) {
695
685
  pathname = '/';
696
686
  } else if (pathname.charAt(0) !== '/') {
@@ -722,8 +712,16 @@ export async function invoke(route, request, platform, url) {
722
712
  throw error;
723
713
  }
724
714
  }
725
- `).indent = 2;
715
+ `);
726
716
  if (routes.special[RoutableFileTypes.NotFound]) {
717
+ writer.indent = 2;
718
+ imports.writeLines(
719
+ `
720
+ const page404ResponseInit = {
721
+ status: 404,
722
+ headers: { "content-type": "text/html;charset=UTF-8" },
723
+ };`
724
+ );
727
725
  writer.write(
728
726
  ` } else {
729
727
  }
@@ -733,11 +731,17 @@ export async function invoke(route, request, platform, url) {
733
731
  `
734
732
  );
735
733
  } else {
734
+ writer.indent = 3;
736
735
  writer.writeBlockEnd("}");
737
736
  }
738
737
  writer.indent--;
739
738
  writer.writeBlockStart(`} catch (error) {`);
740
739
  if (routes.special[RoutableFileTypes.Error]) {
740
+ imports.writeLines(`
741
+ const page500ResponseInit = {
742
+ status: 404,
743
+ headers: { "content-type": "text/html;charset=UTF-8" },
744
+ };`);
741
745
  writer.writeBlockStart(
742
746
  `if (context.request.headers.get('Accept')?.includes('text/html')) {`
743
747
  ).writeLines(
@@ -825,7 +829,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
825
829
  if (terminal || (dynamic == null ? void 0 : dynamic.route)) {
826
830
  closeCount++;
827
831
  writer.writeBlockStart(`if (!${index} || ${index} === len) {`);
828
- let value = `pathname.slice(${offset}, ${index} ? -1 : len)`;
832
+ let value = `decodeURIComponent(pathname.slice(${offset}, ${index} ? -1 : len))`;
829
833
  if (dynamic == null ? void 0 : dynamic.route) {
830
834
  const segment = `s${next}`;
831
835
  writer.writeLines(`const ${segment} = ${value};`);
@@ -864,7 +868,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
864
868
  writer.writeBlockStart(`if (${index} && ${index} !== len) {`);
865
869
  closeCount++;
866
870
  }
867
- let value = `pathname.slice(${offset}, ${index} - 1)`;
871
+ let value = `decodeURIComponent(pathname.slice(${offset}, ${index} - 1))`;
868
872
  if ((dynamic == null ? void 0 : dynamic.static) || (dynamic == null ? void 0 : dynamic.dynamic)) {
869
873
  const segment = `s${next}`;
870
874
  writer.writeLines(`const ${segment} = ${value};`);
@@ -876,11 +880,12 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
876
880
  writer.writeBlockStart(`switch (${value}.toLowerCase()) {`);
877
881
  }
878
882
  for (const child of children) {
883
+ const decodedKey = decodeURIComponent(child.key);
879
884
  if (useSwitch) {
880
- writer.writeBlockStart(`case '${child.key}': {`);
885
+ writer.writeBlockStart(`case '${decodedKey}': {`);
881
886
  } else {
882
887
  writer.writeBlockStart(
883
- `if (${value}.toLowerCase() === '${child.key}') {`
888
+ `if (${value}.toLowerCase() === '${decodedKey}') {`
884
889
  );
885
890
  }
886
891
  const nextOffset = typeof offset === "string" ? index : offset + child.key.length + 1;
@@ -910,6 +915,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
910
915
  }
911
916
  }
912
917
  function wrapPropertyName(name) {
918
+ name = decodeURIComponent(name);
913
919
  return /^[^A-Za-z_$]|[^A-Za-z0-9$_]/.test(name) ? `'${name}'` : name;
914
920
  }
915
921
  function renderParamsInfo(params, pathIndex) {
@@ -922,7 +928,7 @@ function renderParamsInfo(params, pathIndex) {
922
928
  for (const { name, index } of params) {
923
929
  if (index >= 0) {
924
930
  result += `${sep} ${wrapPropertyName(name)}: s${index + 1}`;
925
- sep || (sep = ",");
931
+ sep = ",";
926
932
  } else if (pathIndex) {
927
933
  catchAll = name;
928
934
  }
@@ -1010,7 +1016,10 @@ interface NoMeta {}
1010
1016
  const routeType = `Route${route.index}`;
1011
1017
  const pathType = `\`${route.path.replace(
1012
1018
  /\/\$(\$?)([^\/]*)/,
1013
- (_, catchAll, name) => catchAll ? `/:${name || "rest"}*` : `/:${name}`
1019
+ (_, catchAll, name) => {
1020
+ name = decodeURIComponent(name);
1021
+ return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
1022
+ }
1014
1023
  )}\``;
1015
1024
  const paramsType = (params == null ? void 0 : params.length) ? renderParamsInfoType(params) : "NoParams";
1016
1025
  let metaType = "NoMeta";
@@ -1018,10 +1027,10 @@ interface NoMeta {}
1018
1027
  const isGet = page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"));
1019
1028
  const isPost = (_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post");
1020
1029
  if (isGet || isPost) {
1021
- const path3 = route.path.replace(
1022
- /\$(\$?)([^/]+)/g,
1023
- (_, s, name) => s ? `\${...${name}}` : `\${${name}}`
1024
- );
1030
+ const path3 = route.path.replace(/\$(\$?)([^/]+)/g, (_, catchAll, name) => {
1031
+ name = decodeURIComponent(name);
1032
+ return catchAll ? `\${...${name}}` : `\${${name}}`;
1033
+ });
1025
1034
  const splatIndex = path3.indexOf("/${...");
1026
1035
  if (splatIndex >= 0) {
1027
1036
  const path22 = path3.slice(0, splatIndex) || "/";
@@ -1232,9 +1241,9 @@ function getExportIdentifiers(astProgramNode) {
1232
1241
  }
1233
1242
 
1234
1243
  // src/vite/utils/log.ts
1244
+ var import_node_zlib = __toESM(require("node:zlib"), 1);
1235
1245
  var import_cli_table3 = __toESM(require("cli-table3"), 1);
1236
1246
  var import_kleur = __toESM(require("kleur"), 1);
1237
- var import_gzip_size = require("gzip-size");
1238
1247
  var import_human_format = __toESM(require("human-format"), 1);
1239
1248
  var HttpVerbColors = {
1240
1249
  get: import_kleur.default.green,
@@ -1320,17 +1329,20 @@ function computeRouteSize(route, bundle) {
1320
1329
  }
1321
1330
  return [0, 0];
1322
1331
  }
1323
- function byteSize(str) {
1324
- 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;
1325
1337
  }
1326
1338
  function computeChunkSize(chunk, bundle, seen = /* @__PURE__ */ new Set()) {
1327
1339
  if (chunk.type === "asset") {
1328
1340
  return [
1329
1341
  byteSize(chunk.source),
1330
- (0, import_gzip_size.gzipSizeSync)(chunk.source)
1342
+ gzipSize(chunk.source)
1331
1343
  ];
1332
1344
  }
1333
- const size = [byteSize(chunk.code), (0, import_gzip_size.gzipSizeSync)(chunk.code)];
1345
+ const size = [byteSize(chunk.code), gzipSize(chunk.code)];
1334
1346
  for (const id of chunk.imports) {
1335
1347
  if (!seen.has(id)) {
1336
1348
  const [bytes, compBytes] = computeChunkSize(bundle[id], bundle, seen);
@@ -1420,7 +1432,7 @@ function markoRun(opts = {}) {
1420
1432
  const filepath = import_path2.default.join(typesDir, "routes.d.ts");
1421
1433
  const data = await renderRouteTypeInfo(
1422
1434
  routes,
1423
- import_path2.default.relative(typesDir, routesDir),
1435
+ import_path2.default.relative(typesDir, resolvedRoutesDir),
1424
1436
  adapter
1425
1437
  );
1426
1438
  if (data !== typesFile || !import_fs2.default.existsSync(filepath)) {
@@ -1515,7 +1527,7 @@ function markoRun(opts = {}) {
1515
1527
  compiler ?? (compiler = await import(opts.compiler || "@marko/compiler"));
1516
1528
  compiler.taglib.register("@marko/run", {
1517
1529
  "<*>": {
1518
- template: import_path2.default.resolve(
1530
+ transform: import_path2.default.resolve(
1519
1531
  __dirname,
1520
1532
  "../components/src-attributes-transformer.cjs"
1521
1533
  )
@@ -1533,6 +1545,9 @@ function markoRun(opts = {}) {
1533
1545
  define: isBuild ? {
1534
1546
  "process.env.NODE_ENV": "'production'"
1535
1547
  } : void 0,
1548
+ ssr: {
1549
+ noExternal: /@marko\/run/
1550
+ },
1536
1551
  build: {
1537
1552
  emptyOutDir: isSSRBuild
1538
1553
  }
@@ -1770,7 +1785,8 @@ async function resolveAdapter(root, options, log) {
1770
1785
  if (adapter !== void 0) {
1771
1786
  return adapter;
1772
1787
  }
1773
- const pkg = (0, import_vite.resolvePackageData)(".", root);
1788
+ const { resolvePackageData } = await import("vite");
1789
+ const pkg = resolvePackageData(".", root);
1774
1790
  if (pkg) {
1775
1791
  const dependecies = { ...pkg.data.dependecies, ...pkg.data.devDependencies };
1776
1792
  for (const name of Object.keys(dependecies)) {
@@ -1805,14 +1821,14 @@ async function parseEnv(envFile) {
1805
1821
  function loadEnv(envFile) {
1806
1822
  (0, import_dotenv.config)({ path: envFile });
1807
1823
  }
1808
- 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) {
1809
1825
  if (port <= 0) {
1810
1826
  port = await getAvailablePort();
1811
1827
  }
1812
1828
  if (typeof env === "string") {
1813
1829
  env = await parseEnv(env);
1814
1830
  }
1815
- const proc = import_child_process.default.spawn(cmd, {
1831
+ const proc = import_child_process.default.spawn(cmd, args, {
1816
1832
  cwd,
1817
1833
  shell: true,
1818
1834
  stdio: "inherit",
@@ -1823,22 +1839,29 @@ async function spawnServer(cmd, port = 0, env, cwd = process.cwd(), wait = 3e4)
1823
1839
  proc.unref();
1824
1840
  proc.kill();
1825
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) {
1826
1854
  let remaining = wait > 0 ? wait : Infinity;
1827
1855
  while (!await isPortInUse(port)) {
1828
1856
  if (remaining >= 100) {
1829
1857
  remaining -= 100;
1830
1858
  await sleep(100);
1831
1859
  } else {
1832
- close();
1833
1860
  throw new Error(
1834
1861
  `site-write: timeout while wating for server to start on port "${port}".`
1835
1862
  );
1836
1863
  }
1837
1864
  }
1838
- return {
1839
- port,
1840
- close
1841
- };
1842
1865
  }
1843
1866
  async function isPortInUse(port) {
1844
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
@@ -643,17 +643,7 @@ function renderRouter(routes, options = {
643
643
  `import page${key} from '${virtualFilePrefix}/${markoRunFilePrefix}special__${key}.marko${serverEntryQuery}';`
644
644
  );
645
645
  }
646
- writer.writeLines(
647
- `
648
- const page404ResponseInit = {
649
- status: 404,
650
- headers: { "content-type": "text/html;charset=UTF-8" },
651
- };
652
- const page500ResponseInit = {
653
- status: 404,
654
- headers: { "content-type": "text/html;charset=UTF-8" },
655
- };`
656
- ).writeBlockStart(`export function match(method, pathname) {`).writeLines(
646
+ writer.writeLines("").writeBlockStart(`export function match(method, pathname) {`).writeLines(
657
647
  `if (!pathname) {
658
648
  pathname = '/';
659
649
  } else if (pathname.charAt(0) !== '/') {
@@ -685,8 +675,16 @@ export async function invoke(route, request, platform, url) {
685
675
  throw error;
686
676
  }
687
677
  }
688
- `).indent = 2;
678
+ `);
689
679
  if (routes.special[RoutableFileTypes.NotFound]) {
680
+ writer.indent = 2;
681
+ imports.writeLines(
682
+ `
683
+ const page404ResponseInit = {
684
+ status: 404,
685
+ headers: { "content-type": "text/html;charset=UTF-8" },
686
+ };`
687
+ );
690
688
  writer.write(
691
689
  ` } else {
692
690
  }
@@ -696,11 +694,17 @@ export async function invoke(route, request, platform, url) {
696
694
  `
697
695
  );
698
696
  } else {
697
+ writer.indent = 3;
699
698
  writer.writeBlockEnd("}");
700
699
  }
701
700
  writer.indent--;
702
701
  writer.writeBlockStart(`} catch (error) {`);
703
702
  if (routes.special[RoutableFileTypes.Error]) {
703
+ imports.writeLines(`
704
+ const page500ResponseInit = {
705
+ status: 404,
706
+ headers: { "content-type": "text/html;charset=UTF-8" },
707
+ };`);
704
708
  writer.writeBlockStart(
705
709
  `if (context.request.headers.get('Accept')?.includes('text/html')) {`
706
710
  ).writeLines(
@@ -788,7 +792,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
788
792
  if (terminal || (dynamic == null ? void 0 : dynamic.route)) {
789
793
  closeCount++;
790
794
  writer.writeBlockStart(`if (!${index} || ${index} === len) {`);
791
- let value = `pathname.slice(${offset}, ${index} ? -1 : len)`;
795
+ let value = `decodeURIComponent(pathname.slice(${offset}, ${index} ? -1 : len))`;
792
796
  if (dynamic == null ? void 0 : dynamic.route) {
793
797
  const segment = `s${next}`;
794
798
  writer.writeLines(`const ${segment} = ${value};`);
@@ -827,7 +831,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
827
831
  writer.writeBlockStart(`if (${index} && ${index} !== len) {`);
828
832
  closeCount++;
829
833
  }
830
- let value = `pathname.slice(${offset}, ${index} - 1)`;
834
+ let value = `decodeURIComponent(pathname.slice(${offset}, ${index} - 1))`;
831
835
  if ((dynamic == null ? void 0 : dynamic.static) || (dynamic == null ? void 0 : dynamic.dynamic)) {
832
836
  const segment = `s${next}`;
833
837
  writer.writeLines(`const ${segment} = ${value};`);
@@ -839,11 +843,12 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
839
843
  writer.writeBlockStart(`switch (${value}.toLowerCase()) {`);
840
844
  }
841
845
  for (const child of children) {
846
+ const decodedKey = decodeURIComponent(child.key);
842
847
  if (useSwitch) {
843
- writer.writeBlockStart(`case '${child.key}': {`);
848
+ writer.writeBlockStart(`case '${decodedKey}': {`);
844
849
  } else {
845
850
  writer.writeBlockStart(
846
- `if (${value}.toLowerCase() === '${child.key}') {`
851
+ `if (${value}.toLowerCase() === '${decodedKey}') {`
847
852
  );
848
853
  }
849
854
  const nextOffset = typeof offset === "string" ? index : offset + child.key.length + 1;
@@ -873,6 +878,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
873
878
  }
874
879
  }
875
880
  function wrapPropertyName(name) {
881
+ name = decodeURIComponent(name);
876
882
  return /^[^A-Za-z_$]|[^A-Za-z0-9$_]/.test(name) ? `'${name}'` : name;
877
883
  }
878
884
  function renderParamsInfo(params, pathIndex) {
@@ -885,7 +891,7 @@ function renderParamsInfo(params, pathIndex) {
885
891
  for (const { name, index } of params) {
886
892
  if (index >= 0) {
887
893
  result += `${sep} ${wrapPropertyName(name)}: s${index + 1}`;
888
- sep || (sep = ",");
894
+ sep = ",";
889
895
  } else if (pathIndex) {
890
896
  catchAll = name;
891
897
  }
@@ -973,7 +979,10 @@ interface NoMeta {}
973
979
  const routeType = `Route${route.index}`;
974
980
  const pathType = `\`${route.path.replace(
975
981
  /\/\$(\$?)([^\/]*)/,
976
- (_, catchAll, name) => catchAll ? `/:${name || "rest"}*` : `/:${name}`
982
+ (_, catchAll, name) => {
983
+ name = decodeURIComponent(name);
984
+ return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
985
+ }
977
986
  )}\``;
978
987
  const paramsType = (params == null ? void 0 : params.length) ? renderParamsInfoType(params) : "NoParams";
979
988
  let metaType = "NoMeta";
@@ -981,10 +990,10 @@ interface NoMeta {}
981
990
  const isGet = page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"));
982
991
  const isPost = (_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post");
983
992
  if (isGet || isPost) {
984
- const path3 = route.path.replace(
985
- /\$(\$?)([^/]+)/g,
986
- (_, s, name) => s ? `\${...${name}}` : `\${${name}}`
987
- );
993
+ const path3 = route.path.replace(/\$(\$?)([^/]+)/g, (_, catchAll, name) => {
994
+ name = decodeURIComponent(name);
995
+ return catchAll ? `\${...${name}}` : `\${${name}}`;
996
+ });
988
997
  const splatIndex = path3.indexOf("/${...");
989
998
  if (splatIndex >= 0) {
990
999
  const path22 = path3.slice(0, splatIndex) || "/";
@@ -1195,9 +1204,9 @@ function getExportIdentifiers(astProgramNode) {
1195
1204
  }
1196
1205
 
1197
1206
  // src/vite/utils/log.ts
1207
+ import zlib from "node:zlib";
1198
1208
  import Table from "cli-table3";
1199
1209
  import kleur from "kleur";
1200
- import { gzipSizeSync } from "gzip-size";
1201
1210
  import format from "human-format";
1202
1211
  var HttpVerbColors = {
1203
1212
  get: kleur.green,
@@ -1283,17 +1292,20 @@ function computeRouteSize(route, bundle) {
1283
1292
  }
1284
1293
  return [0, 0];
1285
1294
  }
1286
- function byteSize(str) {
1287
- 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;
1288
1300
  }
1289
1301
  function computeChunkSize(chunk, bundle, seen = /* @__PURE__ */ new Set()) {
1290
1302
  if (chunk.type === "asset") {
1291
1303
  return [
1292
1304
  byteSize(chunk.source),
1293
- gzipSizeSync(chunk.source)
1305
+ gzipSize(chunk.source)
1294
1306
  ];
1295
1307
  }
1296
- const size = [byteSize(chunk.code), gzipSizeSync(chunk.code)];
1308
+ const size = [byteSize(chunk.code), gzipSize(chunk.code)];
1297
1309
  for (const id of chunk.imports) {
1298
1310
  if (!seen.has(id)) {
1299
1311
  const [bytes, compBytes] = computeChunkSize(bundle[id], bundle, seen);
@@ -1382,7 +1394,7 @@ function markoRun(opts = {}) {
1382
1394
  const filepath = path2.join(typesDir, "routes.d.ts");
1383
1395
  const data = await renderRouteTypeInfo(
1384
1396
  routes,
1385
- path2.relative(typesDir, routesDir),
1397
+ path2.relative(typesDir, resolvedRoutesDir),
1386
1398
  adapter
1387
1399
  );
1388
1400
  if (data !== typesFile || !fs2.existsSync(filepath)) {
@@ -1477,7 +1489,7 @@ function markoRun(opts = {}) {
1477
1489
  compiler ?? (compiler = await import(opts.compiler || "@marko/compiler"));
1478
1490
  compiler.taglib.register("@marko/run", {
1479
1491
  "<*>": {
1480
- template: path2.resolve(
1492
+ transform: path2.resolve(
1481
1493
  __dirname,
1482
1494
  "../components/src-attributes-transformer.cjs"
1483
1495
  )
@@ -1495,6 +1507,9 @@ function markoRun(opts = {}) {
1495
1507
  define: isBuild ? {
1496
1508
  "process.env.NODE_ENV": "'production'"
1497
1509
  } : void 0,
1510
+ ssr: {
1511
+ noExternal: /@marko\/run/
1512
+ },
1498
1513
  build: {
1499
1514
  emptyOutDir: isSSRBuild
1500
1515
  }
@@ -1732,6 +1747,7 @@ async function resolveAdapter(root, options, log) {
1732
1747
  if (adapter !== void 0) {
1733
1748
  return adapter;
1734
1749
  }
1750
+ const { resolvePackageData } = await import("vite");
1735
1751
  const pkg = resolvePackageData(".", root);
1736
1752
  if (pkg) {
1737
1753
  const dependecies = { ...pkg.data.dependecies, ...pkg.data.devDependencies };
@@ -1767,14 +1783,14 @@ async function parseEnv(envFile) {
1767
1783
  function loadEnv(envFile) {
1768
1784
  config({ path: envFile });
1769
1785
  }
1770
- 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) {
1771
1787
  if (port <= 0) {
1772
1788
  port = await getAvailablePort();
1773
1789
  }
1774
1790
  if (typeof env === "string") {
1775
1791
  env = await parseEnv(env);
1776
1792
  }
1777
- const proc = cp.spawn(cmd, {
1793
+ const proc = cp.spawn(cmd, args, {
1778
1794
  cwd,
1779
1795
  shell: true,
1780
1796
  stdio: "inherit",
@@ -1785,22 +1801,29 @@ async function spawnServer(cmd, port = 0, env, cwd = process.cwd(), wait = 3e4)
1785
1801
  proc.unref();
1786
1802
  proc.kill();
1787
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) {
1788
1816
  let remaining = wait > 0 ? wait : Infinity;
1789
1817
  while (!await isPortInUse(port)) {
1790
1818
  if (remaining >= 100) {
1791
1819
  remaining -= 100;
1792
1820
  await sleep(100);
1793
1821
  } else {
1794
- close();
1795
1822
  throw new Error(
1796
1823
  `site-write: timeout while wating for server to start on port "${port}".`
1797
1824
  );
1798
1825
  }
1799
1826
  }
1800
- return {
1801
- port,
1802
- close
1803
- };
1804
1827
  }
1805
1828
  async function isPortInUse(port) {
1806
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.3",
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",