@marko/run 0.1.5 → 0.1.6

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.
@@ -0,0 +1,36 @@
1
+ import { createServer } from "vite";
2
+
3
+ let activeDevServers;
4
+
5
+ process
6
+ .on("message", (message) => {
7
+ switch (message.type) {
8
+ case "start":
9
+ return start(message.entry, message.config);
10
+ case "shutdown":
11
+ return shutdown();
12
+ }
13
+ })
14
+ .send("ready");
15
+
16
+ async function start(entry, config) {
17
+ let changed = false;
18
+ const loader = await createServer(config);
19
+ ({ activeDevServers } = await loader.ssrLoadModule("@marko/run/adapter"));
20
+ await loader.ssrLoadModule(entry);
21
+
22
+ loader.watcher.on("change", (path) => {
23
+ if (!changed && loader.moduleGraph.getModulesByFile(path)) {
24
+ changed = true;
25
+ process.send("restart");
26
+ }
27
+ });
28
+ }
29
+
30
+ function shutdown() {
31
+ if (activeDevServers) {
32
+ for (const devServer of activeDevServers) {
33
+ devServer.ws.send({ type: "full-reload" });
34
+ }
35
+ }
36
+ }
@@ -1,4 +1,6 @@
1
- import { InlineConfig, ViteDevServer } from "vite";
1
+ import { type InlineConfig, type ViteDevServer } from "vite";
2
2
  import type { NodeMiddleware } from "./middleware";
3
+ export declare const activeDevServers: Set<ViteDevServer>;
3
4
  export declare function createViteDevMiddleware<T>(devServer: ViteDevServer, load: (prev: T | undefined) => Promise<T>, factory: (value: T) => NodeMiddleware): NodeMiddleware;
5
+ export declare function createViteDevServer(config?: InlineConfig): Promise<ViteDevServer>;
4
6
  export declare function createDevServer(config?: InlineConfig): Promise<ViteDevServer>;
@@ -26,8 +26,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
26
26
  // src/adapter/index.ts
27
27
  var adapter_exports = {};
28
28
  __export(adapter_exports, {
29
+ activeDevServers: () => activeDevServers,
29
30
  createDevServer: () => createDevServer,
30
31
  createViteDevMiddleware: () => createViteDevMiddleware,
32
+ createViteDevServer: () => createViteDevServer,
31
33
  default: () => adapter
32
34
  });
33
35
  module.exports = __toCommonJS(adapter_exports);
@@ -37,6 +39,7 @@ var import_url = require("url");
37
39
  // src/adapter/dev-server.ts
38
40
  var import_vite = require("vite");
39
41
  var import_strip_ansi = __toESM(require("strip-ansi"), 1);
42
+ var activeDevServers = /* @__PURE__ */ new Set();
40
43
  function createViteDevMiddleware(devServer, load, factory) {
41
44
  let value;
42
45
  let middleware;
@@ -59,12 +62,22 @@ function createViteDevMiddleware(devServer, load, factory) {
59
62
  }
60
63
  };
61
64
  }
62
- async function createDevServer(config2) {
65
+ async function createViteDevServer(config2) {
63
66
  const devServer = await (0, import_vite.createServer)({
64
67
  ...config2,
65
68
  appType: "custom",
66
69
  server: { middlewareMode: true }
67
70
  });
71
+ const originalClose = devServer.close;
72
+ devServer.close = () => {
73
+ activeDevServers.delete(devServer);
74
+ return originalClose.call(devServer);
75
+ };
76
+ activeDevServers.add(devServer);
77
+ return devServer;
78
+ }
79
+ async function createDevServer(config2) {
80
+ const devServer = await createViteDevServer(config2);
68
81
  const { createMiddleware } = await devServer.ssrLoadModule(
69
82
  "@marko/run/adapter/middleware"
70
83
  );
@@ -82,6 +95,7 @@ var import_net = __toESM(require("net"), 1);
82
95
  var import_child_process = __toESM(require("child_process"), 1);
83
96
  var import_dotenv = require("dotenv");
84
97
  var import_fs = __toESM(require("fs"), 1);
98
+ var import_cluster = __toESM(require("cluster"), 1);
85
99
  async function parseEnv(envFile) {
86
100
  if (import_fs.default.existsSync(envFile)) {
87
101
  const content = await import_fs.default.promises.readFile(envFile, "utf8");
@@ -120,9 +134,37 @@ async function spawnServer(cmd, args = [], port = 0, env, cwd = process.cwd(), w
120
134
  close
121
135
  };
122
136
  }
137
+ async function spawnServerWorker(module2, args = [], port = 0, env) {
138
+ if (port <= 0) {
139
+ port = await getAvailablePort();
140
+ }
141
+ if (typeof env === "string") {
142
+ env = await parseEnv(env);
143
+ }
144
+ const originalExec = import_cluster.default.settings.exec;
145
+ const originalArgs = import_cluster.default.settings.execArgv;
146
+ try {
147
+ import_cluster.default.settings.exec = module2;
148
+ import_cluster.default.settings.execArgv = args;
149
+ const worker = import_cluster.default.fork({ ...env, NODE_ENV: "development", ...process.env, PORT: `${port}` });
150
+ return new Promise((resolve) => {
151
+ function ready(message) {
152
+ if (message === "ready") {
153
+ worker.off("message", ready);
154
+ resolve(worker);
155
+ }
156
+ }
157
+ worker.on("message", ready);
158
+ });
159
+ } finally {
160
+ import_cluster.default.settings.exec = originalExec;
161
+ import_cluster.default.settings.execArgv = originalArgs;
162
+ }
163
+ }
123
164
  async function waitForServer(port, wait = 0) {
124
165
  let remaining = wait > 0 ? wait : Infinity;
125
- while (!await isPortInUse(port)) {
166
+ let connection;
167
+ while (!(connection = await getConnection(port))) {
126
168
  if (remaining >= 100) {
127
169
  remaining -= 100;
128
170
  await sleep(100);
@@ -132,14 +174,16 @@ async function waitForServer(port, wait = 0) {
132
174
  );
133
175
  }
134
176
  }
177
+ return connection;
135
178
  }
136
- async function isPortInUse(port) {
179
+ async function getConnection(port) {
137
180
  return new Promise((resolve) => {
138
- const connection = import_net.default.connect(port).setNoDelay(true).setKeepAlive(false).on("error", () => done(false)).on("connect", () => done(true));
139
- function done(connected) {
181
+ const connection = import_net.default.connect(port).setNoDelay(true).setKeepAlive(false).on("error", () => {
140
182
  connection.end();
141
- resolve(connected);
142
- }
183
+ resolve(null);
184
+ }).on("connect", () => {
185
+ resolve(connection);
186
+ });
143
187
  });
144
188
  }
145
189
  async function getAvailablePort() {
@@ -158,20 +202,56 @@ function sleep(ms) {
158
202
  var import_parse_node_args = __toESM(require("parse-node-args"), 1);
159
203
  var import_meta = {};
160
204
  var __dirname = (0, import_url.fileURLToPath)(new URL(".", import_meta.url));
205
+ var defaultEntry = import_path.default.join(__dirname, "default-entry");
206
+ var loadDevWorker = import_path.default.join(__dirname, "load-dev-worker.mjs");
161
207
  function adapter() {
162
208
  return {
163
209
  name: "base-adapter",
164
210
  async getEntryFile() {
165
- const entry = import_path.default.join(__dirname, "default-entry");
166
- return entry;
211
+ return defaultEntry;
167
212
  },
168
- async startDev(config2, { port = 3e3, envFile }) {
169
- const { root, configFile } = config2;
213
+ async startDev(entry, config2, options) {
214
+ const { port = 3e3, envFile } = options;
215
+ if (entry) {
216
+ const { nodeArgs } = (0, import_parse_node_args.default)(options.args);
217
+ let worker;
218
+ async function start() {
219
+ const nextWorker = await spawnServerWorker(
220
+ loadDevWorker,
221
+ nodeArgs,
222
+ port,
223
+ envFile
224
+ );
225
+ nextWorker.on("message", (messsage) => {
226
+ if (messsage === "restart") {
227
+ start();
228
+ }
229
+ }).send({ type: "start", entry, config: config2 });
230
+ await waitForWorker(nextWorker, port);
231
+ if (worker) {
232
+ const prevWorker = worker;
233
+ let timeout;
234
+ worker.once("disconnect", () => {
235
+ clearTimeout(timeout);
236
+ });
237
+ worker.send({ type: "shutdown" });
238
+ worker.disconnect();
239
+ timeout = setTimeout(() => {
240
+ prevWorker.kill();
241
+ }, 2e3);
242
+ }
243
+ worker = nextWorker;
244
+ }
245
+ await start();
246
+ return {
247
+ port,
248
+ close() {
249
+ worker.kill();
250
+ }
251
+ };
252
+ }
253
+ const devServer = await createDevServer(config2);
170
254
  envFile && await loadEnv(envFile);
171
- const devServer = await createDevServer({
172
- root,
173
- configFile
174
- });
175
255
  return new Promise((resolve) => {
176
256
  const listener = devServer.middlewares.listen(port, () => {
177
257
  const address = listener.address();
@@ -195,8 +275,21 @@ function adapter() {
195
275
  }
196
276
  };
197
277
  }
278
+ async function waitForWorker(worker, port) {
279
+ return new Promise((resolve) => {
280
+ function listening(address) {
281
+ if (address.port === port) {
282
+ worker.off("listening", listening);
283
+ resolve();
284
+ }
285
+ }
286
+ worker.on("listening", listening);
287
+ });
288
+ }
198
289
  // Annotate the CommonJS export names for ESM import in node:
199
290
  0 && (module.exports = {
291
+ activeDevServers,
200
292
  createDevServer,
201
- createViteDevMiddleware
293
+ createViteDevMiddleware,
294
+ createViteDevServer
202
295
  });
@@ -1,6 +1,6 @@
1
1
  import type { Adapter } from "../vite";
2
2
  import { type SpawnedServer } from "../vite/utils/server";
3
- export { createDevServer, createViteDevMiddleware } from "./dev-server";
3
+ export { activeDevServers, createDevServer, createViteDevServer, createViteDevMiddleware, } from "./dev-server";
4
4
  export type { Adapter, SpawnedServer };
5
5
  export type { NodePlatformInfo } from "./middleware";
6
6
  export default function adapter(): Adapter;
@@ -5,6 +5,7 @@ import { fileURLToPath } from "url";
5
5
  // src/adapter/dev-server.ts
6
6
  import { createServer } from "vite";
7
7
  import stripAnsi from "strip-ansi";
8
+ var activeDevServers = /* @__PURE__ */ new Set();
8
9
  function createViteDevMiddleware(devServer, load, factory) {
9
10
  let value;
10
11
  let middleware;
@@ -27,12 +28,22 @@ function createViteDevMiddleware(devServer, load, factory) {
27
28
  }
28
29
  };
29
30
  }
30
- async function createDevServer(config2) {
31
+ async function createViteDevServer(config2) {
31
32
  const devServer = await createServer({
32
33
  ...config2,
33
34
  appType: "custom",
34
35
  server: { middlewareMode: true }
35
36
  });
37
+ const originalClose = devServer.close;
38
+ devServer.close = () => {
39
+ activeDevServers.delete(devServer);
40
+ return originalClose.call(devServer);
41
+ };
42
+ activeDevServers.add(devServer);
43
+ return devServer;
44
+ }
45
+ async function createDevServer(config2) {
46
+ const devServer = await createViteDevServer(config2);
36
47
  const { createMiddleware } = await devServer.ssrLoadModule(
37
48
  "@marko/run/adapter/middleware"
38
49
  );
@@ -50,6 +61,7 @@ import net from "net";
50
61
  import cp from "child_process";
51
62
  import { parse, config } from "dotenv";
52
63
  import fs from "fs";
64
+ import cluster from "cluster";
53
65
  async function parseEnv(envFile) {
54
66
  if (fs.existsSync(envFile)) {
55
67
  const content = await fs.promises.readFile(envFile, "utf8");
@@ -88,9 +100,37 @@ async function spawnServer(cmd, args = [], port = 0, env, cwd = process.cwd(), w
88
100
  close
89
101
  };
90
102
  }
103
+ async function spawnServerWorker(module, args = [], port = 0, env) {
104
+ if (port <= 0) {
105
+ port = await getAvailablePort();
106
+ }
107
+ if (typeof env === "string") {
108
+ env = await parseEnv(env);
109
+ }
110
+ const originalExec = cluster.settings.exec;
111
+ const originalArgs = cluster.settings.execArgv;
112
+ try {
113
+ cluster.settings.exec = module;
114
+ cluster.settings.execArgv = args;
115
+ const worker = cluster.fork({ ...env, NODE_ENV: "development", ...process.env, PORT: `${port}` });
116
+ return new Promise((resolve) => {
117
+ function ready(message) {
118
+ if (message === "ready") {
119
+ worker.off("message", ready);
120
+ resolve(worker);
121
+ }
122
+ }
123
+ worker.on("message", ready);
124
+ });
125
+ } finally {
126
+ cluster.settings.exec = originalExec;
127
+ cluster.settings.execArgv = originalArgs;
128
+ }
129
+ }
91
130
  async function waitForServer(port, wait = 0) {
92
131
  let remaining = wait > 0 ? wait : Infinity;
93
- while (!await isPortInUse(port)) {
132
+ let connection;
133
+ while (!(connection = await getConnection(port))) {
94
134
  if (remaining >= 100) {
95
135
  remaining -= 100;
96
136
  await sleep(100);
@@ -100,14 +140,16 @@ async function waitForServer(port, wait = 0) {
100
140
  );
101
141
  }
102
142
  }
143
+ return connection;
103
144
  }
104
- async function isPortInUse(port) {
145
+ async function getConnection(port) {
105
146
  return new Promise((resolve) => {
106
- const connection = net.connect(port).setNoDelay(true).setKeepAlive(false).on("error", () => done(false)).on("connect", () => done(true));
107
- function done(connected) {
147
+ const connection = net.connect(port).setNoDelay(true).setKeepAlive(false).on("error", () => {
108
148
  connection.end();
109
- resolve(connected);
110
- }
149
+ resolve(null);
150
+ }).on("connect", () => {
151
+ resolve(connection);
152
+ });
111
153
  });
112
154
  }
113
155
  async function getAvailablePort() {
@@ -125,20 +167,56 @@ function sleep(ms) {
125
167
  // src/adapter/index.ts
126
168
  import parseNodeArgs from "parse-node-args";
127
169
  var __dirname = fileURLToPath(new URL(".", import.meta.url));
170
+ var defaultEntry = path.join(__dirname, "default-entry");
171
+ var loadDevWorker = path.join(__dirname, "load-dev-worker.mjs");
128
172
  function adapter() {
129
173
  return {
130
174
  name: "base-adapter",
131
175
  async getEntryFile() {
132
- const entry = path.join(__dirname, "default-entry");
133
- return entry;
176
+ return defaultEntry;
134
177
  },
135
- async startDev(config2, { port = 3e3, envFile }) {
136
- const { root, configFile } = config2;
178
+ async startDev(entry, config2, options) {
179
+ const { port = 3e3, envFile } = options;
180
+ if (entry) {
181
+ const { nodeArgs } = parseNodeArgs(options.args);
182
+ let worker;
183
+ async function start() {
184
+ const nextWorker = await spawnServerWorker(
185
+ loadDevWorker,
186
+ nodeArgs,
187
+ port,
188
+ envFile
189
+ );
190
+ nextWorker.on("message", (messsage) => {
191
+ if (messsage === "restart") {
192
+ start();
193
+ }
194
+ }).send({ type: "start", entry, config: config2 });
195
+ await waitForWorker(nextWorker, port);
196
+ if (worker) {
197
+ const prevWorker = worker;
198
+ let timeout;
199
+ worker.once("disconnect", () => {
200
+ clearTimeout(timeout);
201
+ });
202
+ worker.send({ type: "shutdown" });
203
+ worker.disconnect();
204
+ timeout = setTimeout(() => {
205
+ prevWorker.kill();
206
+ }, 2e3);
207
+ }
208
+ worker = nextWorker;
209
+ }
210
+ await start();
211
+ return {
212
+ port,
213
+ close() {
214
+ worker.kill();
215
+ }
216
+ };
217
+ }
218
+ const devServer = await createDevServer(config2);
137
219
  envFile && await loadEnv(envFile);
138
- const devServer = await createDevServer({
139
- root,
140
- configFile
141
- });
142
220
  return new Promise((resolve) => {
143
221
  const listener = devServer.middlewares.listen(port, () => {
144
222
  const address = listener.address();
@@ -162,8 +240,21 @@ function adapter() {
162
240
  }
163
241
  };
164
242
  }
243
+ async function waitForWorker(worker, port) {
244
+ return new Promise((resolve) => {
245
+ function listening(address) {
246
+ if (address.port === port) {
247
+ worker.off("listening", listening);
248
+ resolve();
249
+ }
250
+ }
251
+ worker.on("listening", listening);
252
+ });
253
+ }
165
254
  export {
255
+ activeDevServers,
166
256
  createDevServer,
167
257
  createViteDevMiddleware,
258
+ createViteDevServer,
168
259
  adapter as default
169
260
  };
@@ -0,0 +1,37 @@
1
+ import { createServer } from "vite";
2
+
3
+ let activeDevServers;
4
+
5
+ process
6
+ .on("message", (message) => {
7
+ switch (message.type) {
8
+ case "start":
9
+ return start(message.entry, message.config);
10
+ case "shutdown":
11
+ return shutdown();
12
+ }
13
+ })
14
+ .send("ready");
15
+
16
+ async function start(entry, config) {
17
+ let changed = false;
18
+ const loader = await createServer(config);
19
+ ({ activeDevServers } = await loader.ssrLoadModule("@marko/run/adapter"));
20
+ await loader.ssrLoadModule(entry);
21
+
22
+ loader.watcher.on("change", (path) => {
23
+ if (!changed && loader.moduleGraph.getModulesByFile(path)) {
24
+ changed = true;
25
+ process.send("restart");
26
+ }
27
+ });
28
+ }
29
+
30
+ function shutdown() {
31
+ if (activeDevServers) {
32
+ for (const devServer of activeDevServers) {
33
+ devServer.ws.send({ type: "full-reload" });
34
+ }
35
+ activeDevServers.clear();
36
+ }
37
+ }
@@ -5,7 +5,7 @@ import sade from "sade";
5
5
 
6
6
  // src/cli/commands.ts
7
7
  import path3 from "path";
8
- import fs4 from "fs";
8
+ import fs3 from "fs";
9
9
  import { fileURLToPath as fileURLToPath2 } from "url";
10
10
  import { build as viteBuild, resolveConfig } from "vite";
11
11
 
@@ -26,84 +26,10 @@ var setExternalAdapterOptions = (viteConfig, value) => setConfig(viteConfig, Ada
26
26
  // src/cli/commands.ts
27
27
  import { MemoryStore } from "@marko/vite";
28
28
 
29
- // src/vite/utils/server.ts
30
- import net from "net";
31
- import cp from "child_process";
32
- import { parse, config } from "dotenv";
33
- import fs from "fs";
34
- async function parseEnv(envFile) {
35
- if (fs.existsSync(envFile)) {
36
- const content = await fs.promises.readFile(envFile, "utf8");
37
- return parse(content);
38
- }
39
- }
40
- async function spawnServer(cmd, args = [], port = 0, env, cwd = process.cwd(), wait = 3e4) {
41
- if (port <= 0) {
42
- port = await getAvailablePort();
43
- }
44
- if (typeof env === "string") {
45
- env = await parseEnv(env);
46
- }
47
- const proc = cp.spawn(cmd, args, {
48
- cwd,
49
- shell: true,
50
- stdio: "inherit",
51
- windowsHide: true,
52
- env: { ...env, NODE_ENV: "development", ...process.env, PORT: `${port}` }
53
- });
54
- const close = () => {
55
- proc.unref();
56
- proc.kill();
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) {
70
- let remaining = wait > 0 ? wait : Infinity;
71
- while (!await isPortInUse(port)) {
72
- if (remaining >= 100) {
73
- remaining -= 100;
74
- await sleep(100);
75
- } else {
76
- throw new Error(
77
- `site-write: timeout while wating for server to start on port "${port}".`
78
- );
79
- }
80
- }
81
- }
82
- async function isPortInUse(port) {
83
- return new Promise((resolve) => {
84
- const connection = net.connect(port).setNoDelay(true).setKeepAlive(false).on("error", () => done(false)).on("connect", () => done(true));
85
- function done(connected) {
86
- connection.end();
87
- resolve(connected);
88
- }
89
- });
90
- }
91
- async function getAvailablePort() {
92
- return new Promise((resolve) => {
93
- const server = net.createServer().listen(0, () => {
94
- const { port } = server.address();
95
- server.close(() => resolve(port));
96
- });
97
- });
98
- }
99
- function sleep(ms) {
100
- return new Promise((resolve) => setTimeout(resolve, ms));
101
- }
102
-
103
29
  // src/vite/plugin.ts
104
30
  import path2 from "path";
105
31
  import crypto from "crypto";
106
- import fs3 from "fs";
32
+ import fs2 from "fs";
107
33
  import glob from "glob";
108
34
  import { mergeConfig } from "vite";
109
35
  import markoVitePlugin, { FileStore } from "@marko/vite";
@@ -131,7 +57,7 @@ var routeableFileRegex = new RegExp(
131
57
  );
132
58
 
133
59
  // src/vite/routes/walk.ts
134
- import fs2 from "fs";
60
+ import fs from "fs";
135
61
  import path from "path";
136
62
 
137
63
  // src/vite/utils/ast.ts
@@ -216,7 +142,7 @@ async function preview(entry, cwd, configFile, port, outDir, envFile, args = [])
216
142
  };
217
143
  return await adapter.startPreview(entryFile, options);
218
144
  }
219
- async function dev(cmd, cwd, configFile, port, envFile, args = []) {
145
+ async function dev(entry, cwd, configFile, port, envFile, args = []) {
220
146
  const resolvedConfig = await resolveConfig(
221
147
  { root: cwd, configFile, logLevel: "silent" },
222
148
  "build"
@@ -227,27 +153,23 @@ async function dev(cmd, cwd, configFile, port, envFile, args = []) {
227
153
  if (envFile) {
228
154
  envFile = path3.resolve(cwd, envFile);
229
155
  }
230
- if (cmd) {
231
- return await spawnServer(cmd, args, port, envFile, cwd);
232
- } else {
233
- const adapter = await resolveAdapter2(resolvedConfig);
234
- if (!adapter) {
235
- throw new Error(
236
- "No adapter specified for 'dev' command without custom target"
237
- );
238
- } else if (!adapter.startDev) {
239
- throw new Error(
240
- `Adapter '${adapter.name}' does not support 'serve' command`
241
- );
242
- }
243
- const options = {
244
- cwd,
245
- args,
246
- port,
247
- envFile
248
- };
249
- return await adapter.startDev({ root: cwd, configFile }, options);
156
+ const adapter = await resolveAdapter2(resolvedConfig);
157
+ if (!adapter) {
158
+ throw new Error(
159
+ "No adapter specified for 'dev' command without custom target"
160
+ );
161
+ } else if (!adapter.startDev) {
162
+ throw new Error(
163
+ `Adapter '${adapter.name}' does not support 'serve' command`
164
+ );
250
165
  }
166
+ const options = {
167
+ cwd,
168
+ args,
169
+ port,
170
+ envFile
171
+ };
172
+ return await adapter.startDev(entry, { root: cwd, configFile }, options);
251
173
  }
252
174
  async function build(entry, cwd, configFile, outDir, envFile) {
253
175
  var _a;
@@ -308,7 +230,7 @@ async function build(entry, cwd, configFile, outDir, envFile) {
308
230
  function findFileWithExt(dir, base, extensions = defaultConfigFileExts) {
309
231
  for (const ext of extensions) {
310
232
  const filePath = path3.join(dir, base + ext);
311
- if (fs4.existsSync(filePath)) {
233
+ if (fs3.existsSync(filePath)) {
312
234
  return filePath;
313
235
  }
314
236
  }
@@ -317,7 +239,7 @@ function findFileWithExt(dir, base, extensions = defaultConfigFileExts) {
317
239
  async function getViteConfig(dir, configFile, bases = defaultConfigFileBases) {
318
240
  if (configFile) {
319
241
  const configFilePath = path3.join(dir, configFile);
320
- if (!fs4.existsSync(configFilePath)) {
242
+ if (!fs3.existsSync(configFilePath)) {
321
243
  throw new Error(`No config file found at '${configFilePath}'`);
322
244
  }
323
245
  return configFile;
@@ -330,12 +252,12 @@ async function getViteConfig(dir, configFile, bases = defaultConfigFileBases) {
330
252
  }
331
253
  return path3.join(__dirname2, "default.config.mjs");
332
254
  }
333
- async function resolveAdapter2(config2) {
334
- const options = getExternalPluginOptions(config2);
255
+ async function resolveAdapter2(config) {
256
+ const options = getExternalPluginOptions(config);
335
257
  if (!options) {
336
258
  throw new Error("Unable to resolve @marko/run options");
337
259
  }
338
- return resolveAdapter(config2.root, options);
260
+ return resolveAdapter(config.root, options);
339
261
  }
340
262
 
341
263
  // src/cli/index.ts
@@ -355,12 +277,12 @@ prog.command("preview [entry]").describe("Start a production-like server for alr
355
277
  process.env.NODE_ENV = "production";
356
278
  const cwd = process.cwd();
357
279
  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);
280
+ const config = await getViteConfig(cwd, opts.config);
281
+ await build(entry, cwd, config, opts.output, opts.env);
360
282
  await preview(
361
283
  opts.file,
362
284
  cwd,
363
- config2,
285
+ config,
364
286
  opts.port,
365
287
  opts.output,
366
288
  opts.env,
@@ -373,15 +295,15 @@ prog.command("dev [entry]", "", { default: true }).describe("Start development s
373
295
  ).example("dev --config vite.config.js").action(async (entry, opts) => {
374
296
  const cwd = process.cwd();
375
297
  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);
298
+ const config = await getViteConfig(cwd, opts.config);
299
+ await dev(entry, cwd, config, opts.port, opts.env, args);
378
300
  });
379
301
  prog.command("build [entry]").describe("Build the application (without serving it)").option(
380
302
  "-o, --output",
381
303
  "Directory to write built files (default: 'build.outDir' in Vite config)"
382
304
  ).example("build --config vite.config.js").action(async (entry, opts) => {
383
305
  const cwd = process.cwd();
384
- const config2 = await getViteConfig(cwd, opts.config);
385
- await build(entry, cwd, config2, opts.ouput, opts.env);
306
+ const config = await getViteConfig(cwd, opts.config);
307
+ await build(entry, cwd, config, opts.ouput, opts.env);
386
308
  });
387
309
  prog.parse(process.argv);
@@ -1,5 +1,6 @@
1
- import type { HandlerLike, ParamsObject, Route as AnyRoute, Context as AnyContext } from "./types";
1
+ import type { HandlerLike, ParamsObject, Route as AnyRoute, Context as AnyContext, RuntimeModule } from "./types";
2
2
  declare global {
3
+ var __marko_run__: RuntimeModule;
3
4
  namespace MarkoRun {
4
5
  const NotHandled: unique symbol;
5
6
  const NotMatched: unique symbol;
@@ -25,14 +25,20 @@ __export(router_exports, {
25
25
  match: () => match
26
26
  });
27
27
  module.exports = __toCommonJS(router_exports);
28
- function notImplemented() {
29
- throw new Error(
30
- "This should have been replaced by the @marko/run plugin at build/dev time"
31
- );
28
+ function fromRuntime(name) {
29
+ return (...args) => {
30
+ const runtime = globalThis.__marko_run__;
31
+ if (!runtime) {
32
+ throw new Error(
33
+ "This should have been replaced by the @marko/run plugin at build/dev time"
34
+ );
35
+ }
36
+ return runtime[name](...args);
37
+ };
32
38
  }
33
- var fetch = notImplemented;
34
- var match = notImplemented;
35
- var invoke = notImplemented;
39
+ var fetch = fromRuntime("fetch");
40
+ var match = fromRuntime("match");
41
+ var invoke = fromRuntime("invoke");
36
42
  // Annotate the CommonJS export names for ESM import in node:
37
43
  0 && (module.exports = {
38
44
  fetch,
@@ -1,12 +1,18 @@
1
1
  // src/runtime/router.ts
2
- function notImplemented() {
3
- throw new Error(
4
- "This should have been replaced by the @marko/run plugin at build/dev time"
5
- );
2
+ function fromRuntime(name) {
3
+ return (...args) => {
4
+ const runtime = globalThis.__marko_run__;
5
+ if (!runtime) {
6
+ throw new Error(
7
+ "This should have been replaced by the @marko/run plugin at build/dev time"
8
+ );
9
+ }
10
+ return runtime[name](...args);
11
+ };
6
12
  }
7
- var fetch = notImplemented;
8
- var match = notImplemented;
9
- var invoke = notImplemented;
13
+ var fetch = fromRuntime("fetch");
14
+ var match = fromRuntime("match");
15
+ var invoke = fromRuntime("invoke");
10
16
  export {
11
17
  fetch,
12
18
  invoke,
@@ -680,7 +680,9 @@ function renderRouter(routes, options = {
680
680
  `import page${key} from '${virtualFilePrefix}/${markoRunFilePrefix}special__${key}.marko${serverEntryQuery}';`
681
681
  );
682
682
  }
683
- writer.writeLines("").writeBlockStart(`export function match(method, pathname) {`).writeLines(
683
+ writer.writeLines(`
684
+ globalThis.__marko_run__ = { match, fetch, invoke };
685
+ `).writeBlockStart(`export function match(method, pathname) {`).writeLines(
684
686
  `if (!pathname) {
685
687
  pathname = '/';
686
688
  } else if (pathname.charAt(0) !== '/') {
@@ -1812,6 +1814,7 @@ var import_net = __toESM(require("net"), 1);
1812
1814
  var import_child_process = __toESM(require("child_process"), 1);
1813
1815
  var import_dotenv = require("dotenv");
1814
1816
  var import_fs3 = __toESM(require("fs"), 1);
1817
+ var import_cluster = __toESM(require("cluster"), 1);
1815
1818
  async function parseEnv(envFile) {
1816
1819
  if (import_fs3.default.existsSync(envFile)) {
1817
1820
  const content = await import_fs3.default.promises.readFile(envFile, "utf8");
@@ -1852,7 +1855,8 @@ async function spawnServer(cmd, args = [], port = 0, env, cwd = process.cwd(), w
1852
1855
  }
1853
1856
  async function waitForServer(port, wait = 0) {
1854
1857
  let remaining = wait > 0 ? wait : Infinity;
1855
- while (!await isPortInUse(port)) {
1858
+ let connection;
1859
+ while (!(connection = await getConnection(port))) {
1856
1860
  if (remaining >= 100) {
1857
1861
  remaining -= 100;
1858
1862
  await sleep(100);
@@ -1862,16 +1866,21 @@ async function waitForServer(port, wait = 0) {
1862
1866
  );
1863
1867
  }
1864
1868
  }
1869
+ return connection;
1865
1870
  }
1866
- async function isPortInUse(port) {
1871
+ async function getConnection(port) {
1867
1872
  return new Promise((resolve) => {
1868
- const connection = import_net.default.connect(port).setNoDelay(true).setKeepAlive(false).on("error", () => done(false)).on("connect", () => done(true));
1869
- function done(connected) {
1873
+ const connection = import_net.default.connect(port).setNoDelay(true).setKeepAlive(false).on("error", () => {
1870
1874
  connection.end();
1871
- resolve(connected);
1872
- }
1875
+ resolve(null);
1876
+ }).on("connect", () => {
1877
+ resolve(connection);
1878
+ });
1873
1879
  });
1874
1880
  }
1881
+ async function isPortInUse(port) {
1882
+ return Boolean(await getConnection(port));
1883
+ }
1875
1884
  async function getAvailablePort() {
1876
1885
  return new Promise((resolve) => {
1877
1886
  const server = import_net.default.createServer().listen(0, () => {
@@ -643,7 +643,9 @@ function renderRouter(routes, options = {
643
643
  `import page${key} from '${virtualFilePrefix}/${markoRunFilePrefix}special__${key}.marko${serverEntryQuery}';`
644
644
  );
645
645
  }
646
- writer.writeLines("").writeBlockStart(`export function match(method, pathname) {`).writeLines(
646
+ writer.writeLines(`
647
+ globalThis.__marko_run__ = { match, fetch, invoke };
648
+ `).writeBlockStart(`export function match(method, pathname) {`).writeLines(
647
649
  `if (!pathname) {
648
650
  pathname = '/';
649
651
  } else if (pathname.charAt(0) !== '/') {
@@ -1774,6 +1776,7 @@ import net from "net";
1774
1776
  import cp from "child_process";
1775
1777
  import { parse, config } from "dotenv";
1776
1778
  import fs3 from "fs";
1779
+ import cluster from "cluster";
1777
1780
  async function parseEnv(envFile) {
1778
1781
  if (fs3.existsSync(envFile)) {
1779
1782
  const content = await fs3.promises.readFile(envFile, "utf8");
@@ -1814,7 +1817,8 @@ async function spawnServer(cmd, args = [], port = 0, env, cwd = process.cwd(), w
1814
1817
  }
1815
1818
  async function waitForServer(port, wait = 0) {
1816
1819
  let remaining = wait > 0 ? wait : Infinity;
1817
- while (!await isPortInUse(port)) {
1820
+ let connection;
1821
+ while (!(connection = await getConnection(port))) {
1818
1822
  if (remaining >= 100) {
1819
1823
  remaining -= 100;
1820
1824
  await sleep(100);
@@ -1824,16 +1828,21 @@ async function waitForServer(port, wait = 0) {
1824
1828
  );
1825
1829
  }
1826
1830
  }
1831
+ return connection;
1827
1832
  }
1828
- async function isPortInUse(port) {
1833
+ async function getConnection(port) {
1829
1834
  return new Promise((resolve) => {
1830
- const connection = net.connect(port).setNoDelay(true).setKeepAlive(false).on("error", () => done(false)).on("connect", () => done(true));
1831
- function done(connected) {
1835
+ const connection = net.connect(port).setNoDelay(true).setKeepAlive(false).on("error", () => {
1832
1836
  connection.end();
1833
- resolve(connected);
1834
- }
1837
+ resolve(null);
1838
+ }).on("connect", () => {
1839
+ resolve(connection);
1840
+ });
1835
1841
  });
1836
1842
  }
1843
+ async function isPortInUse(port) {
1844
+ return Boolean(await getConnection(port));
1845
+ }
1837
1846
  async function getAvailablePort() {
1838
1847
  return new Promise((resolve) => {
1839
1848
  const server = net.createServer().listen(0, () => {
@@ -24,7 +24,7 @@ export interface Adapter {
24
24
  pluginOptions?(options: Options): Promise<Options> | Options | undefined;
25
25
  viteConfig?(config: UserConfig): Promise<UserConfig> | UserConfig | undefined;
26
26
  getEntryFile?(): Promise<string> | string;
27
- startDev?(config: InlineConfig, options: StartDevOptions): Promise<SpawnedServer> | SpawnedServer;
27
+ startDev?(entry: string | undefined, config: InlineConfig, options: StartDevOptions): Promise<SpawnedServer> | SpawnedServer;
28
28
  startPreview?(entry: string | undefined, options: StartPreviewOptions): Promise<SpawnedServer> | SpawnedServer;
29
29
  buildEnd?(config: ResolvedConfig, routes: Route[], builtEntries: string[], sourceEntries: string[]): Promise<void> | void;
30
30
  typeInfo?(writer: (data: string) => void): Promise<string> | string;
@@ -1,3 +1,6 @@
1
+ /// <reference types="node" />
2
+ import { type Socket } from "net";
3
+ import { type Worker } from "cluster";
1
4
  export interface SpawnedServer {
2
5
  port: number;
3
6
  close(): Promise<void> | void;
@@ -5,6 +8,8 @@ export interface SpawnedServer {
5
8
  export declare function parseEnv(envFile: string): Promise<import("dotenv").DotenvParseOutput | undefined>;
6
9
  export declare function loadEnv(envFile: string): void;
7
10
  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>;
11
+ export declare function spawnServerWorker(module: string, args?: string[], port?: number, env?: string | Record<string, string>): Promise<Worker>;
12
+ export declare function waitForServer(port: number, wait?: number): Promise<Socket>;
13
+ export declare function getConnection(port: number): Promise<Socket | null>;
9
14
  export declare function isPortInUse(port: number): Promise<boolean>;
10
15
  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.5",
3
+ "version": "0.1.6",
4
4
  "description": "The Marko application framework.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/marko-js/run/tree/main/packages/run",