@marko/run 0.0.1-beta2 → 0.0.1-beta4
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 +102 -74
- package/dist/adapter/default-entry.mjs +9 -3
- package/dist/adapter/dev-server.d.ts +1 -1
- package/dist/adapter/index.cjs +189 -8
- package/dist/adapter/index.d.ts +1 -0
- package/dist/adapter/index.js +188 -7
- package/dist/adapter/middleware.cjs +199 -0
- package/dist/adapter/middleware.d.ts +55 -0
- package/dist/adapter/middleware.js +168 -0
- package/dist/cli/default.config.mjs +1 -1
- package/dist/cli/index.mjs +88 -59
- package/dist/runtime/index.cjs +0 -16
- package/dist/runtime/index.d.ts +10 -2
- package/dist/runtime/index.js +0 -7
- package/dist/runtime/internal.cjs +148 -0
- package/dist/runtime/internal.d.ts +10 -0
- package/dist/runtime/internal.js +115 -0
- package/dist/runtime/router.cjs +9 -7
- package/dist/runtime/router.d.ts +4 -4
- package/dist/runtime/router.js +7 -5
- package/dist/runtime/types.d.ts +29 -16
- package/dist/vite/codegen/index.d.ts +4 -3
- package/dist/vite/codegen/writer.d.ts +1 -1
- package/dist/vite/constants.d.ts +3 -2
- package/dist/vite/index.cjs +557 -282
- package/dist/vite/index.d.ts +4 -3
- package/dist/vite/index.js +554 -282
- package/dist/vite/types.d.ts +14 -7
- package/dist/vite/utils/config.d.ts +5 -3
- package/dist/vite/utils/server.d.ts +3 -1
- package/package.json +23 -11
package/dist/vite/index.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
// src/vite/plugin.ts
|
|
2
2
|
import path2 from "path";
|
|
3
3
|
import crypto from "crypto";
|
|
4
|
+
import fs2 from "fs";
|
|
5
|
+
import glob from "glob";
|
|
4
6
|
import { mergeConfig, normalizePath } from "vite";
|
|
5
7
|
import markoVitePlugin, { FileStore } from "@marko/vite";
|
|
6
8
|
|
|
7
9
|
// src/vite/constants.ts
|
|
8
|
-
var
|
|
9
|
-
var virtualFilePrefix = "virtual:marko-
|
|
10
|
+
var markoRunFilePrefix = "__marko-run__";
|
|
11
|
+
var virtualFilePrefix = "virtual:marko-run";
|
|
10
12
|
var virtualRoutesPrefix = `${virtualFilePrefix}/routes`;
|
|
13
|
+
var virtualRuntimePrefix = `${virtualFilePrefix}/internal`;
|
|
11
14
|
var httpVerbs = ["get", "post", "put", "delete"];
|
|
12
15
|
var serverEntryQuery = "?marko-server-entry";
|
|
13
16
|
var browserEntryQuery = "?marko-browser-entry";
|
|
@@ -47,15 +50,20 @@ function isSpecialType(type) {
|
|
|
47
50
|
return type === RoutableFileTypes.NotFound || type === RoutableFileTypes.Error;
|
|
48
51
|
}
|
|
49
52
|
async function buildRoutes(walk, basePath) {
|
|
50
|
-
|
|
53
|
+
if (basePath) {
|
|
54
|
+
basePath = basePath.replace(/^\/+|\/+$/g, "");
|
|
55
|
+
}
|
|
56
|
+
const dirStack = [];
|
|
51
57
|
const pathStack = [];
|
|
52
58
|
const paramStack = [];
|
|
53
59
|
const layoutsStack = [];
|
|
54
60
|
const middlewareStack = [];
|
|
55
61
|
const routes = /* @__PURE__ */ new Map();
|
|
56
62
|
const special = {};
|
|
63
|
+
const middleware = /* @__PURE__ */ new Set();
|
|
57
64
|
let isRoot = true;
|
|
58
|
-
let
|
|
65
|
+
let nextFileId = 1;
|
|
66
|
+
let nextRouteIndex = 1;
|
|
59
67
|
let current;
|
|
60
68
|
let children = [];
|
|
61
69
|
await walk({
|
|
@@ -83,10 +91,13 @@ async function buildRoutes(walk, basePath) {
|
|
|
83
91
|
if (!entries) {
|
|
84
92
|
current.files.set(type, entries = []);
|
|
85
93
|
}
|
|
94
|
+
const relativePath = current.originalPath ? `${current.originalPath}/${entry.name}` : entry.name;
|
|
86
95
|
entries.push({
|
|
96
|
+
id: String(nextFileId++),
|
|
87
97
|
type,
|
|
88
98
|
filePath: entry.path,
|
|
89
|
-
|
|
99
|
+
relativePath,
|
|
100
|
+
importPath: `${basePath}/${relativePath}`,
|
|
90
101
|
name: entry.name,
|
|
91
102
|
verbs: type === RoutableFileTypes.Page ? ["get"] : void 0
|
|
92
103
|
});
|
|
@@ -97,20 +108,24 @@ async function buildRoutes(walk, basePath) {
|
|
|
97
108
|
return;
|
|
98
109
|
}
|
|
99
110
|
const { path: path3, files } = current;
|
|
100
|
-
const
|
|
101
|
-
const
|
|
111
|
+
const localMiddleware = (_a = files.get(RoutableFileTypes.Middleware)) == null ? void 0 : _a[0];
|
|
112
|
+
const localLayout = (_b = files.get(RoutableFileTypes.Layout)) == null ? void 0 : _b[0];
|
|
102
113
|
const handler = (_c = files.get(RoutableFileTypes.Handler)) == null ? void 0 : _c[0];
|
|
103
114
|
const page = (_d = files.get(RoutableFileTypes.Page)) == null ? void 0 : _d[0];
|
|
104
115
|
const middlewareStackLength = middlewareStack.length;
|
|
105
116
|
const layoutsStackLength = layoutsStack.length;
|
|
106
|
-
|
|
107
|
-
|
|
117
|
+
if (localMiddleware) {
|
|
118
|
+
middlewareStack.push(localMiddleware);
|
|
119
|
+
}
|
|
120
|
+
if (localLayout) {
|
|
121
|
+
layoutsStack.push(localLayout);
|
|
122
|
+
}
|
|
108
123
|
if (handler || page) {
|
|
109
124
|
const key = path3.replace(/(\$\$?)[^\/]*/g, "$1").replace(/^\/+/, "").replace(/[^a-z0-9_$\/]+/gi, "").replace(/\//g, "__") || "index";
|
|
110
125
|
if (routes.has(key)) {
|
|
111
126
|
console.warn(`Duplicate route for path ${path3} -- ignoring`, current);
|
|
112
127
|
} else {
|
|
113
|
-
const index =
|
|
128
|
+
const index = nextRouteIndex++;
|
|
114
129
|
routes.set(key, {
|
|
115
130
|
index,
|
|
116
131
|
key,
|
|
@@ -123,6 +138,9 @@ async function buildRoutes(walk, basePath) {
|
|
|
123
138
|
handler,
|
|
124
139
|
score: scorePath(path3, index)
|
|
125
140
|
});
|
|
141
|
+
for (const mw of middlewareStack) {
|
|
142
|
+
middleware.add(mw);
|
|
143
|
+
}
|
|
126
144
|
}
|
|
127
145
|
}
|
|
128
146
|
if (isRoot) {
|
|
@@ -158,7 +176,7 @@ async function buildRoutes(walk, basePath) {
|
|
|
158
176
|
if (name.charCodeAt(0) === 36) {
|
|
159
177
|
if (name.charCodeAt(1) === 36) {
|
|
160
178
|
paramStack.push({
|
|
161
|
-
name: name.slice(2) || "
|
|
179
|
+
name: name.slice(2) || "rest",
|
|
162
180
|
index: -1
|
|
163
181
|
});
|
|
164
182
|
} else if (name.length > 1) {
|
|
@@ -188,7 +206,8 @@ async function buildRoutes(walk, basePath) {
|
|
|
188
206
|
});
|
|
189
207
|
return {
|
|
190
208
|
list: [...routes.values()],
|
|
191
|
-
special
|
|
209
|
+
special,
|
|
210
|
+
middleware: [...middleware]
|
|
192
211
|
};
|
|
193
212
|
}
|
|
194
213
|
|
|
@@ -238,6 +257,17 @@ function createWriter(sink, options) {
|
|
|
238
257
|
let firstOpenIndex = 0;
|
|
239
258
|
const branches = [];
|
|
240
259
|
const openWriters = /* @__PURE__ */ new Map();
|
|
260
|
+
function write(data) {
|
|
261
|
+
if (!writer.__isActive) {
|
|
262
|
+
throw new Error("Cannot write to branch that has been joined");
|
|
263
|
+
}
|
|
264
|
+
if (openWriters.size) {
|
|
265
|
+
buffer += data;
|
|
266
|
+
} else {
|
|
267
|
+
sink(data);
|
|
268
|
+
}
|
|
269
|
+
return writer;
|
|
270
|
+
}
|
|
241
271
|
const writer = {
|
|
242
272
|
__isActive: true,
|
|
243
273
|
get indent() {
|
|
@@ -254,24 +284,16 @@ function createWriter(sink, options) {
|
|
|
254
284
|
}
|
|
255
285
|
}
|
|
256
286
|
},
|
|
257
|
-
write(data) {
|
|
258
|
-
if (
|
|
259
|
-
|
|
260
|
-
}
|
|
261
|
-
if (openWriters.size) {
|
|
262
|
-
buffer += data;
|
|
263
|
-
} else {
|
|
264
|
-
sink(data);
|
|
287
|
+
write(data, indent = false) {
|
|
288
|
+
if (indent && indentString) {
|
|
289
|
+
write(indentString);
|
|
265
290
|
}
|
|
266
|
-
return
|
|
291
|
+
return write(data);
|
|
267
292
|
},
|
|
268
293
|
writeLines(...lines) {
|
|
269
294
|
for (const line of lines) {
|
|
270
295
|
if (line) {
|
|
271
|
-
|
|
272
|
-
writer.write(indentString);
|
|
273
|
-
}
|
|
274
|
-
writer.write(line);
|
|
296
|
+
writer.write(line, true);
|
|
275
297
|
}
|
|
276
298
|
writer.write("\n");
|
|
277
299
|
}
|
|
@@ -418,16 +440,13 @@ function hasVerb(route, verb) {
|
|
|
418
440
|
}
|
|
419
441
|
|
|
420
442
|
// src/vite/codegen/index.ts
|
|
421
|
-
var DefaultCodegenOptions = {
|
|
422
|
-
trailingSlashes: "RedirectWithout"
|
|
423
|
-
};
|
|
424
443
|
function renderRouteTemplate(route) {
|
|
425
444
|
if (!route.page) {
|
|
426
445
|
throw new Error(`Route ${route.key} has no page to render`);
|
|
427
446
|
}
|
|
428
447
|
const writer = createStringWriter();
|
|
429
448
|
writer.writeLines(
|
|
430
|
-
`// ${virtualFilePrefix}/${
|
|
449
|
+
`// ${virtualFilePrefix}/${markoRunFilePrefix}route__${route.key}.marko`
|
|
431
450
|
);
|
|
432
451
|
writer.branch("imports");
|
|
433
452
|
writer.writeLines("");
|
|
@@ -459,25 +478,47 @@ function renderRouteEntry(route) {
|
|
|
459
478
|
}
|
|
460
479
|
const writer = createStringWriter();
|
|
461
480
|
writer.writeLines(
|
|
462
|
-
`// ${virtualFilePrefix}/${
|
|
481
|
+
`// ${virtualFilePrefix}/${markoRunFilePrefix}route__${key}.js`
|
|
463
482
|
);
|
|
464
483
|
const imports = writer.branch("imports");
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
i++;
|
|
484
|
+
const runtimeImports = [];
|
|
485
|
+
if (handler) {
|
|
486
|
+
runtimeImports.push("normalize");
|
|
469
487
|
}
|
|
470
|
-
if (
|
|
471
|
-
|
|
472
|
-
|
|
488
|
+
if (handler || middleware.length) {
|
|
489
|
+
runtimeImports.push("call");
|
|
490
|
+
}
|
|
491
|
+
if (!page || verbs.length > 1) {
|
|
492
|
+
runtimeImports.push("noContent");
|
|
493
|
+
}
|
|
494
|
+
if (runtimeImports.length) {
|
|
495
|
+
imports.writeLines(
|
|
496
|
+
`import { ${runtimeImports.join(", ")} } from '${virtualRuntimePrefix}';`
|
|
473
497
|
);
|
|
498
|
+
}
|
|
499
|
+
if (middleware.length) {
|
|
500
|
+
const names = middleware.map((m) => `mware$${m.id}`);
|
|
501
|
+
imports.writeLines(
|
|
502
|
+
`import { ${names.join(
|
|
503
|
+
", "
|
|
504
|
+
)} } from '${virtualFilePrefix}/${markoRunFilePrefix}middleware.js';`
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
if ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.length) {
|
|
508
|
+
writer.writeLines("");
|
|
509
|
+
const names = [];
|
|
510
|
+
for (const verb of handler.verbs) {
|
|
511
|
+
const name = verb === "delete" ? "del" : verb;
|
|
512
|
+
names.push(name);
|
|
513
|
+
writer.writeLines(`const handler$${name} = normalize(${name});`);
|
|
514
|
+
}
|
|
474
515
|
imports.writeLines(
|
|
475
516
|
`import { ${names.join(", ")} } from './${handler.importPath}';`
|
|
476
517
|
);
|
|
477
518
|
}
|
|
478
519
|
if (page) {
|
|
479
520
|
imports.writeLines(
|
|
480
|
-
`import page from '${virtualFilePrefix}/${
|
|
521
|
+
`import page from '${virtualFilePrefix}/${markoRunFilePrefix}route__${key}.marko${serverEntryQuery}';`
|
|
481
522
|
);
|
|
482
523
|
}
|
|
483
524
|
if (meta) {
|
|
@@ -485,21 +526,27 @@ function renderRouteEntry(route) {
|
|
|
485
526
|
`export { default as meta$${index} } from './${meta.importPath}';`
|
|
486
527
|
);
|
|
487
528
|
}
|
|
488
|
-
if (!page || verbs.length > 1) {
|
|
489
|
-
writer.writeLines("").writeBlockStart(`function create204Response() {`).writeBlockStart(`return new Response(null, {`).writeLines(`status: 204`).writeBlockEnd(`})`).writeBlockEnd(`}`);
|
|
490
|
-
}
|
|
491
529
|
for (const verb of verbs) {
|
|
492
530
|
writeRouteEntryHandler(writer, route, verb);
|
|
493
531
|
}
|
|
494
532
|
return writer.end();
|
|
495
533
|
}
|
|
496
|
-
function
|
|
534
|
+
function writePageResponse(writer, wrapFn) {
|
|
497
535
|
writer.writeBlock(
|
|
498
|
-
`return new Response(page.stream(
|
|
536
|
+
`${wrapFn ? `const ${wrapFn} = () =>` : `return`} new Response(page.stream(buildInput()), {`,
|
|
499
537
|
["status: 200,", 'headers: { "content-type": "text/html;charset=UTF-8" }'],
|
|
500
538
|
"});"
|
|
501
539
|
);
|
|
502
540
|
}
|
|
541
|
+
function writeMiddleware(writer, middleware, next, wrapFn) {
|
|
542
|
+
if (wrapFn) {
|
|
543
|
+
writer.writeLines(
|
|
544
|
+
`const ${wrapFn} = () => call(${middleware}, ${next}, context);`
|
|
545
|
+
);
|
|
546
|
+
} else {
|
|
547
|
+
writer.writeLines(`return call(${middleware}, ${next}, context);`);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
503
550
|
function writeRouteEntryHandler(writer, route, verb) {
|
|
504
551
|
var _a;
|
|
505
552
|
const { key, index, page, handler, middleware } = route;
|
|
@@ -507,47 +554,38 @@ function writeRouteEntryHandler(writer, route, verb) {
|
|
|
507
554
|
let nextName;
|
|
508
555
|
let currentName;
|
|
509
556
|
let hasBody = false;
|
|
510
|
-
writer.writeLines("").writeBlockStart(
|
|
557
|
+
writer.writeLines("").writeBlockStart(
|
|
558
|
+
`export async function ${verb}$${index}(context, buildInput) {`
|
|
559
|
+
);
|
|
511
560
|
const continuations = writer.branch("cont");
|
|
512
561
|
if (page && verb === "get") {
|
|
513
|
-
currentName = "
|
|
562
|
+
currentName = "__page";
|
|
514
563
|
if ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes(verb)) {
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
continuations.writeBlockEnd("}");
|
|
564
|
+
const name = `handler$${verb}`;
|
|
565
|
+
writePageResponse(continuations, currentName);
|
|
518
566
|
if (len) {
|
|
519
567
|
nextName = currentName;
|
|
520
|
-
currentName = `
|
|
521
|
-
continuations
|
|
522
|
-
`async function ${currentName}() {`,
|
|
523
|
-
[`return await handler$${verb}(ctx, ${nextName});`],
|
|
524
|
-
"}"
|
|
525
|
-
);
|
|
568
|
+
currentName = `__${name}`;
|
|
569
|
+
writeMiddleware(continuations, name, nextName, currentName);
|
|
526
570
|
} else {
|
|
527
|
-
writer
|
|
571
|
+
writeMiddleware(writer, name, currentName);
|
|
528
572
|
hasBody = true;
|
|
529
573
|
}
|
|
530
574
|
} else if (len) {
|
|
531
|
-
continuations
|
|
532
|
-
writePageResponseContinuation(continuations);
|
|
533
|
-
continuations.writeBlockEnd("}");
|
|
575
|
+
writePageResponse(continuations, currentName);
|
|
534
576
|
nextName = currentName;
|
|
535
577
|
} else {
|
|
536
|
-
|
|
578
|
+
writePageResponse(continuations);
|
|
537
579
|
hasBody = true;
|
|
538
580
|
}
|
|
539
581
|
} else if (handler) {
|
|
540
|
-
|
|
582
|
+
const name = `handler$${verb}`;
|
|
583
|
+
currentName = `__${name}`;
|
|
584
|
+
nextName = "noContent";
|
|
541
585
|
if (len) {
|
|
542
|
-
continuations
|
|
543
|
-
`async function ${currentName}() {`,
|
|
544
|
-
[`return await handler$${verb}(ctx, create204Response);`],
|
|
545
|
-
"}"
|
|
546
|
-
);
|
|
586
|
+
writeMiddleware(continuations, name, nextName, currentName);
|
|
547
587
|
} else {
|
|
548
|
-
writer
|
|
549
|
-
`return await handler$${verb}(ctx, create204Response);`
|
|
550
|
-
);
|
|
588
|
+
writeMiddleware(writer, name, nextName);
|
|
551
589
|
hasBody = true;
|
|
552
590
|
}
|
|
553
591
|
} else {
|
|
@@ -555,24 +593,26 @@ function writeRouteEntryHandler(writer, route, verb) {
|
|
|
555
593
|
}
|
|
556
594
|
if (!hasBody) {
|
|
557
595
|
let i = len;
|
|
558
|
-
while (--
|
|
596
|
+
while (i--) {
|
|
597
|
+
const { id } = middleware[i];
|
|
598
|
+
const name = `mware$${id}`;
|
|
559
599
|
nextName = currentName;
|
|
560
|
-
currentName = `
|
|
561
|
-
continuations
|
|
562
|
-
`async function ${currentName}() {`,
|
|
563
|
-
[`return await middleware$${i + 1}(ctx, ${nextName});`],
|
|
564
|
-
"}"
|
|
565
|
-
);
|
|
600
|
+
currentName = i ? `__${name}` : "";
|
|
601
|
+
writeMiddleware(continuations, name, nextName, currentName);
|
|
566
602
|
}
|
|
567
|
-
writer.writeLines(`return await middleware$1(ctx, ${currentName});`);
|
|
568
603
|
}
|
|
569
604
|
continuations.join();
|
|
570
605
|
writer.writeBlockEnd("}");
|
|
571
606
|
}
|
|
572
|
-
function renderRouter(routes, options =
|
|
607
|
+
function renderRouter(routes, options = {
|
|
608
|
+
trailingSlashes: "RedirectWithout"
|
|
609
|
+
}) {
|
|
573
610
|
const writer = createStringWriter();
|
|
574
611
|
writer.writeLines(`// @marko/run/router`);
|
|
575
612
|
const imports = writer.branch("imports");
|
|
613
|
+
imports.writeLines(
|
|
614
|
+
`import { RequestNotHandled, RequestNotMatched, createInput } from 'virtual:marko-run/internal';`
|
|
615
|
+
);
|
|
576
616
|
for (const route of routes.list) {
|
|
577
617
|
const verbs = getVerbs(route);
|
|
578
618
|
const names = verbs.map((verb) => `${verb}$${route.index}`);
|
|
@@ -580,15 +620,15 @@ function renderRouter(routes, options = DefaultCodegenOptions) {
|
|
|
580
620
|
imports.writeLines(
|
|
581
621
|
`import { ${names.join(
|
|
582
622
|
", "
|
|
583
|
-
)} } from '${virtualFilePrefix}/${
|
|
623
|
+
)} } from '${virtualFilePrefix}/${markoRunFilePrefix}route__${route.key}.js';`
|
|
584
624
|
);
|
|
585
625
|
}
|
|
586
626
|
for (const { key } of Object.values(routes.special)) {
|
|
587
627
|
imports.writeLines(
|
|
588
|
-
`import page$${key} from '${virtualFilePrefix}/${
|
|
628
|
+
`import page$${key} from '${virtualFilePrefix}/${markoRunFilePrefix}special__${key}.marko${serverEntryQuery}';`
|
|
589
629
|
);
|
|
590
630
|
}
|
|
591
|
-
writer.writeLines(
|
|
631
|
+
writer.writeLines(``).writeBlockStart(`function findRoute(method, pathname) {`).writeBlockStart(`switch (method.toLowerCase()) {`);
|
|
592
632
|
for (const verb of httpVerbs) {
|
|
593
633
|
const filteredRoutes = routes.list.filter((route) => hasVerb(route, verb));
|
|
594
634
|
if (filteredRoutes.length) {
|
|
@@ -598,120 +638,105 @@ function renderRouter(routes, options = DefaultCodegenOptions) {
|
|
|
598
638
|
writer.writeBlockEnd("}");
|
|
599
639
|
}
|
|
600
640
|
}
|
|
601
|
-
writer.writeBlockEnd("}").writeBlockEnd("}");
|
|
602
|
-
writer.
|
|
603
|
-
|
|
604
|
-
if (
|
|
605
|
-
|
|
641
|
+
writer.writeBlockEnd("}").writeLines("return null;").writeBlockEnd("}");
|
|
642
|
+
writer.write(`
|
|
643
|
+
export function matchRoute(method, pathname) {
|
|
644
|
+
if (!pathname) {
|
|
645
|
+
pathname = '/';
|
|
646
|
+
} else if (pathname.charAt(0) !== '/') {
|
|
647
|
+
pathname = '/' + pathname;
|
|
606
648
|
}
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
649
|
+
return findRoute(method, pathname);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
export async function invokeRoute(route, context) {
|
|
653
|
+
try {
|
|
654
|
+
const buildInput = createInput(context);
|
|
655
|
+
if (route) {
|
|
656
|
+
context.params = route.params;
|
|
657
|
+
context.meta = route.meta;
|
|
658
|
+
try {
|
|
659
|
+
const response = await route.handler(context, buildInput);
|
|
660
|
+
if (response) return response;
|
|
661
|
+
} catch (error) {
|
|
662
|
+
if (error === RequestNotHandled) {
|
|
663
|
+
return;
|
|
664
|
+
} else if (error !== RequestNotMatched) {
|
|
665
|
+
throw error;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
`).indent = 2;
|
|
669
|
+
if (routes.special[RoutableFileTypes.NotFound]) {
|
|
670
|
+
writer.write(
|
|
671
|
+
` } else {
|
|
672
|
+
context.params = {};
|
|
673
|
+
context.meta = {};
|
|
674
|
+
}
|
|
675
|
+
if (context.request.headers.get('Accept')?.includes('text/html')) {
|
|
676
|
+
return new Response(page$404.stream(buildInput()), {
|
|
677
|
+
status: 404,
|
|
678
|
+
headers: { "content-type": "text/html;charset=UTF-8" },
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
`
|
|
682
|
+
);
|
|
683
|
+
} else {
|
|
684
|
+
writer.writeBlockEnd("}");
|
|
628
685
|
}
|
|
629
|
-
writer.
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
writer.writeBlockStart(
|
|
633
|
-
`if (request.headers.get('Accept')?.includes('text/html')) {`
|
|
686
|
+
writer.indent--;
|
|
687
|
+
writer.writeBlockStart(`} catch (error) {`);
|
|
688
|
+
if (routes.special[RoutableFileTypes.Error]) {
|
|
689
|
+
writer.writeBlockStart(
|
|
690
|
+
`if (context.request.headers.get('Accept')?.includes('text/html')) {`
|
|
634
691
|
).writeBlock(
|
|
635
|
-
`return new Response(page$500.stream({
|
|
692
|
+
`return new Response(page$500.stream(buildInput({ error })), {`,
|
|
636
693
|
[
|
|
637
694
|
`status: 500,`,
|
|
638
695
|
`headers: { "content-type": "text/html;charset=UTF-8" },`
|
|
639
696
|
],
|
|
640
697
|
`});`
|
|
641
|
-
).writeBlockEnd("}")
|
|
642
|
-
}
|
|
643
|
-
writer.writeBlockEnd("}");
|
|
644
|
-
writer.write(`
|
|
645
|
-
export function getMatchedRoute(method, url) {
|
|
646
|
-
const route = matchRoute(method, url.pathname);
|
|
647
|
-
if (route) {
|
|
648
|
-
const [handler, params = {}, meta] = route;
|
|
649
|
-
return {
|
|
650
|
-
handler,
|
|
651
|
-
params,
|
|
652
|
-
meta,
|
|
653
|
-
async invoke(request) {
|
|
654
|
-
return await invokeRoute(route, url, request);
|
|
655
|
-
}
|
|
656
|
-
}
|
|
698
|
+
).writeBlockEnd("}");
|
|
657
699
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
export async function handler(context) {
|
|
662
|
-
const response = await router(context.request);
|
|
663
|
-
//if (response.body) {
|
|
664
|
-
// context.waitUntil?.(once(Readable.from(response.body), "end"));
|
|
665
|
-
//}
|
|
666
|
-
return response;
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
export async function router(request) {
|
|
700
|
+
writer.writeLines(`throw error;`).writeBlockEnd("}").writeBlockEnd("}").write(`
|
|
701
|
+
export async function router(context) {
|
|
670
702
|
try {
|
|
671
|
-
const url =
|
|
672
|
-
let { pathname } = url;
|
|
673
|
-
|
|
674
|
-
if (pathname !== '/') {
|
|
675
|
-
if (pathname.endsWith('/')) {
|
|
676
|
-
pathname = pathname.replace(/\\/+$/, '');
|
|
677
|
-
`);
|
|
703
|
+
const { url, method } = context;
|
|
704
|
+
let { pathname } = url;`);
|
|
678
705
|
switch (options.trailingSlashes) {
|
|
679
706
|
case "RedirectWithout":
|
|
680
707
|
writer.write(`
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
708
|
+
if (pathname !== '/' && pathname.endsWith('/')) {
|
|
709
|
+
url.pathname = pathname.slice(0, -1);
|
|
710
|
+
return Response.redirect(url);
|
|
711
|
+
}`);
|
|
684
712
|
break;
|
|
685
713
|
case "RedirectWith":
|
|
686
714
|
writer.write(`
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
`);
|
|
715
|
+
if (pathname !== '/' && !pathname.endsWith('/')) {
|
|
716
|
+
url.pathname = pathname + '/';
|
|
717
|
+
return Response.redirect(url);
|
|
718
|
+
}`);
|
|
691
719
|
break;
|
|
692
720
|
case "RewriteWithout":
|
|
693
721
|
writer.write(`
|
|
694
|
-
|
|
695
|
-
|
|
722
|
+
if (pathname !== '/' && pathname.endsWith('/')) {
|
|
723
|
+
url.pathname = pathname = pathname.slice(0, -1);
|
|
724
|
+
}`);
|
|
696
725
|
break;
|
|
697
726
|
case "RewriteWith":
|
|
698
727
|
writer.write(`
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
`);
|
|
728
|
+
if (pathname !== '/' && !pathname.endsWith('/')) {
|
|
729
|
+
url.pathname = pathname = pathname + '/';
|
|
730
|
+
}`);
|
|
702
731
|
break;
|
|
703
732
|
}
|
|
704
|
-
writer.write(`
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
statusText: \`Not Found (No route matched \${pathname})\`,
|
|
710
|
-
status: 404
|
|
711
|
-
});
|
|
712
|
-
} catch (err) {
|
|
733
|
+
writer.write(`
|
|
734
|
+
|
|
735
|
+
const route = matchRoute(method, pathname);
|
|
736
|
+
return await invokeRoute(route, context);
|
|
737
|
+
} catch (error) {
|
|
713
738
|
const message = import.meta.env.DEV
|
|
714
|
-
? \`Internal Server Error (\${
|
|
739
|
+
? \`Internal Server Error (\${error.message})\`
|
|
715
740
|
: "Internal Server Error";
|
|
716
741
|
|
|
717
742
|
return new Response(
|
|
@@ -719,7 +744,7 @@ export async function router(request) {
|
|
|
719
744
|
error: {
|
|
720
745
|
message,
|
|
721
746
|
stack: import.meta.env.DEV
|
|
722
|
-
? \`This will only be seen in development mode\\n\\n\${
|
|
747
|
+
? \`This will only be seen in development mode\\n\\n\${error.stack}\`
|
|
723
748
|
: ""
|
|
724
749
|
}
|
|
725
750
|
}),
|
|
@@ -732,101 +757,259 @@ export async function router(request) {
|
|
|
732
757
|
}`);
|
|
733
758
|
return writer.end();
|
|
734
759
|
}
|
|
735
|
-
function writeRouterVerb(writer, trie, verb, level = 0,
|
|
736
|
-
const {
|
|
737
|
-
|
|
738
|
-
if (level
|
|
739
|
-
|
|
740
|
-
if (
|
|
741
|
-
writer.writeLines(
|
|
742
|
-
`if (pathname === '/') return ${renderMatch(verb, value)}; // ${value.path}`
|
|
743
|
-
);
|
|
744
|
-
}
|
|
745
|
-
if (children || dynamic) {
|
|
746
|
-
writer.writeLines(
|
|
747
|
-
`const segments = pathname.split('/');`,
|
|
748
|
-
`const len = segments.length;`
|
|
749
|
-
);
|
|
750
|
-
}
|
|
751
|
-
} else {
|
|
752
|
-
if (!key) {
|
|
753
|
-
writer.writeBlockStart(`if (segments[${level}]) {`);
|
|
754
|
-
} else if (useSwitch) {
|
|
755
|
-
writer.writeBlockStart(`case '${key}':`);
|
|
756
|
-
} else {
|
|
757
|
-
writer.writeBlockStart(
|
|
758
|
-
`if (segments[${level}]?.toLowerCase() === '${key}') {`
|
|
759
|
-
);
|
|
760
|
-
}
|
|
761
|
-
if (value) {
|
|
760
|
+
function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
|
|
761
|
+
const { route, dynamic, catchAll } = trie;
|
|
762
|
+
let closeCount = 0;
|
|
763
|
+
if (level === 0) {
|
|
764
|
+
writer.writeLines(`const len = pathname.length;`);
|
|
765
|
+
if (route) {
|
|
762
766
|
writer.writeLines(
|
|
763
|
-
`if (len ===
|
|
767
|
+
`if (len === 1) return ${renderMatch(verb, route)}; // ${route.path}`
|
|
764
768
|
);
|
|
769
|
+
} else if (trie.static || dynamic) {
|
|
770
|
+
writer.writeBlockStart(`if (len > 1) {`);
|
|
771
|
+
closeCount++;
|
|
765
772
|
}
|
|
766
773
|
}
|
|
767
|
-
if (
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
774
|
+
if (trie.static || dynamic) {
|
|
775
|
+
const next = level + 1;
|
|
776
|
+
const index = `i${next}`;
|
|
777
|
+
let terminal;
|
|
778
|
+
let children;
|
|
779
|
+
writer.writeLines(`const ${index} = pathname.indexOf('/', ${offset}) + 1;`);
|
|
780
|
+
if (trie.static) {
|
|
781
|
+
for (const child of trie.static.values()) {
|
|
782
|
+
if (child.route) {
|
|
783
|
+
(terminal ?? (terminal = [])).push(child);
|
|
775
784
|
}
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
785
|
+
if (child.static || child.dynamic || child.catchAll) {
|
|
786
|
+
(children ?? (children = [])).push(child);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
if (terminal || (dynamic == null ? void 0 : dynamic.route)) {
|
|
791
|
+
closeCount++;
|
|
792
|
+
writer.writeBlockStart(`if (!${index} || ${index} === len) {`);
|
|
793
|
+
let value = `pathname.slice(${offset}, ${index} ? -1 : len)`;
|
|
794
|
+
if (dynamic == null ? void 0 : dynamic.route) {
|
|
795
|
+
const segment = `s${next}`;
|
|
796
|
+
writer.writeLines(`const ${segment} = ${value};`);
|
|
797
|
+
value = segment;
|
|
798
|
+
}
|
|
799
|
+
if (terminal) {
|
|
800
|
+
const useSwitch = terminal.length > 1;
|
|
801
|
+
if (useSwitch) {
|
|
802
|
+
writer.writeBlockStart(`switch (${value}.toLowerCase()) {`);
|
|
803
|
+
}
|
|
804
|
+
for (const { key, route: route2 } of terminal) {
|
|
805
|
+
if (useSwitch) {
|
|
806
|
+
writer.write(`case '${key}': `, true);
|
|
807
|
+
} else {
|
|
808
|
+
writer.write(`if (${value}.toLowerCase() === '${key}') `, true);
|
|
809
|
+
}
|
|
810
|
+
writer.write(
|
|
811
|
+
`return ${renderMatch(verb, route2)}; // ${route2.path}
|
|
812
|
+
`
|
|
813
|
+
);
|
|
814
|
+
}
|
|
815
|
+
if (useSwitch) {
|
|
816
|
+
writer.writeBlockEnd("}");
|
|
780
817
|
}
|
|
781
818
|
}
|
|
819
|
+
if (dynamic == null ? void 0 : dynamic.route) {
|
|
820
|
+
writer.writeLines(
|
|
821
|
+
`if (${value}) return ${renderMatch(verb, dynamic.route)}; // ${dynamic.route.path}`
|
|
822
|
+
);
|
|
823
|
+
}
|
|
782
824
|
}
|
|
783
|
-
if (dynamic) {
|
|
784
|
-
|
|
825
|
+
if (children || (dynamic == null ? void 0 : dynamic.static) || (dynamic == null ? void 0 : dynamic.dynamic) || (dynamic == null ? void 0 : dynamic.catchAll)) {
|
|
826
|
+
if (terminal || (dynamic == null ? void 0 : dynamic.route)) {
|
|
827
|
+
writer.writeBlockEnd("} else {").indent++;
|
|
828
|
+
} else {
|
|
829
|
+
writer.writeBlockStart(`if (${index} && ${index} !== len) {`);
|
|
830
|
+
closeCount++;
|
|
831
|
+
}
|
|
832
|
+
let value = `pathname.slice(${offset}, ${index} - 1)`;
|
|
833
|
+
if ((dynamic == null ? void 0 : dynamic.static) || (dynamic == null ? void 0 : dynamic.dynamic)) {
|
|
834
|
+
const segment = `s${next}`;
|
|
835
|
+
writer.writeLines(`const ${segment} = ${value};`);
|
|
836
|
+
value = segment;
|
|
837
|
+
}
|
|
838
|
+
if (children) {
|
|
839
|
+
const useSwitch = children.length > 1;
|
|
840
|
+
if (useSwitch) {
|
|
841
|
+
writer.writeBlockStart(`switch (${value}.toLowerCase()) {`);
|
|
842
|
+
}
|
|
843
|
+
for (const child of children) {
|
|
844
|
+
if (useSwitch) {
|
|
845
|
+
writer.writeBlockStart(`case '${child.key}': {`);
|
|
846
|
+
} else {
|
|
847
|
+
writer.writeBlockStart(
|
|
848
|
+
`if (${value}.toLowerCase() === '${child.key}') {`
|
|
849
|
+
);
|
|
850
|
+
}
|
|
851
|
+
const nextOffset = typeof offset === "string" ? index : offset + child.key.length + 1;
|
|
852
|
+
writeRouterVerb(writer, child, verb, next, nextOffset);
|
|
853
|
+
writer.writeBlockEnd("}");
|
|
854
|
+
}
|
|
855
|
+
if (useSwitch) {
|
|
856
|
+
writer.writeBlockEnd("}");
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
if ((dynamic == null ? void 0 : dynamic.static) || (dynamic == null ? void 0 : dynamic.dynamic) || (dynamic == null ? void 0 : dynamic.catchAll)) {
|
|
860
|
+
writer.writeBlockStart(`if (${value}) {`);
|
|
861
|
+
writeRouterVerb(writer, dynamic, verb, next, index);
|
|
862
|
+
writer.writeBlockEnd(`}`);
|
|
863
|
+
}
|
|
785
864
|
}
|
|
786
865
|
}
|
|
866
|
+
while (closeCount--) {
|
|
867
|
+
writer.writeBlockEnd("}");
|
|
868
|
+
}
|
|
787
869
|
if (catchAll) {
|
|
788
870
|
writer.writeLines(
|
|
789
|
-
`return ${renderMatch(verb, catchAll,
|
|
871
|
+
`return ${renderMatch(verb, catchAll, String(offset))}; // ${catchAll.path}`
|
|
790
872
|
);
|
|
791
|
-
if (level > 0) {
|
|
792
|
-
writer.indent--;
|
|
793
|
-
}
|
|
794
873
|
} else if (level === 0) {
|
|
795
|
-
writer.writeLines("return;");
|
|
796
|
-
} else if (useSwitch) {
|
|
797
|
-
writer.writeLines("break;").indent--;
|
|
798
|
-
} else {
|
|
799
|
-
writer.writeBlockEnd("}");
|
|
874
|
+
writer.writeLines("return null;");
|
|
800
875
|
}
|
|
801
876
|
}
|
|
877
|
+
function wrapPropertyName(name) {
|
|
878
|
+
return /^[^A-Za-z_$]|[^A-Za-z0-9$_]/.test(name) ? `'${name}'` : name;
|
|
879
|
+
}
|
|
802
880
|
function renderParamsInfo(params, pathIndex) {
|
|
881
|
+
if (!params.length) {
|
|
882
|
+
return "{}";
|
|
883
|
+
}
|
|
803
884
|
let result = "";
|
|
804
885
|
let catchAll = "";
|
|
805
|
-
let
|
|
886
|
+
let sep = "{";
|
|
806
887
|
for (const { name, index } of params) {
|
|
807
888
|
if (index >= 0) {
|
|
808
|
-
result +=
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
} else if (pathIndex && pathIndex >= 0) {
|
|
889
|
+
result += `${sep} ${wrapPropertyName(name)}: s${index + 1}`;
|
|
890
|
+
sep || (sep = ",");
|
|
891
|
+
} else if (pathIndex) {
|
|
812
892
|
catchAll = name;
|
|
813
893
|
}
|
|
814
894
|
}
|
|
815
895
|
if (catchAll) {
|
|
816
|
-
result +=
|
|
817
|
-
|
|
896
|
+
result += `${sep} ${wrapPropertyName(
|
|
897
|
+
catchAll
|
|
898
|
+
)}: pathname.slice(${pathIndex})`;
|
|
818
899
|
}
|
|
819
900
|
return result ? result + " }" : "{}";
|
|
820
901
|
}
|
|
821
|
-
function
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
tuple[1] = renderParamsInfo(params, pathIndex);
|
|
902
|
+
function renderParamsInfoType(params) {
|
|
903
|
+
if (!params.length) {
|
|
904
|
+
return "{}";
|
|
825
905
|
}
|
|
826
|
-
|
|
827
|
-
|
|
906
|
+
let result = "{";
|
|
907
|
+
for (const { name } of params) {
|
|
908
|
+
result += ` ${wrapPropertyName(name)}: string;`;
|
|
909
|
+
}
|
|
910
|
+
return result + " }";
|
|
911
|
+
}
|
|
912
|
+
function renderMatch(verb, route, pathIndex) {
|
|
913
|
+
var _a;
|
|
914
|
+
const handler = `${verb}$${route.index}`;
|
|
915
|
+
const params = ((_a = route.params) == null ? void 0 : _a.length) ? renderParamsInfo(route.params, pathIndex) : "{}";
|
|
916
|
+
const meta = route.meta ? `meta$${route.index}` : "{}";
|
|
917
|
+
return `{ handler: ${handler}, params: ${params}, meta: ${meta} }`;
|
|
918
|
+
}
|
|
919
|
+
function renderMiddleware(middleware) {
|
|
920
|
+
const writer = createStringWriter();
|
|
921
|
+
writer.writeLines(
|
|
922
|
+
`// ${virtualFilePrefix}/${markoRunFilePrefix}middleware.js`
|
|
923
|
+
);
|
|
924
|
+
const imports = writer.branch("imports");
|
|
925
|
+
imports.writeLines(`import { normalize } from 'virtual:marko-run/internal';`);
|
|
926
|
+
writer.writeLines("");
|
|
927
|
+
for (const { id, importPath } of middleware) {
|
|
928
|
+
const importName = `mware${id}`;
|
|
929
|
+
imports.writeLines(`import ${importName} from './${importPath}';`);
|
|
930
|
+
writer.writeLines(`export const mware$${id} = normalize(${importName});`);
|
|
931
|
+
}
|
|
932
|
+
imports.join();
|
|
933
|
+
return writer.end();
|
|
934
|
+
}
|
|
935
|
+
function stripTsExtension(path3) {
|
|
936
|
+
const index = path3.lastIndexOf(".");
|
|
937
|
+
if (index !== -1) {
|
|
938
|
+
const ext = path3.slice(index + 1);
|
|
939
|
+
if (ext.toLowerCase() === "ts") {
|
|
940
|
+
return path3.slice(0, index);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
return path3;
|
|
944
|
+
}
|
|
945
|
+
function renderRouteTypeInfo(routes, pathPrefix = ".") {
|
|
946
|
+
const writer = createStringWriter();
|
|
947
|
+
writer.writeLines(
|
|
948
|
+
`/*
|
|
949
|
+
WARNING: This file is automatically generated and any changes made to it will be overwritten without warning.
|
|
950
|
+
Do NOT manually edit this file or your changes will be lost.
|
|
951
|
+
*/
|
|
952
|
+
`,
|
|
953
|
+
`import type { HandlerLike, Route } from "@marko/run";
|
|
954
|
+
`
|
|
955
|
+
);
|
|
956
|
+
const routesWriter = writer.branch("types");
|
|
957
|
+
const middlewareRouteTypes = /* @__PURE__ */ new Map();
|
|
958
|
+
for (const route of routes.list) {
|
|
959
|
+
const { meta, handler, params, middleware } = route;
|
|
960
|
+
const routeType = `Route${route.index}`;
|
|
961
|
+
const pathType = `\`${route.path.replace(
|
|
962
|
+
/\/\$(\$?)([^\/]*)/,
|
|
963
|
+
(_, catchAll, name) => catchAll ? `/:${name || "rest"}*` : `/:${name}`
|
|
964
|
+
)}\``;
|
|
965
|
+
const paramsType = params ? renderParamsInfoType(params) : "{}";
|
|
966
|
+
let metaType = "undefined";
|
|
967
|
+
if (meta) {
|
|
968
|
+
metaType = `typeof import('${pathPrefix}/${stripTsExtension(
|
|
969
|
+
meta.relativePath
|
|
970
|
+
)}')`;
|
|
971
|
+
if (/\.(ts|js|mjs)$/.test(meta.relativePath)) {
|
|
972
|
+
metaType += `['default']`;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
if (handler) {
|
|
976
|
+
writeRouteTypeModule(writer, pathPrefix, handler.relativePath, routeType);
|
|
977
|
+
}
|
|
978
|
+
if (middleware) {
|
|
979
|
+
let i = 0;
|
|
980
|
+
for (const mw of middleware) {
|
|
981
|
+
const existing = middlewareRouteTypes.get(mw);
|
|
982
|
+
if (!existing) {
|
|
983
|
+
middlewareRouteTypes.set(mw, {
|
|
984
|
+
routeTypes: [routeType],
|
|
985
|
+
middleware: middleware.slice(0, i)
|
|
986
|
+
});
|
|
987
|
+
} else {
|
|
988
|
+
existing.routeTypes.push(routeType);
|
|
989
|
+
}
|
|
990
|
+
i++;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
routesWriter.writeLines(
|
|
994
|
+
`interface ${routeType} extends Route<${paramsType}, ${metaType}, ${pathType}> {}`
|
|
995
|
+
);
|
|
828
996
|
}
|
|
829
|
-
|
|
997
|
+
for (const [file, { routeTypes }] of middlewareRouteTypes) {
|
|
998
|
+
const routeType = routeTypes.length > 1 ? routeTypes.join(" | ") : routeTypes[0];
|
|
999
|
+
writeRouteTypeModule(writer, pathPrefix, file.relativePath, routeType);
|
|
1000
|
+
}
|
|
1001
|
+
return writer.end();
|
|
1002
|
+
}
|
|
1003
|
+
function writeRouteTypeModule(writer, pathPrefix, path3, routeType) {
|
|
1004
|
+
writer.writeLines(`
|
|
1005
|
+
declare module '${pathPrefix}/${stripTsExtension(path3)}' {
|
|
1006
|
+
namespace Marko {
|
|
1007
|
+
type CurrentRoute = ${routeType};
|
|
1008
|
+
type Handler<_Params = CurrentRoute['params'], _Meta = CurrentRoute['meta']> = HandlerLike<CurrentRoute>;
|
|
1009
|
+
function route(handler: Handler): typeof handler;
|
|
1010
|
+
function route<_Params = CurrentRoute['params'], _Meta = CurrentRoute['meta']>(handler: Handler): typeof handler;
|
|
1011
|
+
}
|
|
1012
|
+
}`);
|
|
830
1013
|
}
|
|
831
1014
|
|
|
832
1015
|
// src/vite/utils/ast.ts
|
|
@@ -873,7 +1056,7 @@ function getExportIdentifiers(astProgramNode) {
|
|
|
873
1056
|
import Table from "cli-table3";
|
|
874
1057
|
import kleur from "kleur";
|
|
875
1058
|
import { gzipSizeSync } from "gzip-size";
|
|
876
|
-
import
|
|
1059
|
+
import format from "human-format";
|
|
877
1060
|
var HttpVerbColors = {
|
|
878
1061
|
get: kleur.green,
|
|
879
1062
|
post: kleur.magenta,
|
|
@@ -900,7 +1083,7 @@ function logRoutesTable(routes, bundle) {
|
|
|
900
1083
|
headings.push("Meta");
|
|
901
1084
|
colAligns.push("center");
|
|
902
1085
|
}
|
|
903
|
-
headings.push("Size");
|
|
1086
|
+
headings.push("Size/GZip");
|
|
904
1087
|
colAligns.push("right");
|
|
905
1088
|
const table = new Table({
|
|
906
1089
|
head: headings.map((title) => kleur.bold(kleur.white(title.toUpperCase()))),
|
|
@@ -931,7 +1114,7 @@ function logRoutesTable(routes, bundle) {
|
|
|
931
1114
|
row.push(entryType.join(" -> "));
|
|
932
1115
|
hasMiddleware && row.push(route.middleware.length || "");
|
|
933
1116
|
hasMeta && row.push(route.meta ? "\u2713" : "");
|
|
934
|
-
row.push(size ||
|
|
1117
|
+
row.push(size || "");
|
|
935
1118
|
table.push(row);
|
|
936
1119
|
}
|
|
937
1120
|
}
|
|
@@ -947,54 +1130,75 @@ function logRoutesTable(routes, bundle) {
|
|
|
947
1130
|
function computeRouteSize(route, bundle) {
|
|
948
1131
|
if (route.page) {
|
|
949
1132
|
for (const chunk of Object.values(bundle)) {
|
|
950
|
-
if (chunk.type === "chunk"
|
|
951
|
-
|
|
1133
|
+
if (chunk.type === "chunk") {
|
|
1134
|
+
for (const key of Object.keys(chunk.modules)) {
|
|
1135
|
+
if (key.startsWith(route.page.filePath)) {
|
|
1136
|
+
return computeChunkSize(chunk, bundle);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
952
1139
|
}
|
|
953
1140
|
}
|
|
954
1141
|
}
|
|
955
|
-
return 0;
|
|
1142
|
+
return [0, 0];
|
|
1143
|
+
}
|
|
1144
|
+
function byteSize(str) {
|
|
1145
|
+
return new Blob([str]).size;
|
|
956
1146
|
}
|
|
957
1147
|
function computeChunkSize(chunk, bundle, seen = /* @__PURE__ */ new Set()) {
|
|
958
1148
|
if (chunk.type === "asset") {
|
|
959
|
-
return
|
|
1149
|
+
return [
|
|
1150
|
+
byteSize(chunk.source),
|
|
1151
|
+
gzipSizeSync(chunk.source)
|
|
1152
|
+
];
|
|
960
1153
|
}
|
|
961
|
-
|
|
1154
|
+
const size = [byteSize(chunk.code), gzipSizeSync(chunk.code)];
|
|
962
1155
|
for (const id of chunk.imports) {
|
|
963
1156
|
if (!seen.has(id)) {
|
|
964
|
-
|
|
1157
|
+
const [bytes, compBytes] = computeChunkSize(bundle[id], bundle, seen);
|
|
1158
|
+
size[0] += bytes;
|
|
1159
|
+
size[1] += compBytes;
|
|
965
1160
|
seen.add(id);
|
|
966
1161
|
}
|
|
967
1162
|
}
|
|
968
1163
|
return size;
|
|
969
1164
|
}
|
|
970
|
-
function prettySize(
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
}).
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
if (
|
|
978
|
-
|
|
979
|
-
|
|
1165
|
+
function prettySize([bytes, compBytes]) {
|
|
1166
|
+
if (bytes <= 0) {
|
|
1167
|
+
return kleur.gray("0.0 kB");
|
|
1168
|
+
}
|
|
1169
|
+
const [size, prefix] = format(bytes, { decimals: 1 }).split(/\s+/);
|
|
1170
|
+
const compSize = format(compBytes, { decimals: 1, prefix, unit: "B" });
|
|
1171
|
+
let str = kleur.white(size) + kleur.gray("/");
|
|
1172
|
+
if (compBytes < 20 * 1e3)
|
|
1173
|
+
str += kleur.green(compSize);
|
|
1174
|
+
else if (compBytes < 50 * 1e3)
|
|
1175
|
+
str += kleur.yellow(compSize);
|
|
1176
|
+
else
|
|
1177
|
+
kleur.bold(kleur.red(compSize));
|
|
1178
|
+
return str;
|
|
980
1179
|
}
|
|
981
1180
|
function prettyPath(path3) {
|
|
982
1181
|
return path3.replace(/\/\$\$(.*)$/, (_, p) => "/" + kleur.bold(kleur.dim(`*${p}`))).replace(/\/\$([^/]+)/g, (_, p) => "/" + kleur.bold(kleur.dim(`:${p}`)));
|
|
983
1182
|
}
|
|
984
1183
|
|
|
985
1184
|
// src/vite/utils/config.ts
|
|
986
|
-
var
|
|
987
|
-
|
|
988
|
-
|
|
1185
|
+
var PluginConfigKey = "__MARKO_RUN_PLUGIN_CONFIG__";
|
|
1186
|
+
var AdapterConfigKey = "__MARKO_RUN_ADAPTER_CONFIG__";
|
|
1187
|
+
function getConfig(obj, key) {
|
|
1188
|
+
return obj[key];
|
|
989
1189
|
}
|
|
990
|
-
function
|
|
991
|
-
|
|
992
|
-
return
|
|
1190
|
+
function setConfig(obj, key, value) {
|
|
1191
|
+
obj[key] = value;
|
|
1192
|
+
return obj;
|
|
993
1193
|
}
|
|
1194
|
+
var getExternalPluginOptions = (viteConfig) => getConfig(viteConfig, PluginConfigKey);
|
|
1195
|
+
var setExternalPluginOptions = (viteConfig, value) => setConfig(viteConfig, PluginConfigKey, value);
|
|
1196
|
+
var getExternalAdapterOptions = (viteConfig) => getConfig(viteConfig, AdapterConfigKey);
|
|
994
1197
|
|
|
995
1198
|
// src/vite/plugin.ts
|
|
1199
|
+
import { fileURLToPath } from "url";
|
|
1200
|
+
var __dirname = fileURLToPath(new URL(".", import.meta.url));
|
|
996
1201
|
var markoExt = ".marko";
|
|
997
|
-
var markoServeFilePrefix2 = "__marko-serve__";
|
|
998
1202
|
function isMarkoFile(id) {
|
|
999
1203
|
return id.endsWith(markoExt);
|
|
1000
1204
|
}
|
|
@@ -1003,8 +1207,10 @@ function markoServe(opts = {}) {
|
|
|
1003
1207
|
let store;
|
|
1004
1208
|
let root;
|
|
1005
1209
|
let resolvedRoutesDir;
|
|
1210
|
+
let typesDir;
|
|
1006
1211
|
let isBuild = false;
|
|
1007
1212
|
let isSSRBuild = false;
|
|
1213
|
+
let tsConfigExists;
|
|
1008
1214
|
let ssrEntryFiles;
|
|
1009
1215
|
let devEntryFile;
|
|
1010
1216
|
let devServer;
|
|
@@ -1013,6 +1219,7 @@ function markoServe(opts = {}) {
|
|
|
1013
1219
|
let routeDataFilename = "routes.json";
|
|
1014
1220
|
let extractVerbs;
|
|
1015
1221
|
let resolvedConfig;
|
|
1222
|
+
let typesFile;
|
|
1016
1223
|
let isStale = true;
|
|
1017
1224
|
let isRendered = false;
|
|
1018
1225
|
const virtualFiles = /* @__PURE__ */ new Map();
|
|
@@ -1020,6 +1227,20 @@ function markoServe(opts = {}) {
|
|
|
1020
1227
|
routesBuild: 0,
|
|
1021
1228
|
routesRender: 0
|
|
1022
1229
|
};
|
|
1230
|
+
async function writeTypesFile() {
|
|
1231
|
+
if (tsConfigExists ?? (tsConfigExists = await globFileExists(
|
|
1232
|
+
root,
|
|
1233
|
+
"{.tsconfig*,tsconfig*.json}"
|
|
1234
|
+
))) {
|
|
1235
|
+
const filepath = path2.join(typesDir, "routes.d.ts");
|
|
1236
|
+
const adapterTypeInfo = (adapter == null ? void 0 : adapter.writeTypeInfo) && await (adapter == null ? void 0 : adapter.writeTypeInfo());
|
|
1237
|
+
const data = renderRouteTypeInfo(routes, path2.relative(typesDir, routesDir)) + adapterTypeInfo;
|
|
1238
|
+
if (data !== typesFile || !fs2.existsSync(filepath)) {
|
|
1239
|
+
await ensureDir(typesDir);
|
|
1240
|
+
await fs2.promises.writeFile(filepath, typesFile = data);
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1023
1244
|
async function setVirtualFiles(render = false) {
|
|
1024
1245
|
for (const route of routes.list) {
|
|
1025
1246
|
if (render && route.handler) {
|
|
@@ -1032,31 +1253,37 @@ function markoServe(opts = {}) {
|
|
|
1032
1253
|
}
|
|
1033
1254
|
if (route.page) {
|
|
1034
1255
|
virtualFiles.set(
|
|
1035
|
-
path2.join(root, `${
|
|
1256
|
+
path2.join(root, `${markoRunFilePrefix}route__${route.key}.marko`),
|
|
1036
1257
|
render ? renderRouteTemplate(route) : ""
|
|
1037
1258
|
);
|
|
1038
1259
|
}
|
|
1039
1260
|
virtualFiles.set(
|
|
1040
|
-
path2.join(root, `${
|
|
1261
|
+
path2.join(root, `${markoRunFilePrefix}route__${route.key}.js`),
|
|
1041
1262
|
render ? renderRouteEntry(route) : ""
|
|
1042
1263
|
);
|
|
1043
1264
|
}
|
|
1044
1265
|
for (const route of Object.values(routes.special)) {
|
|
1045
1266
|
virtualFiles.set(
|
|
1046
|
-
path2.join(root, `${
|
|
1267
|
+
path2.join(root, `${markoRunFilePrefix}special__${route.key}.marko`),
|
|
1047
1268
|
render ? renderRouteTemplate(route) : ""
|
|
1048
1269
|
);
|
|
1049
1270
|
}
|
|
1050
1271
|
virtualFiles.set(
|
|
1051
1272
|
"@marko/run/router",
|
|
1052
|
-
render ? renderRouter(routes,
|
|
1273
|
+
render ? renderRouter(routes, {
|
|
1274
|
+
trailingSlashes: opts.trailingSlashes || "RedirectWithout"
|
|
1275
|
+
}) : ""
|
|
1276
|
+
);
|
|
1277
|
+
virtualFiles.set(
|
|
1278
|
+
path2.join(root, `${markoRunFilePrefix}middleware.js`),
|
|
1279
|
+
render ? renderMiddleware(routes.middleware) : ""
|
|
1053
1280
|
);
|
|
1054
1281
|
}
|
|
1055
1282
|
const buildVirtualFiles = single(async () => {
|
|
1056
1283
|
const startTime = performance.now();
|
|
1057
1284
|
routes = await buildRoutes(createFSWalker(resolvedRoutesDir), routesDir);
|
|
1058
1285
|
times.routesBuild = performance.now() - startTime;
|
|
1059
|
-
await setVirtualFiles(false);
|
|
1286
|
+
await Promise.all([writeTypesFile(), setVirtualFiles(false)]);
|
|
1060
1287
|
isStale = false;
|
|
1061
1288
|
isRendered = false;
|
|
1062
1289
|
});
|
|
@@ -1070,23 +1297,30 @@ function markoServe(opts = {}) {
|
|
|
1070
1297
|
{
|
|
1071
1298
|
name: "marko-run-vite:pre",
|
|
1072
1299
|
enforce: "pre",
|
|
1073
|
-
async config(
|
|
1300
|
+
async config(config2, env) {
|
|
1074
1301
|
var _a, _b, _c;
|
|
1075
|
-
const externalPluginOptions =
|
|
1302
|
+
const externalPluginOptions = getExternalPluginOptions(config2);
|
|
1076
1303
|
if (externalPluginOptions) {
|
|
1077
1304
|
opts = mergeConfig(opts, externalPluginOptions);
|
|
1078
1305
|
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1306
|
+
if (adapter) {
|
|
1307
|
+
const externalAdapterConfig = getExternalAdapterOptions(config2);
|
|
1308
|
+
if (externalAdapterConfig && adapter.configure) {
|
|
1309
|
+
adapter.configure(externalAdapterConfig);
|
|
1310
|
+
}
|
|
1311
|
+
const adapterOptions = await ((_a = adapter.pluginOptions) == null ? void 0 : _a.call(adapter, opts));
|
|
1312
|
+
if (adapterOptions) {
|
|
1313
|
+
opts = mergeConfig(opts, adapterOptions);
|
|
1314
|
+
}
|
|
1082
1315
|
}
|
|
1083
|
-
root = normalizePath(
|
|
1316
|
+
root = normalizePath(config2.root || process.cwd());
|
|
1084
1317
|
store = opts.store || new FileStore(
|
|
1085
1318
|
`marko-serve-vite-${crypto.createHash("SHA1").update(root).digest("hex")}`
|
|
1086
1319
|
);
|
|
1087
1320
|
isBuild = env.command === "build";
|
|
1088
|
-
isSSRBuild = isBuild && Boolean((_b =
|
|
1321
|
+
isSSRBuild = isBuild && Boolean((_b = config2.build) == null ? void 0 : _b.ssr);
|
|
1089
1322
|
resolvedRoutesDir = path2.resolve(root, routesDir);
|
|
1323
|
+
typesDir = path2.join(root, ".marko-run");
|
|
1090
1324
|
devEntryFile = path2.join(root, "index.html");
|
|
1091
1325
|
let pluginConfig = {
|
|
1092
1326
|
logLevel: isBuild ? "warn" : void 0,
|
|
@@ -1097,18 +1331,18 @@ function markoServe(opts = {}) {
|
|
|
1097
1331
|
emptyOutDir: isSSRBuild
|
|
1098
1332
|
}
|
|
1099
1333
|
};
|
|
1100
|
-
const adapterConfig = await ((_c = adapter == null ? void 0 : adapter.viteConfig) == null ? void 0 : _c.call(adapter,
|
|
1334
|
+
const adapterConfig = await ((_c = adapter == null ? void 0 : adapter.viteConfig) == null ? void 0 : _c.call(adapter, config2));
|
|
1101
1335
|
if (adapterConfig) {
|
|
1102
1336
|
pluginConfig = mergeConfig(pluginConfig, adapterConfig);
|
|
1103
1337
|
}
|
|
1104
|
-
return
|
|
1338
|
+
return setExternalPluginOptions(pluginConfig, opts);
|
|
1105
1339
|
},
|
|
1106
|
-
configResolved(
|
|
1107
|
-
resolvedConfig =
|
|
1340
|
+
configResolved(config2) {
|
|
1341
|
+
resolvedConfig = config2;
|
|
1108
1342
|
const {
|
|
1109
1343
|
ssr,
|
|
1110
1344
|
rollupOptions: { input }
|
|
1111
|
-
} =
|
|
1345
|
+
} = config2.build;
|
|
1112
1346
|
if (typeof ssr === "string") {
|
|
1113
1347
|
ssrEntryFiles = [ssr];
|
|
1114
1348
|
} else if (typeof input === "string") {
|
|
@@ -1139,6 +1373,7 @@ function markoServe(opts = {}) {
|
|
|
1139
1373
|
if (isStale) {
|
|
1140
1374
|
for (const id of virtualFiles.keys()) {
|
|
1141
1375
|
devServer.watcher.emit("change", id);
|
|
1376
|
+
break;
|
|
1142
1377
|
}
|
|
1143
1378
|
}
|
|
1144
1379
|
}
|
|
@@ -1168,12 +1403,18 @@ function markoServe(opts = {}) {
|
|
|
1168
1403
|
},
|
|
1169
1404
|
async resolveId(importee, importer, { ssr }) {
|
|
1170
1405
|
let resolved;
|
|
1171
|
-
if (importee.startsWith(
|
|
1406
|
+
if (importee.startsWith(virtualRuntimePrefix)) {
|
|
1407
|
+
return this.resolve(
|
|
1408
|
+
path2.resolve(__dirname, "../runtime/internal"),
|
|
1409
|
+
importer,
|
|
1410
|
+
{ skipSelf: true }
|
|
1411
|
+
);
|
|
1412
|
+
} else if (importee.startsWith(virtualFilePrefix)) {
|
|
1172
1413
|
importee = path2.resolve(
|
|
1173
1414
|
root,
|
|
1174
1415
|
importee.slice(virtualFilePrefix.length + 1)
|
|
1175
1416
|
);
|
|
1176
|
-
} else if (!isBuild && importer === devEntryFile && importee.startsWith(`/${
|
|
1417
|
+
} else if (!isBuild && importer === devEntryFile && importee.startsWith(`/${markoRunFilePrefix}`)) {
|
|
1177
1418
|
importee = path2.resolve(root, "." + importee);
|
|
1178
1419
|
}
|
|
1179
1420
|
if (isStale) {
|
|
@@ -1295,20 +1536,49 @@ function single(fn) {
|
|
|
1295
1536
|
return result;
|
|
1296
1537
|
};
|
|
1297
1538
|
}
|
|
1539
|
+
async function globFileExists(root, pattern) {
|
|
1540
|
+
return new Promise((resolve, reject) => {
|
|
1541
|
+
glob(pattern, { root }, (err, matches) => {
|
|
1542
|
+
if (err) {
|
|
1543
|
+
reject(err);
|
|
1544
|
+
}
|
|
1545
|
+
resolve(matches.length > 0);
|
|
1546
|
+
});
|
|
1547
|
+
});
|
|
1548
|
+
}
|
|
1549
|
+
async function ensureDir(dir) {
|
|
1550
|
+
if (!fs2.existsSync(dir)) {
|
|
1551
|
+
await fs2.promises.mkdir(dir, { recursive: true });
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1298
1554
|
|
|
1299
1555
|
// src/vite/utils/server.ts
|
|
1300
1556
|
import net from "net";
|
|
1301
1557
|
import cp from "child_process";
|
|
1302
|
-
|
|
1558
|
+
import { parse, config } from "dotenv";
|
|
1559
|
+
import fs3 from "fs";
|
|
1560
|
+
async function parseEnv(envFile) {
|
|
1561
|
+
if (fs3.existsSync(envFile)) {
|
|
1562
|
+
const content = await fs3.promises.readFile(envFile, "utf8");
|
|
1563
|
+
return parse(content);
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
function loadEnv(envFile) {
|
|
1567
|
+
config({ path: envFile });
|
|
1568
|
+
}
|
|
1569
|
+
async function spawnServer(cmd, port = 0, env, cwd = process.cwd(), wait = 3e4) {
|
|
1303
1570
|
if (port <= 0) {
|
|
1304
1571
|
port = await getAvailablePort();
|
|
1305
1572
|
}
|
|
1573
|
+
if (typeof env === "string") {
|
|
1574
|
+
env = await parseEnv(env);
|
|
1575
|
+
}
|
|
1306
1576
|
const proc = cp.spawn(cmd, {
|
|
1307
1577
|
cwd,
|
|
1308
1578
|
shell: true,
|
|
1309
1579
|
stdio: "inherit",
|
|
1310
1580
|
windowsHide: true,
|
|
1311
|
-
env: { NODE_ENV: "development", ...process.env, PORT: `${port}` }
|
|
1581
|
+
env: { ...env, NODE_ENV: "development", ...process.env, PORT: `${port}` }
|
|
1312
1582
|
});
|
|
1313
1583
|
const close = () => {
|
|
1314
1584
|
proc.unref();
|
|
@@ -1355,5 +1625,7 @@ export {
|
|
|
1355
1625
|
markoServe as default,
|
|
1356
1626
|
getAvailablePort,
|
|
1357
1627
|
isPortInUse,
|
|
1628
|
+
loadEnv,
|
|
1629
|
+
parseEnv,
|
|
1358
1630
|
spawnServer
|
|
1359
1631
|
};
|