mokup 0.1.0 → 0.2.2
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/dist/cli-bin.cjs +110 -0
- package/dist/cli-bin.d.cts +5 -0
- package/dist/cli-bin.d.mts +5 -0
- package/dist/cli-bin.d.ts +5 -0
- package/dist/cli-bin.mjs +108 -0
- package/dist/cli.cjs +16 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.mjs +1 -0
- package/dist/index.d.cts +12 -1
- package/dist/index.d.mts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/runtime.cjs +16 -0
- package/dist/runtime.d.cts +1 -0
- package/dist/runtime.d.mts +1 -0
- package/dist/runtime.d.ts +1 -0
- package/dist/runtime.mjs +1 -0
- package/dist/server/worker.cjs +16 -0
- package/dist/server/worker.d.cts +1 -0
- package/dist/server/worker.d.mts +1 -0
- package/dist/server/worker.d.ts +1 -0
- package/dist/server/worker.mjs +1 -0
- package/dist/server.cjs +16 -0
- package/dist/server.d.cts +1 -0
- package/dist/server.d.mts +1 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.mjs +1 -0
- package/dist/sw.cjs +90 -0
- package/dist/sw.d.cts +14 -0
- package/dist/sw.d.mts +14 -0
- package/dist/sw.d.ts +14 -0
- package/dist/sw.mjs +87 -0
- package/dist/vite.cjs +702 -21
- package/dist/vite.d.cts +1 -1
- package/dist/vite.d.mts +1 -1
- package/dist/vite.d.ts +1 -1
- package/dist/vite.mjs +702 -21
- package/package.json +32 -2
package/dist/vite.cjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const node_fs = require('node:fs');
|
|
3
4
|
const node_process = require('node:process');
|
|
5
|
+
const node_url = require('node:url');
|
|
4
6
|
const chokidar = require('chokidar');
|
|
5
7
|
const node_buffer = require('node:buffer');
|
|
6
8
|
const hono = require('hono');
|
|
7
9
|
const patternRouter = require('hono/router/pattern-router');
|
|
8
10
|
const pathe = require('pathe');
|
|
9
|
-
const node_fs = require('node:fs');
|
|
10
11
|
const node_module = require('node:module');
|
|
11
12
|
const runtime = require('@mokup/runtime');
|
|
12
|
-
const node_url = require('node:url');
|
|
13
13
|
const esbuild = require('esbuild');
|
|
14
14
|
const jsoncParser = require('jsonc-parser');
|
|
15
15
|
|
|
@@ -142,6 +142,18 @@ function toHonoPath(route) {
|
|
|
142
142
|
});
|
|
143
143
|
return `/${segments.join("/")}`;
|
|
144
144
|
}
|
|
145
|
+
function isValidStatus(status) {
|
|
146
|
+
return typeof status === "number" && Number.isFinite(status) && status >= 200 && status <= 599;
|
|
147
|
+
}
|
|
148
|
+
function resolveStatus(routeStatus, responseStatus) {
|
|
149
|
+
if (isValidStatus(routeStatus)) {
|
|
150
|
+
return routeStatus;
|
|
151
|
+
}
|
|
152
|
+
if (isValidStatus(responseStatus)) {
|
|
153
|
+
return responseStatus;
|
|
154
|
+
}
|
|
155
|
+
return 200;
|
|
156
|
+
}
|
|
145
157
|
function applyRouteOverrides(response, route) {
|
|
146
158
|
const headers = new Headers(response.headers);
|
|
147
159
|
const hasHeaders = !!route.headers && Object.keys(route.headers).length > 0;
|
|
@@ -150,7 +162,7 @@ function applyRouteOverrides(response, route) {
|
|
|
150
162
|
headers.set(key, value);
|
|
151
163
|
}
|
|
152
164
|
}
|
|
153
|
-
const status = route.status
|
|
165
|
+
const status = resolveStatus(route.status, response.status);
|
|
154
166
|
if (status === response.status && !hasHeaders) {
|
|
155
167
|
return response;
|
|
156
168
|
}
|
|
@@ -336,17 +348,28 @@ function normalizePlaygroundPath(value) {
|
|
|
336
348
|
const normalized = value.startsWith("/") ? value : `/${value}`;
|
|
337
349
|
return normalized.length > 1 && normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
|
|
338
350
|
}
|
|
339
|
-
function normalizeBase(base) {
|
|
351
|
+
function normalizeBase$1(base) {
|
|
340
352
|
if (!base || base === "/") {
|
|
341
353
|
return "";
|
|
342
354
|
}
|
|
343
355
|
return base.endsWith("/") ? base.slice(0, -1) : base;
|
|
344
356
|
}
|
|
357
|
+
function resolvePlaygroundRequestPath(base, playgroundPath) {
|
|
358
|
+
const normalizedBase = normalizeBase$1(base);
|
|
359
|
+
const normalizedPath = normalizePlaygroundPath(playgroundPath);
|
|
360
|
+
if (!normalizedBase) {
|
|
361
|
+
return normalizedPath;
|
|
362
|
+
}
|
|
363
|
+
if (normalizedPath.startsWith(normalizedBase)) {
|
|
364
|
+
return normalizedPath;
|
|
365
|
+
}
|
|
366
|
+
return `${normalizedBase}${normalizedPath}`;
|
|
367
|
+
}
|
|
345
368
|
function injectPlaygroundHmr(html, base) {
|
|
346
369
|
if (html.includes("mokup-playground-hmr")) {
|
|
347
370
|
return html;
|
|
348
371
|
}
|
|
349
|
-
const normalizedBase = normalizeBase(base);
|
|
372
|
+
const normalizedBase = normalizeBase$1(base);
|
|
350
373
|
const clientPath = `${normalizedBase}/@vite/client`;
|
|
351
374
|
const snippet = [
|
|
352
375
|
'<script type="module" id="mokup-playground-hmr">',
|
|
@@ -370,6 +393,29 @@ function injectPlaygroundHmr(html, base) {
|
|
|
370
393
|
return `${html}
|
|
371
394
|
${snippet}`;
|
|
372
395
|
}
|
|
396
|
+
function injectPlaygroundSw(html, script) {
|
|
397
|
+
if (!script) {
|
|
398
|
+
return html;
|
|
399
|
+
}
|
|
400
|
+
if (html.includes("mokup-playground-sw")) {
|
|
401
|
+
return html;
|
|
402
|
+
}
|
|
403
|
+
const snippet = [
|
|
404
|
+
'<script type="module" id="mokup-playground-sw">',
|
|
405
|
+
script,
|
|
406
|
+
"<\/script>"
|
|
407
|
+
].join("\n");
|
|
408
|
+
if (html.includes("</head>")) {
|
|
409
|
+
return html.replace("</head>", `${snippet}
|
|
410
|
+
</head>`);
|
|
411
|
+
}
|
|
412
|
+
if (html.includes("</body>")) {
|
|
413
|
+
return html.replace("</body>", `${snippet}
|
|
414
|
+
</body>`);
|
|
415
|
+
}
|
|
416
|
+
return `${html}
|
|
417
|
+
${snippet}`;
|
|
418
|
+
}
|
|
373
419
|
function isViteDevServer$1(server) {
|
|
374
420
|
return !!server && "ws" in server;
|
|
375
421
|
}
|
|
@@ -508,25 +554,31 @@ function createPlaygroundMiddleware(params) {
|
|
|
508
554
|
if (!params.config.enabled) {
|
|
509
555
|
return next();
|
|
510
556
|
}
|
|
557
|
+
const server = params.getServer?.();
|
|
558
|
+
const requestPath = resolvePlaygroundRequestPath(server?.config?.base ?? "/", playgroundPath);
|
|
511
559
|
const requestUrl = req.url ?? "/";
|
|
512
560
|
const url = new URL(requestUrl, "http://mokup.local");
|
|
513
561
|
const pathname = url.pathname;
|
|
514
|
-
|
|
562
|
+
const matchedPath = pathname.startsWith(requestPath) ? requestPath : pathname.startsWith(playgroundPath) ? playgroundPath : null;
|
|
563
|
+
if (!matchedPath) {
|
|
515
564
|
return next();
|
|
516
565
|
}
|
|
517
|
-
const subPath = pathname.slice(
|
|
566
|
+
const subPath = pathname.slice(matchedPath.length);
|
|
518
567
|
if (subPath === "") {
|
|
519
568
|
const suffix = url.search ?? "";
|
|
520
569
|
res.statusCode = 302;
|
|
521
|
-
res.setHeader("Location", `${
|
|
570
|
+
res.setHeader("Location", `${matchedPath}/${suffix}`);
|
|
522
571
|
res.end();
|
|
523
572
|
return;
|
|
524
573
|
}
|
|
525
574
|
if (subPath === "" || subPath === "/" || subPath === "/index.html") {
|
|
526
575
|
try {
|
|
527
576
|
const html = await node_fs.promises.readFile(indexPath, "utf8");
|
|
528
|
-
|
|
529
|
-
|
|
577
|
+
let output = html;
|
|
578
|
+
if (isViteDevServer$1(server)) {
|
|
579
|
+
output = injectPlaygroundHmr(output, server.config.base ?? "/");
|
|
580
|
+
output = injectPlaygroundSw(output, params.getSwScript?.());
|
|
581
|
+
}
|
|
530
582
|
const contentType = mimeTypes[".html"] ?? "text/html; charset=utf-8";
|
|
531
583
|
sendFile(res, output, contentType);
|
|
532
584
|
} catch (error) {
|
|
@@ -537,13 +589,13 @@ function createPlaygroundMiddleware(params) {
|
|
|
537
589
|
return;
|
|
538
590
|
}
|
|
539
591
|
if (subPath === "/routes") {
|
|
540
|
-
const server = params.getServer?.();
|
|
541
592
|
const dirs = params.getDirs?.() ?? [];
|
|
542
593
|
const baseRoot = resolveGroupRoot(dirs, server?.config?.root);
|
|
543
594
|
const groups = resolveGroups(dirs, baseRoot);
|
|
544
595
|
const routes = params.getRoutes();
|
|
545
596
|
sendJson(res, {
|
|
546
|
-
basePath:
|
|
597
|
+
basePath: matchedPath,
|
|
598
|
+
root: baseRoot,
|
|
547
599
|
count: routes.length,
|
|
548
600
|
groups: groups.map((group) => ({ key: group.key, label: group.label })),
|
|
549
601
|
routes: routes.map((route) => toPlaygroundRoute(route, baseRoot, groups))
|
|
@@ -768,12 +820,12 @@ function normalizeMiddlewares(value, source, logger) {
|
|
|
768
820
|
}
|
|
769
821
|
const list = Array.isArray(value) ? value : [value];
|
|
770
822
|
const middlewares = [];
|
|
771
|
-
for (const entry of list) {
|
|
823
|
+
for (const [index, entry] of list.entries()) {
|
|
772
824
|
if (typeof entry !== "function") {
|
|
773
825
|
logger.warn(`Invalid middleware in ${source}`);
|
|
774
826
|
continue;
|
|
775
827
|
}
|
|
776
|
-
middlewares.push({ handle: entry, source });
|
|
828
|
+
middlewares.push({ handle: entry, source, index });
|
|
777
829
|
}
|
|
778
830
|
return middlewares;
|
|
779
831
|
}
|
|
@@ -996,7 +1048,7 @@ async function scanRoutes(params) {
|
|
|
996
1048
|
continue;
|
|
997
1049
|
}
|
|
998
1050
|
const rules = await loadRules(fileInfo.file, params.server, params.logger);
|
|
999
|
-
for (const rule of rules) {
|
|
1051
|
+
for (const [index, rule] of rules.entries()) {
|
|
1000
1052
|
if (!rule || typeof rule !== "object") {
|
|
1001
1053
|
continue;
|
|
1002
1054
|
}
|
|
@@ -1025,6 +1077,7 @@ async function scanRoutes(params) {
|
|
|
1025
1077
|
if (!resolved) {
|
|
1026
1078
|
continue;
|
|
1027
1079
|
}
|
|
1080
|
+
resolved.ruleIndex = index;
|
|
1028
1081
|
if (config.headers) {
|
|
1029
1082
|
resolved.headers = { ...config.headers, ...resolved.headers ?? {} };
|
|
1030
1083
|
}
|
|
@@ -1048,6 +1101,330 @@ async function scanRoutes(params) {
|
|
|
1048
1101
|
return sortRoutes(routes);
|
|
1049
1102
|
}
|
|
1050
1103
|
|
|
1104
|
+
const defaultSwPath = "/mokup-sw.js";
|
|
1105
|
+
const defaultSwScope = "/";
|
|
1106
|
+
function normalizeSwPath(path) {
|
|
1107
|
+
if (!path) {
|
|
1108
|
+
return defaultSwPath;
|
|
1109
|
+
}
|
|
1110
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
1111
|
+
}
|
|
1112
|
+
function normalizeSwScope(scope) {
|
|
1113
|
+
if (!scope) {
|
|
1114
|
+
return defaultSwScope;
|
|
1115
|
+
}
|
|
1116
|
+
return scope.startsWith("/") ? scope : `/${scope}`;
|
|
1117
|
+
}
|
|
1118
|
+
function normalizeBasePath(value) {
|
|
1119
|
+
if (!value) {
|
|
1120
|
+
return "/";
|
|
1121
|
+
}
|
|
1122
|
+
const normalized = value.startsWith("/") ? value : `/${value}`;
|
|
1123
|
+
if (normalized.length > 1 && normalized.endsWith("/")) {
|
|
1124
|
+
return normalized.slice(0, -1);
|
|
1125
|
+
}
|
|
1126
|
+
return normalized;
|
|
1127
|
+
}
|
|
1128
|
+
function resolveSwConfigFromEntries(entries, logger) {
|
|
1129
|
+
let path = defaultSwPath;
|
|
1130
|
+
let scope = defaultSwScope;
|
|
1131
|
+
let register = true;
|
|
1132
|
+
let unregister = false;
|
|
1133
|
+
const basePaths = [];
|
|
1134
|
+
let hasPath = false;
|
|
1135
|
+
let hasScope = false;
|
|
1136
|
+
let hasRegister = false;
|
|
1137
|
+
let hasUnregister = false;
|
|
1138
|
+
for (const entry of entries) {
|
|
1139
|
+
const config = entry.sw;
|
|
1140
|
+
if (config?.path) {
|
|
1141
|
+
const next = normalizeSwPath(config.path);
|
|
1142
|
+
if (!hasPath) {
|
|
1143
|
+
path = next;
|
|
1144
|
+
hasPath = true;
|
|
1145
|
+
} else if (path !== next) {
|
|
1146
|
+
logger.warn(`SW path "${next}" ignored; using "${path}".`);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
if (config?.scope) {
|
|
1150
|
+
const next = normalizeSwScope(config.scope);
|
|
1151
|
+
if (!hasScope) {
|
|
1152
|
+
scope = next;
|
|
1153
|
+
hasScope = true;
|
|
1154
|
+
} else if (scope !== next) {
|
|
1155
|
+
logger.warn(`SW scope "${next}" ignored; using "${scope}".`);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
if (typeof config?.register === "boolean") {
|
|
1159
|
+
if (!hasRegister) {
|
|
1160
|
+
register = config.register;
|
|
1161
|
+
hasRegister = true;
|
|
1162
|
+
} else if (register !== config.register) {
|
|
1163
|
+
logger.warn(
|
|
1164
|
+
`SW register="${String(config.register)}" ignored; using "${String(register)}".`
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
if (typeof config?.unregister === "boolean") {
|
|
1169
|
+
if (!hasUnregister) {
|
|
1170
|
+
unregister = config.unregister;
|
|
1171
|
+
hasUnregister = true;
|
|
1172
|
+
} else if (unregister !== config.unregister) {
|
|
1173
|
+
logger.warn(
|
|
1174
|
+
`SW unregister="${String(config.unregister)}" ignored; using "${String(unregister)}".`
|
|
1175
|
+
);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
if (typeof config?.basePath !== "undefined") {
|
|
1179
|
+
const values = Array.isArray(config.basePath) ? config.basePath : [config.basePath];
|
|
1180
|
+
for (const value of values) {
|
|
1181
|
+
basePaths.push(normalizeBasePath(value));
|
|
1182
|
+
}
|
|
1183
|
+
continue;
|
|
1184
|
+
}
|
|
1185
|
+
const normalizedPrefix = normalizePrefix(entry.prefix ?? "");
|
|
1186
|
+
if (normalizedPrefix) {
|
|
1187
|
+
basePaths.push(normalizedPrefix);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
return {
|
|
1191
|
+
path,
|
|
1192
|
+
scope,
|
|
1193
|
+
register,
|
|
1194
|
+
unregister,
|
|
1195
|
+
basePaths: Array.from(new Set(basePaths))
|
|
1196
|
+
};
|
|
1197
|
+
}
|
|
1198
|
+
function resolveSwConfig(options, logger) {
|
|
1199
|
+
const swEntries = options.filter((entry) => entry.mode === "sw");
|
|
1200
|
+
if (swEntries.length === 0) {
|
|
1201
|
+
return null;
|
|
1202
|
+
}
|
|
1203
|
+
return resolveSwConfigFromEntries(swEntries, logger);
|
|
1204
|
+
}
|
|
1205
|
+
function resolveSwUnregisterConfig(options, logger) {
|
|
1206
|
+
return resolveSwConfigFromEntries(options, logger);
|
|
1207
|
+
}
|
|
1208
|
+
function toViteImportPath(file, root) {
|
|
1209
|
+
const absolute = pathe.isAbsolute(file) ? file : pathe.resolve(root, file);
|
|
1210
|
+
const rel = pathe.relative(root, absolute);
|
|
1211
|
+
if (!rel.startsWith("..") && !pathe.isAbsolute(rel)) {
|
|
1212
|
+
return `/${toPosix(rel)}`;
|
|
1213
|
+
}
|
|
1214
|
+
return `/@fs/${toPosix(absolute)}`;
|
|
1215
|
+
}
|
|
1216
|
+
function shouldModuleize(handler) {
|
|
1217
|
+
if (typeof handler === "function") {
|
|
1218
|
+
return true;
|
|
1219
|
+
}
|
|
1220
|
+
if (typeof Response !== "undefined" && handler instanceof Response) {
|
|
1221
|
+
return true;
|
|
1222
|
+
}
|
|
1223
|
+
return false;
|
|
1224
|
+
}
|
|
1225
|
+
function toBinaryBody(handler) {
|
|
1226
|
+
if (handler instanceof ArrayBuffer) {
|
|
1227
|
+
return node_buffer.Buffer.from(new Uint8Array(handler)).toString("base64");
|
|
1228
|
+
}
|
|
1229
|
+
if (handler instanceof Uint8Array) {
|
|
1230
|
+
return node_buffer.Buffer.from(handler).toString("base64");
|
|
1231
|
+
}
|
|
1232
|
+
if (node_buffer.Buffer.isBuffer(handler)) {
|
|
1233
|
+
return handler.toString("base64");
|
|
1234
|
+
}
|
|
1235
|
+
return null;
|
|
1236
|
+
}
|
|
1237
|
+
function buildManifestResponse(route, moduleId) {
|
|
1238
|
+
if (moduleId) {
|
|
1239
|
+
const response = {
|
|
1240
|
+
type: "module",
|
|
1241
|
+
module: moduleId
|
|
1242
|
+
};
|
|
1243
|
+
if (typeof route.ruleIndex === "number") {
|
|
1244
|
+
response.ruleIndex = route.ruleIndex;
|
|
1245
|
+
}
|
|
1246
|
+
return response;
|
|
1247
|
+
}
|
|
1248
|
+
const handler = route.handler;
|
|
1249
|
+
if (typeof handler === "string") {
|
|
1250
|
+
return {
|
|
1251
|
+
type: "text",
|
|
1252
|
+
body: handler
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
const binary = toBinaryBody(handler);
|
|
1256
|
+
if (binary) {
|
|
1257
|
+
return {
|
|
1258
|
+
type: "binary",
|
|
1259
|
+
body: binary,
|
|
1260
|
+
encoding: "base64"
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
return {
|
|
1264
|
+
type: "json",
|
|
1265
|
+
body: handler
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1268
|
+
function buildSwScript(params) {
|
|
1269
|
+
const { routes, root } = params;
|
|
1270
|
+
const runtimeImportPath = params.runtimeImportPath ?? "mokup/runtime";
|
|
1271
|
+
const basePaths = params.basePaths ?? [];
|
|
1272
|
+
const ruleModules = /* @__PURE__ */ new Map();
|
|
1273
|
+
const middlewareModules = /* @__PURE__ */ new Map();
|
|
1274
|
+
const manifestRoutes = routes.map((route) => {
|
|
1275
|
+
const moduleId = shouldModuleize(route.handler) ? toViteImportPath(route.file, root) : null;
|
|
1276
|
+
if (moduleId) {
|
|
1277
|
+
ruleModules.set(moduleId, moduleId);
|
|
1278
|
+
}
|
|
1279
|
+
const middleware = route.middlewares?.map((entry) => {
|
|
1280
|
+
const modulePath = toViteImportPath(entry.source, root);
|
|
1281
|
+
middlewareModules.set(modulePath, modulePath);
|
|
1282
|
+
return {
|
|
1283
|
+
module: modulePath,
|
|
1284
|
+
ruleIndex: entry.index
|
|
1285
|
+
};
|
|
1286
|
+
});
|
|
1287
|
+
const response = buildManifestResponse(route, moduleId);
|
|
1288
|
+
const manifestRoute = {
|
|
1289
|
+
method: route.method,
|
|
1290
|
+
url: route.template,
|
|
1291
|
+
...route.tokens ? { tokens: route.tokens } : {},
|
|
1292
|
+
...route.score ? { score: route.score } : {},
|
|
1293
|
+
...route.status ? { status: route.status } : {},
|
|
1294
|
+
...route.headers ? { headers: route.headers } : {},
|
|
1295
|
+
...route.delay ? { delay: route.delay } : {},
|
|
1296
|
+
...middleware && middleware.length > 0 ? { middleware } : {},
|
|
1297
|
+
response
|
|
1298
|
+
};
|
|
1299
|
+
return manifestRoute;
|
|
1300
|
+
});
|
|
1301
|
+
const manifest = {
|
|
1302
|
+
version: 1,
|
|
1303
|
+
routes: manifestRoutes
|
|
1304
|
+
};
|
|
1305
|
+
const imports = [
|
|
1306
|
+
`import { createRuntimeApp, handle } from ${JSON.stringify(runtimeImportPath)}`
|
|
1307
|
+
];
|
|
1308
|
+
const moduleEntries = [];
|
|
1309
|
+
let moduleIndex = 0;
|
|
1310
|
+
for (const id of ruleModules.keys()) {
|
|
1311
|
+
const name = `module${moduleIndex++}`;
|
|
1312
|
+
imports.push(`import * as ${name} from '${id}'`);
|
|
1313
|
+
moduleEntries.push({ id, name, kind: "rule" });
|
|
1314
|
+
}
|
|
1315
|
+
for (const id of middlewareModules.keys()) {
|
|
1316
|
+
const name = `module${moduleIndex++}`;
|
|
1317
|
+
imports.push(`import * as ${name} from '${id}'`);
|
|
1318
|
+
moduleEntries.push({ id, name, kind: "middleware" });
|
|
1319
|
+
}
|
|
1320
|
+
const lines = [];
|
|
1321
|
+
lines.push(...imports, "");
|
|
1322
|
+
lines.push(
|
|
1323
|
+
"const resolveModuleExport = (mod) => mod?.default ?? mod",
|
|
1324
|
+
"",
|
|
1325
|
+
"const toRuntimeRule = (value) => {",
|
|
1326
|
+
" if (typeof value === 'undefined') {",
|
|
1327
|
+
" return null",
|
|
1328
|
+
" }",
|
|
1329
|
+
" if (typeof value === 'function') {",
|
|
1330
|
+
" return { response: value }",
|
|
1331
|
+
" }",
|
|
1332
|
+
" if (value === null) {",
|
|
1333
|
+
" return { response: null }",
|
|
1334
|
+
" }",
|
|
1335
|
+
" if (typeof value === 'object') {",
|
|
1336
|
+
" if ('response' in value) {",
|
|
1337
|
+
" return value",
|
|
1338
|
+
" }",
|
|
1339
|
+
" if ('handler' in value) {",
|
|
1340
|
+
" const handlerRule = value",
|
|
1341
|
+
" return {",
|
|
1342
|
+
" response: handlerRule.handler,",
|
|
1343
|
+
" ...(typeof handlerRule.status === 'number' ? { status: handlerRule.status } : {}),",
|
|
1344
|
+
" ...(handlerRule.headers ? { headers: handlerRule.headers } : {}),",
|
|
1345
|
+
" ...(typeof handlerRule.delay === 'number' ? { delay: handlerRule.delay } : {}),",
|
|
1346
|
+
" }",
|
|
1347
|
+
" }",
|
|
1348
|
+
" return { response: value }",
|
|
1349
|
+
" }",
|
|
1350
|
+
" return { response: value }",
|
|
1351
|
+
"}",
|
|
1352
|
+
"",
|
|
1353
|
+
"const toRuntimeRules = (value) => {",
|
|
1354
|
+
" if (typeof value === 'undefined') {",
|
|
1355
|
+
" return []",
|
|
1356
|
+
" }",
|
|
1357
|
+
" if (Array.isArray(value)) {",
|
|
1358
|
+
" return value.map(toRuntimeRule).filter(Boolean)",
|
|
1359
|
+
" }",
|
|
1360
|
+
" const rule = toRuntimeRule(value)",
|
|
1361
|
+
" return rule ? [rule] : []",
|
|
1362
|
+
"}",
|
|
1363
|
+
""
|
|
1364
|
+
);
|
|
1365
|
+
lines.push(
|
|
1366
|
+
`const manifest = ${JSON.stringify(manifest, null, 2)}`,
|
|
1367
|
+
""
|
|
1368
|
+
);
|
|
1369
|
+
if (moduleEntries.length > 0) {
|
|
1370
|
+
lines.push("const moduleMap = {");
|
|
1371
|
+
for (const entry of moduleEntries) {
|
|
1372
|
+
if (entry.kind === "rule") {
|
|
1373
|
+
lines.push(
|
|
1374
|
+
` ${JSON.stringify(entry.id)}: { default: toRuntimeRules(resolveModuleExport(${entry.name})) },`
|
|
1375
|
+
);
|
|
1376
|
+
continue;
|
|
1377
|
+
}
|
|
1378
|
+
lines.push(
|
|
1379
|
+
` ${JSON.stringify(entry.id)}: ${entry.name},`
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1382
|
+
lines.push("}", "");
|
|
1383
|
+
}
|
|
1384
|
+
const runtimeOptions = moduleEntries.length > 0 ? "{ manifest, moduleMap }" : "{ manifest }";
|
|
1385
|
+
lines.push(
|
|
1386
|
+
`const basePaths = ${JSON.stringify(basePaths)}`,
|
|
1387
|
+
"",
|
|
1388
|
+
"self.addEventListener('install', () => {",
|
|
1389
|
+
" self.skipWaiting()",
|
|
1390
|
+
"})",
|
|
1391
|
+
"",
|
|
1392
|
+
"self.addEventListener('activate', (event) => {",
|
|
1393
|
+
" event.waitUntil(self.clients.claim())",
|
|
1394
|
+
"})",
|
|
1395
|
+
"",
|
|
1396
|
+
"const shouldHandle = (request) => {",
|
|
1397
|
+
" if (!basePaths || basePaths.length === 0) {",
|
|
1398
|
+
" return true",
|
|
1399
|
+
" }",
|
|
1400
|
+
" const pathname = new URL(request.url).pathname",
|
|
1401
|
+
" return basePaths.some((basePath) => {",
|
|
1402
|
+
" if (basePath === '/') {",
|
|
1403
|
+
" return true",
|
|
1404
|
+
" }",
|
|
1405
|
+
" return pathname === basePath || pathname.startsWith(basePath + '/')",
|
|
1406
|
+
" })",
|
|
1407
|
+
"}",
|
|
1408
|
+
"",
|
|
1409
|
+
"const registerHandler = async () => {",
|
|
1410
|
+
` const app = await createRuntimeApp(${runtimeOptions})`,
|
|
1411
|
+
" const handler = handle(app)",
|
|
1412
|
+
" self.addEventListener('fetch', (event) => {",
|
|
1413
|
+
" if (!shouldHandle(event.request)) {",
|
|
1414
|
+
" return",
|
|
1415
|
+
" }",
|
|
1416
|
+
" handler(event)",
|
|
1417
|
+
" })",
|
|
1418
|
+
"}",
|
|
1419
|
+
"",
|
|
1420
|
+
"registerHandler().catch((error) => {",
|
|
1421
|
+
" console.error('[mokup] Failed to build service worker app:', error)",
|
|
1422
|
+
"})",
|
|
1423
|
+
""
|
|
1424
|
+
);
|
|
1425
|
+
return lines.join("\n");
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1051
1428
|
function buildRouteSignature(routes) {
|
|
1052
1429
|
return routes.map(
|
|
1053
1430
|
(route) => [
|
|
@@ -1075,9 +1452,75 @@ function resolvePlaygroundInput(list) {
|
|
|
1075
1452
|
}
|
|
1076
1453
|
return void 0;
|
|
1077
1454
|
}
|
|
1455
|
+
function normalizeBase(base) {
|
|
1456
|
+
if (!base) {
|
|
1457
|
+
return "/";
|
|
1458
|
+
}
|
|
1459
|
+
if (base.startsWith(".")) {
|
|
1460
|
+
return "/";
|
|
1461
|
+
}
|
|
1462
|
+
let normalized = base.startsWith("/") ? base : `/${base}`;
|
|
1463
|
+
if (!normalized.endsWith("/")) {
|
|
1464
|
+
normalized = `${normalized}/`;
|
|
1465
|
+
}
|
|
1466
|
+
return normalized;
|
|
1467
|
+
}
|
|
1468
|
+
function resolveRegisterPath(base, path) {
|
|
1469
|
+
const normalizedBase = normalizeBase(base);
|
|
1470
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
1471
|
+
if (normalizedPath.startsWith(normalizedBase)) {
|
|
1472
|
+
return normalizedPath;
|
|
1473
|
+
}
|
|
1474
|
+
return `${normalizedBase}${normalizedPath.slice(1)}`;
|
|
1475
|
+
}
|
|
1476
|
+
function resolveRegisterScope(base, scope) {
|
|
1477
|
+
const normalizedBase = normalizeBase(base);
|
|
1478
|
+
const normalizedScope = scope.startsWith("/") ? scope : `/${scope}`;
|
|
1479
|
+
if (normalizedScope.startsWith(normalizedBase)) {
|
|
1480
|
+
return normalizedScope;
|
|
1481
|
+
}
|
|
1482
|
+
return `${normalizedBase}${normalizedScope.slice(1)}`;
|
|
1483
|
+
}
|
|
1484
|
+
function resolveSwImportPath(base) {
|
|
1485
|
+
const normalizedBase = normalizeBase(base);
|
|
1486
|
+
return `${normalizedBase}@id/mokup/sw`;
|
|
1487
|
+
}
|
|
1488
|
+
function resolveSwRuntimeImportPath(base) {
|
|
1489
|
+
const normalizedBase = normalizeBase(base);
|
|
1490
|
+
return `${normalizedBase}@id/mokup/runtime`;
|
|
1491
|
+
}
|
|
1492
|
+
const swModuleCandidates = [
|
|
1493
|
+
new URL("../sw.ts", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('vite.cjs', document.baseURI).href))),
|
|
1494
|
+
new URL("../sw.js", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('vite.cjs', document.baseURI).href)))
|
|
1495
|
+
];
|
|
1496
|
+
const localSwModulePath = (() => {
|
|
1497
|
+
for (const candidate of swModuleCandidates) {
|
|
1498
|
+
const filePath = node_url.fileURLToPath(candidate);
|
|
1499
|
+
if (node_fs.existsSync(filePath)) {
|
|
1500
|
+
return filePath;
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
return node_url.fileURLToPath(swModuleCandidates[0] ?? new URL("../sw.ts", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('vite.cjs', document.baseURI).href))));
|
|
1504
|
+
})();
|
|
1505
|
+
function hasMiddlewareStack(middlewares) {
|
|
1506
|
+
const candidate = middlewares;
|
|
1507
|
+
return Array.isArray(candidate.stack);
|
|
1508
|
+
}
|
|
1509
|
+
function addMiddlewareFirst(server, middleware) {
|
|
1510
|
+
if (hasMiddlewareStack(server.middlewares)) {
|
|
1511
|
+
server.middlewares.stack.unshift({ route: "", handle: middleware });
|
|
1512
|
+
return;
|
|
1513
|
+
}
|
|
1514
|
+
server.middlewares.use(middleware);
|
|
1515
|
+
}
|
|
1078
1516
|
function createMokupPlugin(options = {}) {
|
|
1079
1517
|
let root = node_process.cwd();
|
|
1518
|
+
let base = "/";
|
|
1519
|
+
let command = "serve";
|
|
1520
|
+
let assetsDir = "assets";
|
|
1080
1521
|
let routes = [];
|
|
1522
|
+
let serverRoutes = [];
|
|
1523
|
+
let swRoutes = [];
|
|
1081
1524
|
let app = null;
|
|
1082
1525
|
let previewWatcher = null;
|
|
1083
1526
|
let currentServer = null;
|
|
@@ -1087,6 +1530,9 @@ function createMokupPlugin(options = {}) {
|
|
|
1087
1530
|
const watchEnabled = optionList.every((entry) => entry.watch !== false);
|
|
1088
1531
|
const playgroundConfig = resolvePlaygroundOptions(resolvePlaygroundInput(optionList));
|
|
1089
1532
|
const logger = createLogger(logEnabled);
|
|
1533
|
+
const hasSwEntries = optionList.some((entry) => entry.mode === "sw");
|
|
1534
|
+
const swConfig = resolveSwConfig(optionList, logger);
|
|
1535
|
+
const unregisterConfig = resolveSwUnregisterConfig(optionList, logger);
|
|
1090
1536
|
const resolveAllDirs = () => {
|
|
1091
1537
|
const dirs = [];
|
|
1092
1538
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -1101,15 +1547,85 @@ function createMokupPlugin(options = {}) {
|
|
|
1101
1547
|
}
|
|
1102
1548
|
return dirs;
|
|
1103
1549
|
};
|
|
1550
|
+
const hasSwRoutes = () => !!swConfig && swRoutes.length > 0;
|
|
1551
|
+
const resolveSwRequestPath = (path) => resolveRegisterPath(base, path);
|
|
1552
|
+
const resolveSwRegisterScope = (scope) => resolveRegisterScope(base, scope);
|
|
1553
|
+
const resolveHtmlAssetPath = (fileName) => {
|
|
1554
|
+
const normalizedFileName = fileName.startsWith("/") ? fileName.slice(1) : fileName;
|
|
1555
|
+
if (base && base.startsWith(".")) {
|
|
1556
|
+
return normalizedFileName;
|
|
1557
|
+
}
|
|
1558
|
+
const normalizedBase = normalizeBase(base);
|
|
1559
|
+
return `${normalizedBase}${normalizedFileName}`;
|
|
1560
|
+
};
|
|
1561
|
+
const resolveAssetsFileName = (fileName) => {
|
|
1562
|
+
const trimmed = assetsDir.replace(/^\/+|\/+$/g, "");
|
|
1563
|
+
if (!trimmed) {
|
|
1564
|
+
return fileName;
|
|
1565
|
+
}
|
|
1566
|
+
return `${trimmed}/${fileName}`;
|
|
1567
|
+
};
|
|
1568
|
+
const swVirtualId = "virtual:mokup-sw";
|
|
1569
|
+
const resolvedSwVirtualId = `\0${swVirtualId}`;
|
|
1570
|
+
const swLifecycleVirtualId = "virtual:mokup-sw-lifecycle";
|
|
1571
|
+
const resolvedSwLifecycleVirtualId = `\0${swLifecycleVirtualId}`;
|
|
1572
|
+
let swLifecycleFileName = null;
|
|
1573
|
+
let swLifecycleScript = null;
|
|
1574
|
+
async function resolveSwModuleImport(context) {
|
|
1575
|
+
const resolved = await context.resolve("mokup/sw");
|
|
1576
|
+
if (resolved?.id) {
|
|
1577
|
+
return resolved.id;
|
|
1578
|
+
}
|
|
1579
|
+
const fallbackResolved = await context.resolve(localSwModulePath);
|
|
1580
|
+
if (fallbackResolved?.id) {
|
|
1581
|
+
return fallbackResolved.id;
|
|
1582
|
+
}
|
|
1583
|
+
return localSwModulePath;
|
|
1584
|
+
}
|
|
1585
|
+
function buildSwLifecycleScript(importPath = "mokup/sw") {
|
|
1586
|
+
const shouldUnregister = unregisterConfig.unregister === true || !hasSwEntries;
|
|
1587
|
+
if (shouldUnregister) {
|
|
1588
|
+
const path2 = resolveSwRequestPath(unregisterConfig.path);
|
|
1589
|
+
const scope2 = resolveSwRegisterScope(unregisterConfig.scope);
|
|
1590
|
+
return [
|
|
1591
|
+
`import { unregisterMokupServiceWorker } from ${JSON.stringify(importPath)}`,
|
|
1592
|
+
"(async () => {",
|
|
1593
|
+
` await unregisterMokupServiceWorker({ path: ${JSON.stringify(path2)}, scope: ${JSON.stringify(scope2)} })`,
|
|
1594
|
+
"})()"
|
|
1595
|
+
].join("\n");
|
|
1596
|
+
}
|
|
1597
|
+
if (!swConfig || swConfig.register === false) {
|
|
1598
|
+
return null;
|
|
1599
|
+
}
|
|
1600
|
+
if (!hasSwRoutes()) {
|
|
1601
|
+
return null;
|
|
1602
|
+
}
|
|
1603
|
+
const path = resolveSwRequestPath(swConfig.path);
|
|
1604
|
+
const scope = resolveSwRegisterScope(swConfig.scope);
|
|
1605
|
+
return [
|
|
1606
|
+
`import { registerMokupServiceWorker } from ${JSON.stringify(importPath)}`,
|
|
1607
|
+
"(async () => {",
|
|
1608
|
+
` const registration = await registerMokupServiceWorker({ path: ${JSON.stringify(path)}, scope: ${JSON.stringify(scope)} })`,
|
|
1609
|
+
" if (import.meta.hot && registration) {",
|
|
1610
|
+
" import.meta.hot.on('mokup:routes-changed', () => {",
|
|
1611
|
+
" registration.update()",
|
|
1612
|
+
" })",
|
|
1613
|
+
" }",
|
|
1614
|
+
"})()"
|
|
1615
|
+
].join("\n");
|
|
1616
|
+
}
|
|
1104
1617
|
const playgroundMiddleware = createPlaygroundMiddleware({
|
|
1105
1618
|
getRoutes: () => routes,
|
|
1106
1619
|
config: playgroundConfig,
|
|
1107
1620
|
logger,
|
|
1108
1621
|
getServer: () => currentServer,
|
|
1109
|
-
getDirs: () => resolveAllDirs()
|
|
1622
|
+
getDirs: () => resolveAllDirs(),
|
|
1623
|
+
getSwScript: () => buildSwLifecycleScript(resolveSwImportPath(base))
|
|
1110
1624
|
});
|
|
1111
1625
|
const refreshRoutes = async (server) => {
|
|
1112
1626
|
const collected = [];
|
|
1627
|
+
const collectedServer = [];
|
|
1628
|
+
const collectedSw = [];
|
|
1113
1629
|
for (const entry of optionList) {
|
|
1114
1630
|
const dirs = resolveDirs(entry.dir, root);
|
|
1115
1631
|
const scanParams = {
|
|
@@ -1128,9 +1644,19 @@ function createMokupPlugin(options = {}) {
|
|
|
1128
1644
|
}
|
|
1129
1645
|
const scanned = await scanRoutes(scanParams);
|
|
1130
1646
|
collected.push(...scanned);
|
|
1647
|
+
if (entry.mode === "sw") {
|
|
1648
|
+
collectedSw.push(...scanned);
|
|
1649
|
+
if (entry.sw?.fallback !== false) {
|
|
1650
|
+
collectedServer.push(...scanned);
|
|
1651
|
+
}
|
|
1652
|
+
} else {
|
|
1653
|
+
collectedServer.push(...scanned);
|
|
1654
|
+
}
|
|
1131
1655
|
}
|
|
1132
1656
|
routes = sortRoutes(collected);
|
|
1133
|
-
|
|
1657
|
+
serverRoutes = sortRoutes(collectedServer);
|
|
1658
|
+
swRoutes = sortRoutes(collectedSw);
|
|
1659
|
+
app = serverRoutes.length > 0 ? createHonoApp(serverRoutes) : null;
|
|
1134
1660
|
const signature = buildRouteSignature(routes);
|
|
1135
1661
|
if (isViteDevServer(server) && server.ws) {
|
|
1136
1662
|
if (lastSignature && signature !== lastSignature) {
|
|
@@ -1146,14 +1672,141 @@ function createMokupPlugin(options = {}) {
|
|
|
1146
1672
|
return {
|
|
1147
1673
|
name: "mokup:vite",
|
|
1148
1674
|
enforce: "pre",
|
|
1675
|
+
resolveId(id) {
|
|
1676
|
+
if (id === swVirtualId) {
|
|
1677
|
+
return resolvedSwVirtualId;
|
|
1678
|
+
}
|
|
1679
|
+
if (id === swLifecycleVirtualId) {
|
|
1680
|
+
return resolvedSwLifecycleVirtualId;
|
|
1681
|
+
}
|
|
1682
|
+
return null;
|
|
1683
|
+
},
|
|
1684
|
+
async load(id) {
|
|
1685
|
+
if (id !== resolvedSwVirtualId) {
|
|
1686
|
+
if (id !== resolvedSwLifecycleVirtualId) {
|
|
1687
|
+
return null;
|
|
1688
|
+
}
|
|
1689
|
+
if (!swLifecycleScript) {
|
|
1690
|
+
if (swRoutes.length === 0) {
|
|
1691
|
+
await refreshRoutes();
|
|
1692
|
+
}
|
|
1693
|
+
const importPath = await resolveSwModuleImport(this);
|
|
1694
|
+
swLifecycleScript = buildSwLifecycleScript(importPath);
|
|
1695
|
+
}
|
|
1696
|
+
return swLifecycleScript ?? "";
|
|
1697
|
+
}
|
|
1698
|
+
if (swRoutes.length === 0) {
|
|
1699
|
+
await refreshRoutes();
|
|
1700
|
+
}
|
|
1701
|
+
return buildSwScript({
|
|
1702
|
+
routes: swRoutes,
|
|
1703
|
+
root,
|
|
1704
|
+
basePaths: swConfig?.basePaths ?? []
|
|
1705
|
+
});
|
|
1706
|
+
},
|
|
1707
|
+
async buildStart() {
|
|
1708
|
+
if (command !== "build") {
|
|
1709
|
+
return;
|
|
1710
|
+
}
|
|
1711
|
+
await refreshRoutes();
|
|
1712
|
+
const shouldInject = buildSwLifecycleScript() !== null;
|
|
1713
|
+
swLifecycleScript = null;
|
|
1714
|
+
if (shouldInject) {
|
|
1715
|
+
swLifecycleFileName = resolveAssetsFileName("mokup-sw-lifecycle.js");
|
|
1716
|
+
this.emitFile({
|
|
1717
|
+
type: "chunk",
|
|
1718
|
+
id: swLifecycleVirtualId,
|
|
1719
|
+
fileName: swLifecycleFileName
|
|
1720
|
+
});
|
|
1721
|
+
} else {
|
|
1722
|
+
swLifecycleFileName = null;
|
|
1723
|
+
}
|
|
1724
|
+
if (!swConfig || !hasSwRoutes()) {
|
|
1725
|
+
return;
|
|
1726
|
+
}
|
|
1727
|
+
const fileName = swConfig.path.startsWith("/") ? swConfig.path.slice(1) : swConfig.path;
|
|
1728
|
+
this.emitFile({
|
|
1729
|
+
type: "chunk",
|
|
1730
|
+
id: swVirtualId,
|
|
1731
|
+
fileName
|
|
1732
|
+
});
|
|
1733
|
+
},
|
|
1734
|
+
async transformIndexHtml(html) {
|
|
1735
|
+
if (swRoutes.length === 0) {
|
|
1736
|
+
await refreshRoutes(currentServer ?? void 0);
|
|
1737
|
+
}
|
|
1738
|
+
const script = buildSwLifecycleScript();
|
|
1739
|
+
if (!script) {
|
|
1740
|
+
return html;
|
|
1741
|
+
}
|
|
1742
|
+
if (command === "build") {
|
|
1743
|
+
if (!swLifecycleFileName) {
|
|
1744
|
+
return html;
|
|
1745
|
+
}
|
|
1746
|
+
const src = resolveHtmlAssetPath(swLifecycleFileName);
|
|
1747
|
+
return {
|
|
1748
|
+
html,
|
|
1749
|
+
tags: [
|
|
1750
|
+
{
|
|
1751
|
+
tag: "script",
|
|
1752
|
+
attrs: { type: "module", src },
|
|
1753
|
+
injectTo: "head"
|
|
1754
|
+
}
|
|
1755
|
+
]
|
|
1756
|
+
};
|
|
1757
|
+
}
|
|
1758
|
+
return {
|
|
1759
|
+
html,
|
|
1760
|
+
tags: [
|
|
1761
|
+
{
|
|
1762
|
+
tag: "script",
|
|
1763
|
+
attrs: { type: "module" },
|
|
1764
|
+
children: script,
|
|
1765
|
+
injectTo: "head"
|
|
1766
|
+
}
|
|
1767
|
+
]
|
|
1768
|
+
};
|
|
1769
|
+
},
|
|
1149
1770
|
configResolved(config) {
|
|
1150
1771
|
root = config.root;
|
|
1772
|
+
base = config.base ?? "/";
|
|
1773
|
+
command = config.command;
|
|
1774
|
+
assetsDir = config.build.assetsDir ?? "assets";
|
|
1151
1775
|
},
|
|
1152
1776
|
async configureServer(server) {
|
|
1153
1777
|
currentServer = server;
|
|
1154
1778
|
await refreshRoutes(server);
|
|
1155
|
-
server
|
|
1156
|
-
|
|
1779
|
+
addMiddlewareFirst(server, playgroundMiddleware);
|
|
1780
|
+
const swPath = swConfig ? resolveSwRequestPath(swConfig.path) : null;
|
|
1781
|
+
if (swPath && hasSwRoutes()) {
|
|
1782
|
+
server.middlewares.use(async (req, res, next) => {
|
|
1783
|
+
const requestUrl = req.url ?? "/";
|
|
1784
|
+
const parsed = new URL(requestUrl, "http://mokup.local");
|
|
1785
|
+
if (parsed.pathname !== swPath) {
|
|
1786
|
+
return next();
|
|
1787
|
+
}
|
|
1788
|
+
try {
|
|
1789
|
+
const code = buildSwScript({
|
|
1790
|
+
routes: swRoutes,
|
|
1791
|
+
root,
|
|
1792
|
+
runtimeImportPath: resolveSwRuntimeImportPath(base),
|
|
1793
|
+
basePaths: swConfig?.basePaths ?? []
|
|
1794
|
+
});
|
|
1795
|
+
res.statusCode = 200;
|
|
1796
|
+
res.setHeader("Content-Type", "application/javascript; charset=utf-8");
|
|
1797
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
1798
|
+
res.end(code);
|
|
1799
|
+
} catch (error) {
|
|
1800
|
+
res.statusCode = 500;
|
|
1801
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
1802
|
+
res.end("Failed to generate mokup service worker.");
|
|
1803
|
+
logger.error("SW generation failed:", error);
|
|
1804
|
+
}
|
|
1805
|
+
});
|
|
1806
|
+
}
|
|
1807
|
+
if (serverRoutes.length > 0) {
|
|
1808
|
+
server.middlewares.use(createMiddleware(() => app, logger));
|
|
1809
|
+
}
|
|
1157
1810
|
if (!watchEnabled) {
|
|
1158
1811
|
return;
|
|
1159
1812
|
}
|
|
@@ -1179,8 +1832,36 @@ function createMokupPlugin(options = {}) {
|
|
|
1179
1832
|
async configurePreviewServer(server) {
|
|
1180
1833
|
currentServer = server;
|
|
1181
1834
|
await refreshRoutes(server);
|
|
1182
|
-
server
|
|
1183
|
-
|
|
1835
|
+
addMiddlewareFirst(server, playgroundMiddleware);
|
|
1836
|
+
const swPath = swConfig ? resolveSwRequestPath(swConfig.path) : null;
|
|
1837
|
+
if (swPath && hasSwRoutes()) {
|
|
1838
|
+
server.middlewares.use(async (req, res, next) => {
|
|
1839
|
+
const requestUrl = req.url ?? "/";
|
|
1840
|
+
const parsed = new URL(requestUrl, "http://mokup.local");
|
|
1841
|
+
if (parsed.pathname !== swPath) {
|
|
1842
|
+
return next();
|
|
1843
|
+
}
|
|
1844
|
+
try {
|
|
1845
|
+
const code = buildSwScript({
|
|
1846
|
+
routes: swRoutes,
|
|
1847
|
+
root,
|
|
1848
|
+
basePaths: swConfig?.basePaths ?? []
|
|
1849
|
+
});
|
|
1850
|
+
res.statusCode = 200;
|
|
1851
|
+
res.setHeader("Content-Type", "application/javascript; charset=utf-8");
|
|
1852
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
1853
|
+
res.end(code);
|
|
1854
|
+
} catch (error) {
|
|
1855
|
+
res.statusCode = 500;
|
|
1856
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
1857
|
+
res.end("Failed to generate mokup service worker.");
|
|
1858
|
+
logger.error("SW generation failed:", error);
|
|
1859
|
+
}
|
|
1860
|
+
});
|
|
1861
|
+
}
|
|
1862
|
+
if (serverRoutes.length > 0) {
|
|
1863
|
+
server.middlewares.use(createMiddleware(() => app, logger));
|
|
1864
|
+
}
|
|
1184
1865
|
if (!watchEnabled) {
|
|
1185
1866
|
return;
|
|
1186
1867
|
}
|