@marko/run 0.0.1-beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +267 -0
- package/dist/adapter/default-entry.mjs +18 -0
- package/dist/adapter/dev-server.d.ts +4 -0
- package/dist/adapter/index.cjs +159 -0
- package/dist/adapter/index.d.ts +4 -0
- package/dist/adapter/index.js +126 -0
- package/dist/adapter/server-old.d.ts +3 -0
- package/dist/adapter/server.d.ts +6 -0
- package/dist/adapters/node/index.d.ts +5 -0
- package/dist/adapters/node/server.d.ts +3 -0
- package/dist/adapters/static/crawler.d.ts +9 -0
- package/dist/adapters/static/default-entry.mjs +1 -0
- package/dist/adapters/static/index.cjs +371 -0
- package/dist/adapters/static/index.d.ts +5 -0
- package/dist/adapters/static/index.js +341 -0
- package/dist/adapters/static/server.d.ts +3 -0
- package/dist/cli/default.config.mjs +7 -0
- package/dist/cli/index.mjs +223 -0
- package/dist/runtime/index.cjs +34 -0
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/index.js +7 -0
- package/dist/runtime/request.d.ts +4 -0
- package/dist/runtime/router.cjs +39 -0
- package/dist/runtime/router.d.ts +4 -0
- package/dist/runtime/router.js +12 -0
- package/dist/runtime/types.d.ts +22 -0
- package/dist/vite/codegen/index.d.ts +5 -0
- package/dist/vite/codegen/writer.d.ts +20 -0
- package/dist/vite/constants.d.ts +19 -0
- package/dist/vite/index.cjs +1394 -0
- package/dist/vite/index.d.ts +3 -0
- package/dist/vite/index.js +1359 -0
- package/dist/vite/plugin.d.ts +3 -0
- package/dist/vite/routes/builder.d.ts +7 -0
- package/dist/vite/routes/routeTrie.d.ts +2 -0
- package/dist/vite/routes/walk.d.ts +14 -0
- package/dist/vite/types.d.ts +62 -0
- package/dist/vite/utils/ast.d.ts +1 -0
- package/dist/vite/utils/config.d.ts +3 -0
- package/dist/vite/utils/log.d.ts +3 -0
- package/dist/vite/utils/route.d.ts +3 -0
- package/dist/vite/utils/server.d.ts +7 -0
- package/package.json +93 -0
|
@@ -0,0 +1,1394 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
25
|
+
|
|
26
|
+
// src/vite/index.ts
|
|
27
|
+
var vite_exports = {};
|
|
28
|
+
__export(vite_exports, {
|
|
29
|
+
default: () => markoServe,
|
|
30
|
+
getAvailablePort: () => getAvailablePort,
|
|
31
|
+
isPortInUse: () => isPortInUse,
|
|
32
|
+
spawnServer: () => spawnServer
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(vite_exports);
|
|
35
|
+
|
|
36
|
+
// src/vite/plugin.ts
|
|
37
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
38
|
+
var import_crypto = __toESM(require("crypto"), 1);
|
|
39
|
+
var import_vite = require("vite");
|
|
40
|
+
var import_vite2 = __toESM(require("@marko/vite"), 1);
|
|
41
|
+
|
|
42
|
+
// src/vite/constants.ts
|
|
43
|
+
var markoServeFilePrefix = "__marko-serve__";
|
|
44
|
+
var virtualFilePrefix = "virtual:marko-serve";
|
|
45
|
+
var virtualRoutesPrefix = `${virtualFilePrefix}/routes`;
|
|
46
|
+
var httpVerbs = ["get", "post", "put", "delete"];
|
|
47
|
+
var serverEntryQuery = "?marko-server-entry";
|
|
48
|
+
var browserEntryQuery = "?marko-browser-entry";
|
|
49
|
+
var RoutableFileTypes = {
|
|
50
|
+
Page: "page",
|
|
51
|
+
Layout: "layout",
|
|
52
|
+
Handler: "handler",
|
|
53
|
+
Middleware: "middleware",
|
|
54
|
+
Meta: "meta",
|
|
55
|
+
NotFound: "404",
|
|
56
|
+
Error: "500"
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// src/vite/routes/builder.ts
|
|
60
|
+
var markoFiles = `(${RoutableFileTypes.Layout}|${RoutableFileTypes.Page}|${RoutableFileTypes.NotFound}|${RoutableFileTypes.Error})\\.(?:.*\\.)?(marko)`;
|
|
61
|
+
var nonMarkoFiles = `(${RoutableFileTypes.Middleware}|${RoutableFileTypes.Handler}|${RoutableFileTypes.Meta})\\.(?:.*\\.)?(.+)`;
|
|
62
|
+
var routeableFileRegex = new RegExp(
|
|
63
|
+
`^[+](?:${markoFiles}|${nonMarkoFiles})$`,
|
|
64
|
+
"i"
|
|
65
|
+
);
|
|
66
|
+
function isRoutableFile(filename) {
|
|
67
|
+
return routeableFileRegex.test(filename);
|
|
68
|
+
}
|
|
69
|
+
function matchRoutableFile(filename) {
|
|
70
|
+
const match = filename.match(routeableFileRegex);
|
|
71
|
+
return match && (match[1] || match[3]).toLowerCase();
|
|
72
|
+
}
|
|
73
|
+
function scorePath(path3, index) {
|
|
74
|
+
const [pattern, splat] = path3.split("/$$", 2);
|
|
75
|
+
const segments = pattern.split("/").filter(Boolean);
|
|
76
|
+
return segments.reduce(
|
|
77
|
+
(score, segment) => score + (segment.startsWith("$") ? 3 : 4),
|
|
78
|
+
segments.length + (splat === void 0 ? 1 : 2)
|
|
79
|
+
) * 1e4 - index;
|
|
80
|
+
}
|
|
81
|
+
function isSpecialType(type) {
|
|
82
|
+
return type === RoutableFileTypes.NotFound || type === RoutableFileTypes.Error;
|
|
83
|
+
}
|
|
84
|
+
async function buildRoutes(walk, basePath) {
|
|
85
|
+
const dirStack = basePath ? basePath.split("/") : [];
|
|
86
|
+
const pathStack = [];
|
|
87
|
+
const paramStack = [];
|
|
88
|
+
const layoutsStack = [];
|
|
89
|
+
const middlewareStack = [];
|
|
90
|
+
const routes = /* @__PURE__ */ new Map();
|
|
91
|
+
const special = {};
|
|
92
|
+
let isRoot = true;
|
|
93
|
+
let nextId = 1;
|
|
94
|
+
let current;
|
|
95
|
+
let children = [];
|
|
96
|
+
await walk({
|
|
97
|
+
onFile(entry) {
|
|
98
|
+
const type = matchRoutableFile(entry.name);
|
|
99
|
+
if (!type) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (!isRoot && isSpecialType(type)) {
|
|
103
|
+
console.warn(
|
|
104
|
+
`Special pages '${RoutableFileTypes.NotFound}' and '${RoutableFileTypes.Error}' are only considered in the root directory - ignoring ${entry.path}`
|
|
105
|
+
);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (!current) {
|
|
109
|
+
current = {
|
|
110
|
+
path: "/" + pathStack.join("/"),
|
|
111
|
+
originalPath: dirStack.join("/"),
|
|
112
|
+
children: [],
|
|
113
|
+
files: /* @__PURE__ */ new Map()
|
|
114
|
+
};
|
|
115
|
+
children.push(current);
|
|
116
|
+
}
|
|
117
|
+
let entries = current.files.get(type);
|
|
118
|
+
if (!entries) {
|
|
119
|
+
current.files.set(type, entries = []);
|
|
120
|
+
}
|
|
121
|
+
entries.push({
|
|
122
|
+
type,
|
|
123
|
+
filePath: entry.path,
|
|
124
|
+
importPath: `${current.originalPath}/${entry.name}`,
|
|
125
|
+
name: entry.name,
|
|
126
|
+
verbs: type === RoutableFileTypes.Page ? ["get"] : void 0
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
onDir(dir) {
|
|
130
|
+
var _a, _b, _c, _d, _e;
|
|
131
|
+
if (!current) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const { path: path3, files } = current;
|
|
135
|
+
const middleware = (_a = files.get(RoutableFileTypes.Middleware)) == null ? void 0 : _a[0];
|
|
136
|
+
const layout = (_b = files.get(RoutableFileTypes.Layout)) == null ? void 0 : _b[0];
|
|
137
|
+
const handler = (_c = files.get(RoutableFileTypes.Handler)) == null ? void 0 : _c[0];
|
|
138
|
+
const page = (_d = files.get(RoutableFileTypes.Page)) == null ? void 0 : _d[0];
|
|
139
|
+
const middlewareStackLength = middlewareStack.length;
|
|
140
|
+
const layoutsStackLength = layoutsStack.length;
|
|
141
|
+
middleware && middlewareStack.push(middleware);
|
|
142
|
+
layout && layoutsStack.push(layout);
|
|
143
|
+
if (handler || page) {
|
|
144
|
+
const key = path3.replace(/(\$\$?)[^\/]*/g, "$1").replace(/^\/+/, "").replace(/[^a-z0-9_$\/]+/gi, "").replace(/\//g, "__") || "index";
|
|
145
|
+
if (routes.has(key)) {
|
|
146
|
+
console.warn(`Duplicate route for path ${path3} -- ignoring`, current);
|
|
147
|
+
} else {
|
|
148
|
+
const index = nextId++;
|
|
149
|
+
routes.set(key, {
|
|
150
|
+
index,
|
|
151
|
+
key,
|
|
152
|
+
path: path3,
|
|
153
|
+
params: [...paramStack],
|
|
154
|
+
middleware: [...middlewareStack],
|
|
155
|
+
layouts: page ? [...layoutsStack] : [],
|
|
156
|
+
meta: (_e = files.get(RoutableFileTypes.Meta)) == null ? void 0 : _e[0],
|
|
157
|
+
page,
|
|
158
|
+
handler,
|
|
159
|
+
score: scorePath(path3, index)
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (isRoot) {
|
|
164
|
+
for (const [type, entries] of files) {
|
|
165
|
+
if (isSpecialType(type)) {
|
|
166
|
+
special[type] = {
|
|
167
|
+
index: 0,
|
|
168
|
+
key: type,
|
|
169
|
+
path: path3,
|
|
170
|
+
middleware: [],
|
|
171
|
+
layouts: [...layoutsStack],
|
|
172
|
+
page: entries[0],
|
|
173
|
+
score: 0
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
} else if (dir.startsWith("$$")) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
return () => {
|
|
181
|
+
middlewareStack.length = middlewareStackLength;
|
|
182
|
+
layoutsStack.length = layoutsStackLength;
|
|
183
|
+
};
|
|
184
|
+
},
|
|
185
|
+
onEnter({ name }) {
|
|
186
|
+
const pathStackLength = pathStack.length;
|
|
187
|
+
const paramStackLength = paramStack.length;
|
|
188
|
+
const prevChildren = children;
|
|
189
|
+
const prevCurrent = current;
|
|
190
|
+
const prevIsRoot = isRoot;
|
|
191
|
+
if (name.charCodeAt(0) === 95 || name.charCodeAt(0) === 40 && name.charCodeAt(name.length - 1) === 41 || name.toLowerCase() === "index") {
|
|
192
|
+
} else {
|
|
193
|
+
if (name.charCodeAt(0) === 36) {
|
|
194
|
+
if (name.charCodeAt(1) === 36) {
|
|
195
|
+
paramStack.push({
|
|
196
|
+
name: name.slice(2) || "*",
|
|
197
|
+
index: -1
|
|
198
|
+
});
|
|
199
|
+
} else if (name.length > 1) {
|
|
200
|
+
paramStack.push({
|
|
201
|
+
name: name.slice(1),
|
|
202
|
+
index: pathStackLength
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
pathStack.push(name.toLowerCase());
|
|
207
|
+
}
|
|
208
|
+
dirStack.push(name);
|
|
209
|
+
isRoot = false;
|
|
210
|
+
if (current) {
|
|
211
|
+
children = current.children;
|
|
212
|
+
current = void 0;
|
|
213
|
+
}
|
|
214
|
+
return () => {
|
|
215
|
+
dirStack.pop();
|
|
216
|
+
pathStack.length = pathStackLength;
|
|
217
|
+
paramStack.length = paramStackLength;
|
|
218
|
+
children = prevChildren;
|
|
219
|
+
current = prevCurrent;
|
|
220
|
+
isRoot = prevIsRoot;
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
return {
|
|
225
|
+
list: [...routes.values()],
|
|
226
|
+
special
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// src/vite/routes/walk.ts
|
|
231
|
+
var import_fs = __toESM(require("fs"), 1);
|
|
232
|
+
var import_path = __toESM(require("path"), 1);
|
|
233
|
+
function createFSWalker(dir) {
|
|
234
|
+
return async function walkFS({ onFile, onEnter, onDir, maxDepth = 50 }) {
|
|
235
|
+
async function walk(dir2, depth) {
|
|
236
|
+
const dirs = [];
|
|
237
|
+
const entries = await import_fs.default.promises.readdir(dir2, { withFileTypes: true });
|
|
238
|
+
const prefix = dir2 + import_path.default.sep;
|
|
239
|
+
for (const dirEntry of entries) {
|
|
240
|
+
const entry = {
|
|
241
|
+
name: dirEntry.name,
|
|
242
|
+
path: prefix + dirEntry.name
|
|
243
|
+
};
|
|
244
|
+
if (dirEntry.isDirectory()) {
|
|
245
|
+
dirs.push(entry);
|
|
246
|
+
} else {
|
|
247
|
+
onFile == null ? void 0 : onFile(entry);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const onAfter = onDir == null ? void 0 : onDir(dir2);
|
|
251
|
+
if (onAfter !== false) {
|
|
252
|
+
if (--depth > 0) {
|
|
253
|
+
for (const entry of dirs) {
|
|
254
|
+
const onExit = onEnter == null ? void 0 : onEnter(entry);
|
|
255
|
+
if (onExit !== false) {
|
|
256
|
+
await walk(entry.path, depth);
|
|
257
|
+
onExit == null ? void 0 : onExit();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
onAfter == null ? void 0 : onAfter();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
await walk(dir, maxDepth);
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// src/vite/codegen/writer.ts
|
|
269
|
+
function createWriter(sink, options) {
|
|
270
|
+
let buffer = "";
|
|
271
|
+
let indentLevel = 0;
|
|
272
|
+
let indentString = "";
|
|
273
|
+
let firstOpenIndex = 0;
|
|
274
|
+
const branches = [];
|
|
275
|
+
const openWriters = /* @__PURE__ */ new Map();
|
|
276
|
+
const writer = {
|
|
277
|
+
__isActive: true,
|
|
278
|
+
get indent() {
|
|
279
|
+
return indentLevel;
|
|
280
|
+
},
|
|
281
|
+
set indent(value) {
|
|
282
|
+
if (options == null ? void 0 : options.indentWith) {
|
|
283
|
+
if (value < 0) {
|
|
284
|
+
value = 0;
|
|
285
|
+
}
|
|
286
|
+
if (value !== indentLevel) {
|
|
287
|
+
indentLevel = value;
|
|
288
|
+
indentString = options.indentWith.repeat(indentLevel);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
write(data) {
|
|
293
|
+
if (!writer.__isActive) {
|
|
294
|
+
throw new Error("Cannot write to branch that has been joined");
|
|
295
|
+
}
|
|
296
|
+
if (openWriters.size) {
|
|
297
|
+
buffer += data;
|
|
298
|
+
} else {
|
|
299
|
+
sink(data);
|
|
300
|
+
}
|
|
301
|
+
return writer;
|
|
302
|
+
},
|
|
303
|
+
writeLines(...lines) {
|
|
304
|
+
for (const line of lines) {
|
|
305
|
+
if (line) {
|
|
306
|
+
if (indentString) {
|
|
307
|
+
writer.write(indentString);
|
|
308
|
+
}
|
|
309
|
+
writer.write(line);
|
|
310
|
+
}
|
|
311
|
+
writer.write("\n");
|
|
312
|
+
}
|
|
313
|
+
return writer;
|
|
314
|
+
},
|
|
315
|
+
writeBlockStart(data) {
|
|
316
|
+
writer.writeLines(data).indent++;
|
|
317
|
+
return writer;
|
|
318
|
+
},
|
|
319
|
+
writeBlockEnd(data = "}") {
|
|
320
|
+
writer.indent--;
|
|
321
|
+
writer.writeLines(data);
|
|
322
|
+
return writer;
|
|
323
|
+
},
|
|
324
|
+
writeBlock(start, lines, end) {
|
|
325
|
+
return writer.writeBlockStart(start).writeLines(...lines).writeBlockEnd(end);
|
|
326
|
+
},
|
|
327
|
+
branch(name) {
|
|
328
|
+
let existing = openWriters.get(name);
|
|
329
|
+
if (existing) {
|
|
330
|
+
return existing;
|
|
331
|
+
}
|
|
332
|
+
const branch = {
|
|
333
|
+
buffer,
|
|
334
|
+
writer: createWriter(
|
|
335
|
+
(data) => {
|
|
336
|
+
branch.buffer += data;
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
...options,
|
|
340
|
+
onJoin() {
|
|
341
|
+
openWriters.delete(name);
|
|
342
|
+
for (let i = firstOpenIndex; i < branches.length; i++) {
|
|
343
|
+
const b = branches[i];
|
|
344
|
+
if (!b) {
|
|
345
|
+
continue;
|
|
346
|
+
} else if (b.writer.__isActive) {
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
sink(b.buffer);
|
|
350
|
+
branches[i] = null;
|
|
351
|
+
firstOpenIndex++;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
)
|
|
356
|
+
};
|
|
357
|
+
branch.writer.indent = indentLevel;
|
|
358
|
+
openWriters.set(name, branch.writer);
|
|
359
|
+
branches.push(branch);
|
|
360
|
+
buffer = "";
|
|
361
|
+
return branch.writer;
|
|
362
|
+
},
|
|
363
|
+
join(recursive) {
|
|
364
|
+
var _a;
|
|
365
|
+
if (writer.__isActive) {
|
|
366
|
+
if (openWriters.size) {
|
|
367
|
+
if (recursive) {
|
|
368
|
+
for (const branch of openWriters.values()) {
|
|
369
|
+
branch.join(true);
|
|
370
|
+
}
|
|
371
|
+
} else {
|
|
372
|
+
throw new Error(
|
|
373
|
+
`Cannot join a Writer with un-joined branches - use the \`recursive\` argument to join all open branches`
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
buffer && sink(buffer);
|
|
378
|
+
writer.__isActive = false;
|
|
379
|
+
(_a = options == null ? void 0 : options.onJoin) == null ? void 0 : _a.call(options, writer);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
return writer;
|
|
384
|
+
}
|
|
385
|
+
function createStringWriter(opts) {
|
|
386
|
+
let code = "";
|
|
387
|
+
const writer = createWriter((data) => {
|
|
388
|
+
code += data;
|
|
389
|
+
}, { indentWith: " ", ...opts });
|
|
390
|
+
return Object.assign(writer, {
|
|
391
|
+
end() {
|
|
392
|
+
writer.join(true);
|
|
393
|
+
return code;
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// src/vite/routes/routeTrie.ts
|
|
399
|
+
function createRouteTrie(routes) {
|
|
400
|
+
const root = {
|
|
401
|
+
key: ""
|
|
402
|
+
};
|
|
403
|
+
function insert(keys, value) {
|
|
404
|
+
let node = root;
|
|
405
|
+
for (const key of keys) {
|
|
406
|
+
if (key.startsWith("$$")) {
|
|
407
|
+
if (!node.catchAll) {
|
|
408
|
+
node.catchAll = value;
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
return false;
|
|
412
|
+
} else if (key.startsWith("$")) {
|
|
413
|
+
node = node.dynamic ?? (node.dynamic = {
|
|
414
|
+
key: ""
|
|
415
|
+
});
|
|
416
|
+
} else {
|
|
417
|
+
node.static ?? (node.static = /* @__PURE__ */ new Map());
|
|
418
|
+
let next = node.static.get(key);
|
|
419
|
+
if (!next) {
|
|
420
|
+
next = {
|
|
421
|
+
key
|
|
422
|
+
};
|
|
423
|
+
node.static.set(key, next);
|
|
424
|
+
}
|
|
425
|
+
node = next;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (node.route === void 0) {
|
|
429
|
+
node.route = value;
|
|
430
|
+
return true;
|
|
431
|
+
}
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
for (const route of routes) {
|
|
435
|
+
const keys = route.path === "/" ? [] : route.path.split("/").slice(1);
|
|
436
|
+
insert(keys, route);
|
|
437
|
+
}
|
|
438
|
+
return root;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// src/vite/utils/route.ts
|
|
442
|
+
function getVerbs(route) {
|
|
443
|
+
var _a, _b;
|
|
444
|
+
const verbs = ((_b = (_a = route.handler) == null ? void 0 : _a.verbs) == null ? void 0 : _b.slice()) || [];
|
|
445
|
+
if (route.page && !verbs.includes("get")) {
|
|
446
|
+
verbs.unshift("get");
|
|
447
|
+
}
|
|
448
|
+
return verbs;
|
|
449
|
+
}
|
|
450
|
+
function hasVerb(route, verb) {
|
|
451
|
+
var _a, _b;
|
|
452
|
+
return verb === "get" && route.page || ((_b = (_a = route.handler) == null ? void 0 : _a.verbs) == null ? void 0 : _b.includes(verb));
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// src/vite/codegen/index.ts
|
|
456
|
+
var DefaultCodegenOptions = {
|
|
457
|
+
trailingSlashes: "RedirectWithout"
|
|
458
|
+
};
|
|
459
|
+
function renderRouteTemplate(route) {
|
|
460
|
+
if (!route.page) {
|
|
461
|
+
throw new Error(`Route ${route.key} has no page to render`);
|
|
462
|
+
}
|
|
463
|
+
const writer = createStringWriter();
|
|
464
|
+
writer.writeLines(
|
|
465
|
+
`// ${virtualFilePrefix}/${markoServeFilePrefix}route__${route.key}.marko`
|
|
466
|
+
);
|
|
467
|
+
writer.branch("imports");
|
|
468
|
+
writer.writeLines("");
|
|
469
|
+
writeRouteTemplateTag(writer, [...route.layouts, route.page]);
|
|
470
|
+
return writer.end();
|
|
471
|
+
}
|
|
472
|
+
function writeRouteTemplateTag(writer, [file, ...rest], index = 1) {
|
|
473
|
+
if (file) {
|
|
474
|
+
const isLast = !rest.length;
|
|
475
|
+
const tag = isLast ? "page" : `layout${index}`;
|
|
476
|
+
writer.branch("imports").writeLines(`import ${tag} from './${file.importPath}';`);
|
|
477
|
+
if (isLast) {
|
|
478
|
+
writer.writeLines(`<${tag} ...input />`);
|
|
479
|
+
} else {
|
|
480
|
+
writer.writeBlockStart(`<${tag} ...input>`);
|
|
481
|
+
writeRouteTemplateTag(writer, rest, index + 1);
|
|
482
|
+
writer.writeBlockEnd(`</>`);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
function renderRouteEntry(route) {
|
|
487
|
+
var _a;
|
|
488
|
+
const { key, index, handler, page, middleware, meta } = route;
|
|
489
|
+
const verbs = getVerbs(route);
|
|
490
|
+
if (!verbs) {
|
|
491
|
+
throw new Error(
|
|
492
|
+
`Route ${key} doesn't have a handler or page for any HTTP verbs`
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
const writer = createStringWriter();
|
|
496
|
+
writer.writeLines(
|
|
497
|
+
`// ${virtualFilePrefix}/${markoServeFilePrefix}route__${key}.js`
|
|
498
|
+
);
|
|
499
|
+
const imports = writer.branch("imports");
|
|
500
|
+
let i = 1;
|
|
501
|
+
for (const { importPath } of middleware) {
|
|
502
|
+
imports.writeLines(`import middleware$${i} from './${importPath}';`);
|
|
503
|
+
i++;
|
|
504
|
+
}
|
|
505
|
+
if ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.length) {
|
|
506
|
+
const names = handler.verbs.map(
|
|
507
|
+
(verb) => `${verb === "delete" ? "del" : verb} as handler$${verb}`
|
|
508
|
+
);
|
|
509
|
+
imports.writeLines(
|
|
510
|
+
`import { ${names.join(", ")} } from './${handler.importPath}';`
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
if (page) {
|
|
514
|
+
imports.writeLines(
|
|
515
|
+
`import page from '${virtualFilePrefix}/${markoServeFilePrefix}route__${key}.marko${serverEntryQuery}';`
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
if (meta) {
|
|
519
|
+
imports.writeLines(
|
|
520
|
+
`export { default as meta$${index} } from './${meta.importPath}';`
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
if (!page || verbs.length > 1) {
|
|
524
|
+
writer.writeLines("").writeBlockStart(`function create204Response() {`).writeBlockStart(`return new Response(null, {`).writeLines(`status: 204`).writeBlockEnd(`})`).writeBlockEnd(`}`);
|
|
525
|
+
}
|
|
526
|
+
for (const verb of verbs) {
|
|
527
|
+
writeRouteEntryHandler(writer, route, verb);
|
|
528
|
+
}
|
|
529
|
+
return writer.end();
|
|
530
|
+
}
|
|
531
|
+
function writePageResponseContinuation(writer) {
|
|
532
|
+
writer.writeBlock(
|
|
533
|
+
`return new Response(page.stream(ctx), {`,
|
|
534
|
+
["status: 200,", 'headers: { "content-type": "text/html;charset=UTF-8" }'],
|
|
535
|
+
"});"
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
function writeRouteEntryHandler(writer, route, verb) {
|
|
539
|
+
var _a;
|
|
540
|
+
const { key, index, page, handler, middleware } = route;
|
|
541
|
+
const len = middleware.length;
|
|
542
|
+
let nextName;
|
|
543
|
+
let currentName;
|
|
544
|
+
let hasBody = false;
|
|
545
|
+
writer.writeLines("").writeBlockStart(`export async function ${verb}$${index}(ctx) {`);
|
|
546
|
+
const continuations = writer.branch("cont");
|
|
547
|
+
if (page && verb === "get") {
|
|
548
|
+
currentName = "createPageResponse";
|
|
549
|
+
if ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes(verb)) {
|
|
550
|
+
continuations.writeBlockStart(`async function ${currentName}() {`);
|
|
551
|
+
writePageResponseContinuation(continuations);
|
|
552
|
+
continuations.writeBlockEnd("}");
|
|
553
|
+
if (len) {
|
|
554
|
+
nextName = currentName;
|
|
555
|
+
currentName = `__handler$${verb}`;
|
|
556
|
+
continuations.writeBlock(
|
|
557
|
+
`async function ${currentName}() {`,
|
|
558
|
+
[`return await handler$${verb}(ctx, ${nextName});`],
|
|
559
|
+
"}"
|
|
560
|
+
);
|
|
561
|
+
} else {
|
|
562
|
+
writer.writeLines(`return await handler$${verb}(ctx, ${currentName})`);
|
|
563
|
+
hasBody = true;
|
|
564
|
+
}
|
|
565
|
+
} else if (len) {
|
|
566
|
+
continuations.writeBlockStart(`async function ${currentName}() {`);
|
|
567
|
+
writePageResponseContinuation(continuations);
|
|
568
|
+
continuations.writeBlockEnd("}");
|
|
569
|
+
nextName = currentName;
|
|
570
|
+
} else {
|
|
571
|
+
writePageResponseContinuation(continuations);
|
|
572
|
+
hasBody = true;
|
|
573
|
+
}
|
|
574
|
+
} else if (handler) {
|
|
575
|
+
currentName = `__handler$${verb}`;
|
|
576
|
+
if (len) {
|
|
577
|
+
continuations.writeBlock(
|
|
578
|
+
`async function ${currentName}() {`,
|
|
579
|
+
[`return await handler$${verb}(ctx, create204Response);`],
|
|
580
|
+
"}"
|
|
581
|
+
);
|
|
582
|
+
} else {
|
|
583
|
+
writer.writeLines(
|
|
584
|
+
`return await handler$${verb}(ctx, create204Response);`
|
|
585
|
+
);
|
|
586
|
+
hasBody = true;
|
|
587
|
+
}
|
|
588
|
+
} else {
|
|
589
|
+
throw new Error(`Route ${key} has no handler for ${verb} requests`);
|
|
590
|
+
}
|
|
591
|
+
if (!hasBody) {
|
|
592
|
+
let i = len;
|
|
593
|
+
while (--i) {
|
|
594
|
+
nextName = currentName;
|
|
595
|
+
currentName = `__middleware${i + 1}`;
|
|
596
|
+
continuations.writeLines("").writeBlock(
|
|
597
|
+
`async function ${currentName}() {`,
|
|
598
|
+
[`return await middleware$${i + 1}(ctx, ${nextName});`],
|
|
599
|
+
"}"
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
writer.writeLines(`return await middleware$1(ctx, ${currentName});`);
|
|
603
|
+
}
|
|
604
|
+
continuations.join();
|
|
605
|
+
writer.writeBlockEnd("}");
|
|
606
|
+
}
|
|
607
|
+
function renderRouter(routes, options = DefaultCodegenOptions) {
|
|
608
|
+
const writer = createStringWriter();
|
|
609
|
+
writer.writeLines(`// @marko/run/router`);
|
|
610
|
+
const imports = writer.branch("imports");
|
|
611
|
+
for (const route of routes.list) {
|
|
612
|
+
const verbs = getVerbs(route);
|
|
613
|
+
const names = verbs.map((verb) => `${verb}$${route.index}`);
|
|
614
|
+
route.meta && names.push(`meta$${route.index}`);
|
|
615
|
+
imports.writeLines(
|
|
616
|
+
`import { ${names.join(
|
|
617
|
+
", "
|
|
618
|
+
)} } from '${virtualFilePrefix}/${markoServeFilePrefix}route__${route.key}.js';`
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
for (const { key } of Object.values(routes.special)) {
|
|
622
|
+
imports.writeLines(
|
|
623
|
+
`import page$${key} from '${virtualFilePrefix}/${markoServeFilePrefix}special__${key}.marko${serverEntryQuery}';`
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
writer.writeLines("").writeBlockStart(`function matchRoute(method, pathname) {`).writeBlockStart(`switch (method.toLowerCase()) {`);
|
|
627
|
+
for (const verb of httpVerbs) {
|
|
628
|
+
const filteredRoutes = routes.list.filter((route) => hasVerb(route, verb));
|
|
629
|
+
if (filteredRoutes.length) {
|
|
630
|
+
const trie = createRouteTrie(filteredRoutes);
|
|
631
|
+
writer.writeBlockStart(`case '${verb}': {`);
|
|
632
|
+
writeRouterVerb(writer, trie, verb);
|
|
633
|
+
writer.writeBlockEnd("}");
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
writer.writeBlockEnd("}").writeBlockEnd("}");
|
|
637
|
+
writer.writeLines("").writeBlockStart(`async function invokeRoute(route, url, request) {`);
|
|
638
|
+
const errorRoute = routes.special[RoutableFileTypes.Error];
|
|
639
|
+
if (errorRoute) {
|
|
640
|
+
writer.writeBlockStart(`try {`);
|
|
641
|
+
}
|
|
642
|
+
writer.writeBlock(
|
|
643
|
+
`if (route) {`,
|
|
644
|
+
[
|
|
645
|
+
`const [handler, params = {}, meta] = route;`,
|
|
646
|
+
`const response = await handler({ request, url, params, meta });`,
|
|
647
|
+
`if (response) return response;`
|
|
648
|
+
],
|
|
649
|
+
`}`
|
|
650
|
+
);
|
|
651
|
+
const notFoundRoute = routes.special[RoutableFileTypes.NotFound];
|
|
652
|
+
if (notFoundRoute) {
|
|
653
|
+
writer.writeBlockStart(
|
|
654
|
+
`if (request.headers.get('Accept')?.includes('text/html')) {`
|
|
655
|
+
).writeBlock(
|
|
656
|
+
`return new Response(page$404.stream({ request, url, params: {} }), {`,
|
|
657
|
+
[
|
|
658
|
+
`status: 404,`,
|
|
659
|
+
`headers: { "content-type": "text/html;charset=UTF-8" },`
|
|
660
|
+
],
|
|
661
|
+
`});`
|
|
662
|
+
).writeBlockEnd("}");
|
|
663
|
+
}
|
|
664
|
+
writer.writeLines(`return null;`);
|
|
665
|
+
if (errorRoute) {
|
|
666
|
+
writer.indent--;
|
|
667
|
+
writer.writeBlockStart(`} catch (err) {`).writeBlockStart(
|
|
668
|
+
`if (request.headers.get('Accept')?.includes('text/html')) {`
|
|
669
|
+
).writeBlock(
|
|
670
|
+
`return new Response(page$500.stream({ request, url, params: {}, error: err }), {`,
|
|
671
|
+
[
|
|
672
|
+
`status: 500,`,
|
|
673
|
+
`headers: { "content-type": "text/html;charset=UTF-8" },`
|
|
674
|
+
],
|
|
675
|
+
`});`
|
|
676
|
+
).writeBlockEnd("}").writeLines(`throw err;`).writeBlockEnd("}");
|
|
677
|
+
}
|
|
678
|
+
writer.writeBlockEnd("}");
|
|
679
|
+
writer.write(`
|
|
680
|
+
export function getMatchedRoute(method, url) {
|
|
681
|
+
const route = matchRoute(method, url.pathname);
|
|
682
|
+
if (route) {
|
|
683
|
+
const [handler, params = {}, meta] = route;
|
|
684
|
+
return {
|
|
685
|
+
handler,
|
|
686
|
+
params,
|
|
687
|
+
meta,
|
|
688
|
+
async invoke(request) {
|
|
689
|
+
return await invokeRoute(route, url, request);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
export async function handler(context) {
|
|
697
|
+
const response = await router(context.request);
|
|
698
|
+
//if (response.body) {
|
|
699
|
+
// context.waitUntil?.(once(Readable.from(response.body), "end"));
|
|
700
|
+
//}
|
|
701
|
+
return response;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
export async function router(request) {
|
|
705
|
+
try {
|
|
706
|
+
const url = new URL(request.url);
|
|
707
|
+
let { pathname } = url;
|
|
708
|
+
|
|
709
|
+
if (pathname !== '/') {
|
|
710
|
+
if (pathname.endsWith('/')) {
|
|
711
|
+
pathname = pathname.replace(/\\/+$/, '');
|
|
712
|
+
`);
|
|
713
|
+
switch (options.trailingSlashes) {
|
|
714
|
+
case "RedirectWithout":
|
|
715
|
+
writer.write(`
|
|
716
|
+
url.pathname = pathname;
|
|
717
|
+
return Response.redirect(url.href);
|
|
718
|
+
`);
|
|
719
|
+
break;
|
|
720
|
+
case "RedirectWith":
|
|
721
|
+
writer.write(`
|
|
722
|
+
} else {
|
|
723
|
+
url.pathname = pathname + '/';
|
|
724
|
+
return Response.redirect(url.href);
|
|
725
|
+
`);
|
|
726
|
+
break;
|
|
727
|
+
case "RewriteWithout":
|
|
728
|
+
writer.write(`
|
|
729
|
+
url.pathname = pathname;
|
|
730
|
+
`);
|
|
731
|
+
break;
|
|
732
|
+
case "RewriteWith":
|
|
733
|
+
writer.write(`
|
|
734
|
+
} else {
|
|
735
|
+
url.pathname = pathname + '/';
|
|
736
|
+
`);
|
|
737
|
+
break;
|
|
738
|
+
}
|
|
739
|
+
writer.write(`
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
const route = matchRoute(request.method, pathname);
|
|
743
|
+
return await invokeRoute(route, url, request) || new Response(null, {
|
|
744
|
+
statusText: \`Not Found (No route matched \${pathname})\`,
|
|
745
|
+
status: 404
|
|
746
|
+
});
|
|
747
|
+
} catch (err) {
|
|
748
|
+
const message = import.meta.env.DEV
|
|
749
|
+
? \`Internal Server Error (\${err.message})\`
|
|
750
|
+
: "Internal Server Error";
|
|
751
|
+
|
|
752
|
+
return new Response(
|
|
753
|
+
JSON.stringify({
|
|
754
|
+
error: {
|
|
755
|
+
message,
|
|
756
|
+
stack: import.meta.env.DEV
|
|
757
|
+
? \`This will only be seen in development mode\\n\\n\${err.stack}\`
|
|
758
|
+
: ""
|
|
759
|
+
}
|
|
760
|
+
}),
|
|
761
|
+
{
|
|
762
|
+
statusText: message,
|
|
763
|
+
status: 500,
|
|
764
|
+
}
|
|
765
|
+
);
|
|
766
|
+
}
|
|
767
|
+
}`);
|
|
768
|
+
return writer.end();
|
|
769
|
+
}
|
|
770
|
+
function writeRouterVerb(writer, trie, verb, level = 0, pathIndex = 0, useSwitch) {
|
|
771
|
+
const { key, route: value, static: children, dynamic, catchAll } = trie;
|
|
772
|
+
pathIndex += key.length;
|
|
773
|
+
if (level <= 0) {
|
|
774
|
+
level = 0;
|
|
775
|
+
if (value) {
|
|
776
|
+
writer.writeLines(
|
|
777
|
+
`if (pathname === '/') return ${renderMatch(verb, value)}; // ${value.path}`
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
if (children || dynamic) {
|
|
781
|
+
writer.writeLines(
|
|
782
|
+
`const segments = pathname.split('/');`,
|
|
783
|
+
`const len = segments.length;`
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
} else {
|
|
787
|
+
if (!key) {
|
|
788
|
+
writer.writeBlockStart(`if (segments[${level}]) {`);
|
|
789
|
+
} else if (useSwitch) {
|
|
790
|
+
writer.writeBlockStart(`case '${key}':`);
|
|
791
|
+
} else {
|
|
792
|
+
writer.writeBlockStart(
|
|
793
|
+
`if (segments[${level}]?.toLowerCase() === '${key}') {`
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
if (value) {
|
|
797
|
+
writer.writeLines(
|
|
798
|
+
`if (len === ${level + 1}) return ${renderMatch(verb, value)}; // ${value.path}`
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
if (children || dynamic) {
|
|
803
|
+
if (children) {
|
|
804
|
+
if (children.size > 1) {
|
|
805
|
+
writer.writeBlockStart(
|
|
806
|
+
`switch(segments[${level + 1}]?.toLowerCase()) {`
|
|
807
|
+
);
|
|
808
|
+
for (const child of children.values()) {
|
|
809
|
+
writeRouterVerb(writer, child, verb, level + 1, pathIndex, true);
|
|
810
|
+
}
|
|
811
|
+
writer.writeBlockEnd("}");
|
|
812
|
+
} else {
|
|
813
|
+
for (const child of children.values()) {
|
|
814
|
+
writeRouterVerb(writer, child, verb, level + 1, pathIndex);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
if (dynamic) {
|
|
819
|
+
writeRouterVerb(writer, dynamic, verb, level + 1, pathIndex);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
if (catchAll) {
|
|
823
|
+
writer.writeLines(
|
|
824
|
+
`return ${renderMatch(verb, catchAll, pathIndex)}; // ${catchAll.path}`
|
|
825
|
+
);
|
|
826
|
+
if (level > 0) {
|
|
827
|
+
writer.indent--;
|
|
828
|
+
}
|
|
829
|
+
} else if (level === 0) {
|
|
830
|
+
writer.writeLines("return;");
|
|
831
|
+
} else if (useSwitch) {
|
|
832
|
+
writer.writeLines("break;").indent--;
|
|
833
|
+
} else {
|
|
834
|
+
writer.writeBlockEnd("}");
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
function renderParamsInfo(params, pathIndex) {
|
|
838
|
+
let result = "";
|
|
839
|
+
let catchAll = "";
|
|
840
|
+
let dynamicLength = "";
|
|
841
|
+
for (const { name, index } of params) {
|
|
842
|
+
if (index >= 0) {
|
|
843
|
+
result += result ? ", " : "{ ";
|
|
844
|
+
result += `'${name}': segments[${index + 1}]`;
|
|
845
|
+
dynamicLength += ` + segments[${index + 1}].length`;
|
|
846
|
+
} else if (pathIndex && pathIndex >= 0) {
|
|
847
|
+
catchAll = name;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
if (catchAll) {
|
|
851
|
+
result += result ? ", " : "{ ";
|
|
852
|
+
result += `'${catchAll}': pathname.slice(${pathIndex}${dynamicLength})`;
|
|
853
|
+
}
|
|
854
|
+
return result ? result + " }" : "{}";
|
|
855
|
+
}
|
|
856
|
+
function renderMatch(verb, { index, params, meta }, pathIndex) {
|
|
857
|
+
const tuple = [`${verb}$${index}`];
|
|
858
|
+
if (params == null ? void 0 : params.length) {
|
|
859
|
+
tuple[1] = renderParamsInfo(params, pathIndex);
|
|
860
|
+
}
|
|
861
|
+
if (meta) {
|
|
862
|
+
tuple[2] = `meta$${index}`;
|
|
863
|
+
}
|
|
864
|
+
return `[${tuple.join(", ")}]`;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
// src/vite/utils/ast.ts
|
|
868
|
+
var t = __toESM(require("@babel/types"), 1);
|
|
869
|
+
function getExportIdentifiers(astProgramNode) {
|
|
870
|
+
const result = [];
|
|
871
|
+
if (t.isProgram(astProgramNode)) {
|
|
872
|
+
for (const node of astProgramNode.body) {
|
|
873
|
+
if (t.isExportNamedDeclaration(node)) {
|
|
874
|
+
const { declaration, specifiers } = node;
|
|
875
|
+
if (declaration) {
|
|
876
|
+
if (t.isFunctionDeclaration(declaration) && declaration.id) {
|
|
877
|
+
result.push(declaration.id.name);
|
|
878
|
+
} else if (t.isVariableDeclaration(declaration)) {
|
|
879
|
+
for (const declarator of declaration.declarations) {
|
|
880
|
+
if (t.isIdentifier(declarator.id)) {
|
|
881
|
+
result.push(declarator.id.name);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
} else if (specifiers) {
|
|
886
|
+
for (const specifier of specifiers) {
|
|
887
|
+
if (t.isExportSpecifier(specifier) && t.isIdentifier(specifier.exported)) {
|
|
888
|
+
result.push(specifier.exported.name);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
} else if (t.isExportDefaultDeclaration(node)) {
|
|
893
|
+
const { declaration } = node;
|
|
894
|
+
if (t.isObjectExpression(declaration)) {
|
|
895
|
+
for (const property of declaration.properties) {
|
|
896
|
+
if (t.isObjectMember(property) && t.isIdentifier(property.key)) {
|
|
897
|
+
result.push(property.key.name);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
return result;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
// src/vite/utils/log.ts
|
|
908
|
+
var import_cli_table3 = __toESM(require("cli-table3"), 1);
|
|
909
|
+
var import_kleur = __toESM(require("kleur"), 1);
|
|
910
|
+
var import_gzip_size = require("gzip-size");
|
|
911
|
+
var import_pretty_bytes = __toESM(require("pretty-bytes"), 1);
|
|
912
|
+
var HttpVerbColors = {
|
|
913
|
+
get: import_kleur.default.green,
|
|
914
|
+
post: import_kleur.default.magenta,
|
|
915
|
+
put: import_kleur.default.cyan,
|
|
916
|
+
delete: import_kleur.default.red,
|
|
917
|
+
other: import_kleur.default.white
|
|
918
|
+
};
|
|
919
|
+
var HttpVerbOrder = {
|
|
920
|
+
get: 0,
|
|
921
|
+
post: 1,
|
|
922
|
+
put: 2,
|
|
923
|
+
delete: 3
|
|
924
|
+
};
|
|
925
|
+
function logRoutesTable(routes, bundle) {
|
|
926
|
+
const hasMiddleware = routes.list.some((route) => route.middleware.length);
|
|
927
|
+
const hasMeta = routes.list.some((route) => route.meta);
|
|
928
|
+
const headings = ["Method", "Path", "Entry"];
|
|
929
|
+
const colAligns = ["left", "left", "left"];
|
|
930
|
+
if (hasMiddleware) {
|
|
931
|
+
headings.push("MW");
|
|
932
|
+
colAligns.push("right");
|
|
933
|
+
}
|
|
934
|
+
if (hasMeta) {
|
|
935
|
+
headings.push("Meta");
|
|
936
|
+
colAligns.push("center");
|
|
937
|
+
}
|
|
938
|
+
headings.push("Size");
|
|
939
|
+
colAligns.push("right");
|
|
940
|
+
const table = new import_cli_table3.default({
|
|
941
|
+
head: headings.map((title) => import_kleur.default.bold(import_kleur.default.white(title.toUpperCase()))),
|
|
942
|
+
wordWrap: true,
|
|
943
|
+
colAligns,
|
|
944
|
+
style: { compact: true }
|
|
945
|
+
});
|
|
946
|
+
for (const route of routes.list.sort((a, b) => b.score - a.score)) {
|
|
947
|
+
const verbs = getVerbs(route).sort(
|
|
948
|
+
(a, b) => HttpVerbOrder[a] - HttpVerbOrder[b]
|
|
949
|
+
);
|
|
950
|
+
let firstRow = true;
|
|
951
|
+
for (const verb of verbs) {
|
|
952
|
+
let size = "";
|
|
953
|
+
const entryType = [];
|
|
954
|
+
if (route.handler) {
|
|
955
|
+
entryType.push(import_kleur.default.blue("handler"));
|
|
956
|
+
}
|
|
957
|
+
if (verb === "get" && route.page) {
|
|
958
|
+
entryType.push(import_kleur.default.yellow("page"));
|
|
959
|
+
size = prettySize(computeRouteSize(route, bundle));
|
|
960
|
+
}
|
|
961
|
+
const row = [import_kleur.default.bold(HttpVerbColors[verb](verb.toUpperCase()))];
|
|
962
|
+
if (verbs.length === 1 || firstRow) {
|
|
963
|
+
row.push({ rowSpan: verbs.length, content: prettyPath(route.path) });
|
|
964
|
+
firstRow = false;
|
|
965
|
+
}
|
|
966
|
+
row.push(entryType.join(" -> "));
|
|
967
|
+
hasMiddleware && row.push(route.middleware.length || "");
|
|
968
|
+
hasMeta && row.push(route.meta ? "\u2713" : "");
|
|
969
|
+
row.push(size || { hAlign: "center", content: "-" });
|
|
970
|
+
table.push(row);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
for (const [key, route] of Object.entries(routes.special).sort()) {
|
|
974
|
+
const row = [import_kleur.default.bold(import_kleur.default.white("*")), key, import_kleur.default.yellow("page")];
|
|
975
|
+
hasMiddleware && row.push("");
|
|
976
|
+
hasMeta && row.push("");
|
|
977
|
+
row.push(prettySize(computeRouteSize(route, bundle)));
|
|
978
|
+
table.push(row);
|
|
979
|
+
}
|
|
980
|
+
console.log(table.toString());
|
|
981
|
+
}
|
|
982
|
+
function computeRouteSize(route, bundle) {
|
|
983
|
+
if (route.page) {
|
|
984
|
+
for (const chunk of Object.values(bundle)) {
|
|
985
|
+
if (chunk.type === "chunk" && chunk.modules[route.page.filePath]) {
|
|
986
|
+
return computeChunkSize(chunk, bundle);
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
return 0;
|
|
991
|
+
}
|
|
992
|
+
function computeChunkSize(chunk, bundle, seen = /* @__PURE__ */ new Set()) {
|
|
993
|
+
if (chunk.type === "asset") {
|
|
994
|
+
return (0, import_gzip_size.gzipSizeSync)(chunk.source);
|
|
995
|
+
}
|
|
996
|
+
let size = (0, import_gzip_size.gzipSizeSync)(chunk.code);
|
|
997
|
+
for (const id of chunk.imports) {
|
|
998
|
+
if (!seen.has(id)) {
|
|
999
|
+
size += computeChunkSize(bundle[id], bundle, seen);
|
|
1000
|
+
seen.add(id);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
return size;
|
|
1004
|
+
}
|
|
1005
|
+
function prettySize(size) {
|
|
1006
|
+
const _size = (0, import_pretty_bytes.default)(size, {
|
|
1007
|
+
minimumFractionDigits: 1,
|
|
1008
|
+
maximumFractionDigits: 1
|
|
1009
|
+
}).replace(/\sB$/, " B ");
|
|
1010
|
+
if (size < 20 * 1e3)
|
|
1011
|
+
return import_kleur.default.green(_size);
|
|
1012
|
+
if (size < 50 * 1e3)
|
|
1013
|
+
return import_kleur.default.yellow(_size);
|
|
1014
|
+
return import_kleur.default.bold(import_kleur.default.red(_size));
|
|
1015
|
+
}
|
|
1016
|
+
function prettyPath(path3) {
|
|
1017
|
+
return path3.replace(/\/\$\$(.*)$/, (_, p) => "/" + import_kleur.default.bold(import_kleur.default.dim(`*${p}`))).replace(/\/\$([^/]+)/g, (_, p) => "/" + import_kleur.default.bold(import_kleur.default.dim(`:${p}`)));
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
// src/vite/utils/config.ts
|
|
1021
|
+
var KEY = "__MARKO_SERVE_OPTIONS__";
|
|
1022
|
+
function getMarkoServeOptions(viteConfig) {
|
|
1023
|
+
return viteConfig[KEY];
|
|
1024
|
+
}
|
|
1025
|
+
function setMarkoServeOptions(viteConfig, options) {
|
|
1026
|
+
viteConfig[KEY] = options;
|
|
1027
|
+
return viteConfig;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
// src/vite/plugin.ts
|
|
1031
|
+
var markoExt = ".marko";
|
|
1032
|
+
var markoServeFilePrefix2 = "__marko-serve__";
|
|
1033
|
+
function isMarkoFile(id) {
|
|
1034
|
+
return id.endsWith(markoExt);
|
|
1035
|
+
}
|
|
1036
|
+
function markoServe(opts = {}) {
|
|
1037
|
+
const { routesDir = "src/routes", adapter, ...markoOptions } = opts;
|
|
1038
|
+
let store;
|
|
1039
|
+
let root;
|
|
1040
|
+
let resolvedRoutesDir;
|
|
1041
|
+
let isBuild = false;
|
|
1042
|
+
let isSSRBuild = false;
|
|
1043
|
+
let ssrEntryFiles;
|
|
1044
|
+
let devEntryFile;
|
|
1045
|
+
let devServer;
|
|
1046
|
+
let routes;
|
|
1047
|
+
let routeData;
|
|
1048
|
+
let routeDataFilename = "routes.json";
|
|
1049
|
+
let extractVerbs;
|
|
1050
|
+
let resolvedConfig;
|
|
1051
|
+
let isStale = true;
|
|
1052
|
+
let isRendered = false;
|
|
1053
|
+
const virtualFiles = /* @__PURE__ */ new Map();
|
|
1054
|
+
let times = {
|
|
1055
|
+
routesBuild: 0,
|
|
1056
|
+
routesRender: 0
|
|
1057
|
+
};
|
|
1058
|
+
async function setVirtualFiles(render = false) {
|
|
1059
|
+
for (const route of routes.list) {
|
|
1060
|
+
if (render && route.handler) {
|
|
1061
|
+
route.handler.verbs = await extractVerbs(route.handler.filePath);
|
|
1062
|
+
if (!route.handler.verbs.length) {
|
|
1063
|
+
console.warn(
|
|
1064
|
+
`Did not find any valid exports in middleware entry file:'${route.handler.filePath}' - expected to find any of 'get', 'post', 'put' or 'del'`
|
|
1065
|
+
);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
if (route.page) {
|
|
1069
|
+
virtualFiles.set(
|
|
1070
|
+
import_path2.default.join(root, `${markoServeFilePrefix2}route__${route.key}.marko`),
|
|
1071
|
+
render ? renderRouteTemplate(route) : ""
|
|
1072
|
+
);
|
|
1073
|
+
}
|
|
1074
|
+
virtualFiles.set(
|
|
1075
|
+
import_path2.default.join(root, `${markoServeFilePrefix2}route__${route.key}.js`),
|
|
1076
|
+
render ? renderRouteEntry(route) : ""
|
|
1077
|
+
);
|
|
1078
|
+
}
|
|
1079
|
+
for (const route of Object.values(routes.special)) {
|
|
1080
|
+
virtualFiles.set(
|
|
1081
|
+
import_path2.default.join(root, `${markoServeFilePrefix2}special__${route.key}.marko`),
|
|
1082
|
+
render ? renderRouteTemplate(route) : ""
|
|
1083
|
+
);
|
|
1084
|
+
}
|
|
1085
|
+
virtualFiles.set(
|
|
1086
|
+
"@marko/run/router",
|
|
1087
|
+
render ? renderRouter(routes, opts.codegen) : ""
|
|
1088
|
+
);
|
|
1089
|
+
}
|
|
1090
|
+
const buildVirtualFiles = single(async () => {
|
|
1091
|
+
const startTime = performance.now();
|
|
1092
|
+
routes = await buildRoutes(createFSWalker(resolvedRoutesDir), routesDir);
|
|
1093
|
+
times.routesBuild = performance.now() - startTime;
|
|
1094
|
+
await setVirtualFiles(false);
|
|
1095
|
+
isStale = false;
|
|
1096
|
+
isRendered = false;
|
|
1097
|
+
});
|
|
1098
|
+
const renderVirtualFiles = single(async () => {
|
|
1099
|
+
const startTime = performance.now();
|
|
1100
|
+
await setVirtualFiles(true);
|
|
1101
|
+
times.routesRender = performance.now() - startTime;
|
|
1102
|
+
isRendered = true;
|
|
1103
|
+
});
|
|
1104
|
+
return [
|
|
1105
|
+
{
|
|
1106
|
+
name: "marko-run-vite:pre",
|
|
1107
|
+
enforce: "pre",
|
|
1108
|
+
async config(config, env) {
|
|
1109
|
+
var _a, _b, _c;
|
|
1110
|
+
const externalPluginOptions = getMarkoServeOptions(config);
|
|
1111
|
+
if (externalPluginOptions) {
|
|
1112
|
+
opts = (0, import_vite.mergeConfig)(opts, externalPluginOptions);
|
|
1113
|
+
}
|
|
1114
|
+
const adapterOptions = await ((_a = adapter == null ? void 0 : adapter.pluginOptions) == null ? void 0 : _a.call(adapter, opts));
|
|
1115
|
+
if (adapterOptions) {
|
|
1116
|
+
opts = (0, import_vite.mergeConfig)(opts, adapterOptions);
|
|
1117
|
+
}
|
|
1118
|
+
root = (0, import_vite.normalizePath)(config.root || process.cwd());
|
|
1119
|
+
store = opts.store || new import_vite2.FileStore(
|
|
1120
|
+
`marko-serve-vite-${import_crypto.default.createHash("SHA1").update(root).digest("hex")}`
|
|
1121
|
+
);
|
|
1122
|
+
isBuild = env.command === "build";
|
|
1123
|
+
isSSRBuild = isBuild && Boolean((_b = config.build) == null ? void 0 : _b.ssr);
|
|
1124
|
+
resolvedRoutesDir = import_path2.default.resolve(root, routesDir);
|
|
1125
|
+
devEntryFile = import_path2.default.join(root, "index.html");
|
|
1126
|
+
let pluginConfig = {
|
|
1127
|
+
logLevel: isBuild ? "warn" : void 0,
|
|
1128
|
+
define: isBuild ? {
|
|
1129
|
+
"process.env.NODE_ENV": "'production'"
|
|
1130
|
+
} : void 0,
|
|
1131
|
+
build: {
|
|
1132
|
+
emptyOutDir: isSSRBuild
|
|
1133
|
+
}
|
|
1134
|
+
};
|
|
1135
|
+
const adapterConfig = await ((_c = adapter == null ? void 0 : adapter.viteConfig) == null ? void 0 : _c.call(adapter, config));
|
|
1136
|
+
if (adapterConfig) {
|
|
1137
|
+
pluginConfig = (0, import_vite.mergeConfig)(pluginConfig, adapterConfig);
|
|
1138
|
+
}
|
|
1139
|
+
return setMarkoServeOptions(pluginConfig, opts);
|
|
1140
|
+
},
|
|
1141
|
+
configResolved(config) {
|
|
1142
|
+
resolvedConfig = config;
|
|
1143
|
+
const {
|
|
1144
|
+
ssr,
|
|
1145
|
+
rollupOptions: { input }
|
|
1146
|
+
} = config.build;
|
|
1147
|
+
if (typeof ssr === "string") {
|
|
1148
|
+
ssrEntryFiles = [ssr];
|
|
1149
|
+
} else if (typeof input === "string") {
|
|
1150
|
+
ssrEntryFiles = [input];
|
|
1151
|
+
} else if (Array.isArray(input)) {
|
|
1152
|
+
ssrEntryFiles = input;
|
|
1153
|
+
} else if (input) {
|
|
1154
|
+
ssrEntryFiles = Object.values(input);
|
|
1155
|
+
} else {
|
|
1156
|
+
ssrEntryFiles = [];
|
|
1157
|
+
}
|
|
1158
|
+
},
|
|
1159
|
+
configureServer(_server) {
|
|
1160
|
+
devServer = _server;
|
|
1161
|
+
devServer.watcher.on("all", async (type, filename) => {
|
|
1162
|
+
const file = import_path2.default.parse(filename);
|
|
1163
|
+
if (filename.startsWith(resolvedRoutesDir) && isRoutableFile(file.base)) {
|
|
1164
|
+
if (type === "add") {
|
|
1165
|
+
isStale = true;
|
|
1166
|
+
} else if (type === "unlink") {
|
|
1167
|
+
isStale = true;
|
|
1168
|
+
} else if (type === "change") {
|
|
1169
|
+
const match = matchRoutableFile(file.base);
|
|
1170
|
+
if (match === RoutableFileTypes.Handler) {
|
|
1171
|
+
isStale = true;
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
if (isStale) {
|
|
1175
|
+
for (const id of virtualFiles.keys()) {
|
|
1176
|
+
devServer.watcher.emit("change", id);
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
});
|
|
1181
|
+
},
|
|
1182
|
+
async buildStart(_options) {
|
|
1183
|
+
if (isBuild && !isSSRBuild) {
|
|
1184
|
+
try {
|
|
1185
|
+
routeData = JSON.parse(
|
|
1186
|
+
await store.get(routeDataFilename)
|
|
1187
|
+
);
|
|
1188
|
+
} catch {
|
|
1189
|
+
this.error(
|
|
1190
|
+
`You must run the "ssr" build before the "browser" build.`
|
|
1191
|
+
);
|
|
1192
|
+
}
|
|
1193
|
+
routes = routeData.routes;
|
|
1194
|
+
times = routeData.times;
|
|
1195
|
+
for (const { key, code } of routeData.files) {
|
|
1196
|
+
virtualFiles.set(key, code);
|
|
1197
|
+
}
|
|
1198
|
+
isStale = false;
|
|
1199
|
+
isRendered = true;
|
|
1200
|
+
} else {
|
|
1201
|
+
extractVerbs = isBuild ? getVerbsFromFileBuild.bind(null, this) : getVerbsFromFileDev.bind(null, devServer);
|
|
1202
|
+
}
|
|
1203
|
+
},
|
|
1204
|
+
async resolveId(importee, importer, { ssr }) {
|
|
1205
|
+
let resolved;
|
|
1206
|
+
if (importee.startsWith(virtualFilePrefix)) {
|
|
1207
|
+
importee = import_path2.default.resolve(
|
|
1208
|
+
root,
|
|
1209
|
+
importee.slice(virtualFilePrefix.length + 1)
|
|
1210
|
+
);
|
|
1211
|
+
} else if (!isBuild && importer === devEntryFile && importee.startsWith(`/${markoServeFilePrefix2}`)) {
|
|
1212
|
+
importee = import_path2.default.resolve(root, "." + importee);
|
|
1213
|
+
}
|
|
1214
|
+
if (isStale) {
|
|
1215
|
+
await buildVirtualFiles();
|
|
1216
|
+
}
|
|
1217
|
+
if (virtualFiles.has(importee)) {
|
|
1218
|
+
resolved = importee;
|
|
1219
|
+
if (isBuild && !ssr && isMarkoFile(resolved)) {
|
|
1220
|
+
resolved += browserEntryQuery;
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
return resolved || null;
|
|
1224
|
+
},
|
|
1225
|
+
async load(id) {
|
|
1226
|
+
var _a;
|
|
1227
|
+
if (virtualFiles.has(id)) {
|
|
1228
|
+
if (!isRendered) {
|
|
1229
|
+
await renderVirtualFiles();
|
|
1230
|
+
if (!isBuild) {
|
|
1231
|
+
await ((_a = opts == null ? void 0 : opts.emitRoutes) == null ? void 0 : _a.call(opts, routes.list));
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
return virtualFiles.get(id);
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
},
|
|
1238
|
+
...(0, import_vite2.default)({
|
|
1239
|
+
...markoOptions,
|
|
1240
|
+
get store() {
|
|
1241
|
+
return store;
|
|
1242
|
+
}
|
|
1243
|
+
}),
|
|
1244
|
+
{
|
|
1245
|
+
name: "marko-run-vite:post",
|
|
1246
|
+
enforce: "post",
|
|
1247
|
+
async writeBundle(options, bundle) {
|
|
1248
|
+
var _a;
|
|
1249
|
+
if (isSSRBuild) {
|
|
1250
|
+
const builtEntries = Object.values(bundle).reduce(
|
|
1251
|
+
(acc, item) => {
|
|
1252
|
+
if (item.type === "chunk" && item.isEntry) {
|
|
1253
|
+
acc.push(import_path2.default.join(options.dir, item.fileName));
|
|
1254
|
+
}
|
|
1255
|
+
return acc;
|
|
1256
|
+
},
|
|
1257
|
+
[]
|
|
1258
|
+
);
|
|
1259
|
+
routeData = {
|
|
1260
|
+
routes,
|
|
1261
|
+
files: [],
|
|
1262
|
+
times,
|
|
1263
|
+
builtEntries,
|
|
1264
|
+
sourceEntries: ssrEntryFiles
|
|
1265
|
+
};
|
|
1266
|
+
for (const [key, code] of virtualFiles) {
|
|
1267
|
+
routeData.files.push({ key, code });
|
|
1268
|
+
}
|
|
1269
|
+
await store.set(routeDataFilename, JSON.stringify(routeData));
|
|
1270
|
+
await ((_a = opts == null ? void 0 : opts.emitRoutes) == null ? void 0 : _a.call(opts, routes.list));
|
|
1271
|
+
} else if (isBuild) {
|
|
1272
|
+
logRoutesTable(routes, bundle);
|
|
1273
|
+
}
|
|
1274
|
+
},
|
|
1275
|
+
async closeBundle() {
|
|
1276
|
+
if (isBuild && !isSSRBuild && (adapter == null ? void 0 : adapter.buildEnd)) {
|
|
1277
|
+
await adapter.buildEnd(
|
|
1278
|
+
resolvedConfig,
|
|
1279
|
+
routes.list,
|
|
1280
|
+
routeData.builtEntries,
|
|
1281
|
+
routeData.sourceEntries
|
|
1282
|
+
);
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
];
|
|
1287
|
+
}
|
|
1288
|
+
async function getVerbsFromFileBuild(context, filePath) {
|
|
1289
|
+
const verbs = [];
|
|
1290
|
+
const result = await context.load({
|
|
1291
|
+
id: filePath,
|
|
1292
|
+
resolveDependencies: false
|
|
1293
|
+
});
|
|
1294
|
+
if (result) {
|
|
1295
|
+
const exportIds = getExportIdentifiers(result.ast);
|
|
1296
|
+
for (const id of exportIds) {
|
|
1297
|
+
const verb = id === "del" ? "delete" : id;
|
|
1298
|
+
if (httpVerbs.includes(verb)) {
|
|
1299
|
+
verbs.push(verb);
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
return verbs;
|
|
1304
|
+
}
|
|
1305
|
+
async function getVerbsFromFileDev(devServer, filePath) {
|
|
1306
|
+
const verbs = [];
|
|
1307
|
+
const result = await devServer.transformRequest(filePath, { ssr: true });
|
|
1308
|
+
if (result && result.code) {
|
|
1309
|
+
const verbMatchReg = /__vite_ssr_exports__,\s+["'](get|post|put|del)["']/g;
|
|
1310
|
+
let match = verbMatchReg.exec(result.code);
|
|
1311
|
+
while (match) {
|
|
1312
|
+
const verb = match[1] === "del" ? "delete" : match[1];
|
|
1313
|
+
if (httpVerbs.includes(verb)) {
|
|
1314
|
+
verbs.push(verb);
|
|
1315
|
+
}
|
|
1316
|
+
match = verbMatchReg.exec(result.code);
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
return verbs;
|
|
1320
|
+
}
|
|
1321
|
+
function single(fn) {
|
|
1322
|
+
let promise;
|
|
1323
|
+
return async (...args) => {
|
|
1324
|
+
if (promise) {
|
|
1325
|
+
return promise;
|
|
1326
|
+
}
|
|
1327
|
+
promise = fn(...args);
|
|
1328
|
+
const result = await promise;
|
|
1329
|
+
promise = void 0;
|
|
1330
|
+
return result;
|
|
1331
|
+
};
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// src/vite/utils/server.ts
|
|
1335
|
+
var import_net = __toESM(require("net"), 1);
|
|
1336
|
+
var import_child_process = __toESM(require("child_process"), 1);
|
|
1337
|
+
async function spawnServer(cmd, port = 0, cwd = process.cwd(), wait = 3e4) {
|
|
1338
|
+
if (port <= 0) {
|
|
1339
|
+
port = await getAvailablePort();
|
|
1340
|
+
}
|
|
1341
|
+
const proc = import_child_process.default.spawn(cmd, {
|
|
1342
|
+
cwd,
|
|
1343
|
+
shell: true,
|
|
1344
|
+
stdio: "inherit",
|
|
1345
|
+
windowsHide: true,
|
|
1346
|
+
env: { NODE_ENV: "development", ...process.env, PORT: `${port}` }
|
|
1347
|
+
});
|
|
1348
|
+
const close = () => {
|
|
1349
|
+
proc.unref();
|
|
1350
|
+
proc.kill();
|
|
1351
|
+
};
|
|
1352
|
+
let remaining = wait > 0 ? wait : Infinity;
|
|
1353
|
+
while (!await isPortInUse(port)) {
|
|
1354
|
+
if (remaining >= 100) {
|
|
1355
|
+
remaining -= 100;
|
|
1356
|
+
await sleep(100);
|
|
1357
|
+
} else {
|
|
1358
|
+
close();
|
|
1359
|
+
throw new Error(
|
|
1360
|
+
`site-write: timeout while wating for server to start on port "${port}".`
|
|
1361
|
+
);
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
return {
|
|
1365
|
+
port,
|
|
1366
|
+
close
|
|
1367
|
+
};
|
|
1368
|
+
}
|
|
1369
|
+
async function isPortInUse(port) {
|
|
1370
|
+
return new Promise((resolve) => {
|
|
1371
|
+
const connection = import_net.default.connect(port).setNoDelay(true).setKeepAlive(false).on("error", () => done(false)).on("connect", () => done(true));
|
|
1372
|
+
function done(connected) {
|
|
1373
|
+
connection.end();
|
|
1374
|
+
resolve(connected);
|
|
1375
|
+
}
|
|
1376
|
+
});
|
|
1377
|
+
}
|
|
1378
|
+
async function getAvailablePort() {
|
|
1379
|
+
return new Promise((resolve) => {
|
|
1380
|
+
const server = import_net.default.createServer().listen(0, () => {
|
|
1381
|
+
const { port } = server.address();
|
|
1382
|
+
server.close(() => resolve(port));
|
|
1383
|
+
});
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
function sleep(ms) {
|
|
1387
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1388
|
+
}
|
|
1389
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1390
|
+
0 && (module.exports = {
|
|
1391
|
+
getAvailablePort,
|
|
1392
|
+
isPortInUse,
|
|
1393
|
+
spawnServer
|
|
1394
|
+
});
|