mokup 2.1.1 → 2.2.0

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.
@@ -246,6 +246,34 @@ function buildManifestData(params) {
246
246
  };
247
247
  }
248
248
 
249
+ const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/mokup.CYGG6ENd.cjs', document.baseURI).href)));
250
+ const mimeTypes = {
251
+ ".html": "text/html; charset=utf-8",
252
+ ".css": "text/css; charset=utf-8",
253
+ ".js": "text/javascript; charset=utf-8",
254
+ ".map": "application/json; charset=utf-8",
255
+ ".json": "application/json; charset=utf-8",
256
+ ".svg": "image/svg+xml",
257
+ ".png": "image/png",
258
+ ".jpg": "image/jpeg",
259
+ ".jpeg": "image/jpeg",
260
+ ".ico": "image/x-icon"
261
+ };
262
+ function resolvePlaygroundDist() {
263
+ const pkgPath = require$1.resolve("@mokup/playground/package.json");
264
+ return pathe.join(pkgPath, "..", "dist");
265
+ }
266
+ function sendJson(res, data, statusCode = 200) {
267
+ res.statusCode = statusCode;
268
+ res.setHeader("Content-Type", "application/json; charset=utf-8");
269
+ res.end(JSON.stringify(data, null, 2));
270
+ }
271
+ function sendFile(res, content, contentType) {
272
+ res.statusCode = 200;
273
+ res.setHeader("Content-Type", contentType);
274
+ res.end(content);
275
+ }
276
+
249
277
  function normalizePlaygroundPath(value) {
250
278
  if (!value) {
251
279
  return "/__mokup";
@@ -272,43 +300,16 @@ function resolvePlaygroundRequestPath(base, playgroundPath) {
272
300
  }
273
301
  function resolvePlaygroundOptions(playground) {
274
302
  if (playground === false) {
275
- return { enabled: false, path: "/__mokup" };
303
+ return { enabled: false, path: "/__mokup", build: false };
276
304
  }
277
305
  if (playground && typeof playground === "object") {
278
306
  return {
279
307
  enabled: playground.enabled !== false,
280
- path: normalizePlaygroundPath(playground.path)
308
+ path: normalizePlaygroundPath(playground.path),
309
+ build: playground.build === true
281
310
  };
282
311
  }
283
- return { enabled: true, path: "/__mokup" };
284
- }
285
-
286
- const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/mokup.To7knvSq.cjs', document.baseURI).href)));
287
- const mimeTypes = {
288
- ".html": "text/html; charset=utf-8",
289
- ".css": "text/css; charset=utf-8",
290
- ".js": "text/javascript; charset=utf-8",
291
- ".map": "application/json; charset=utf-8",
292
- ".json": "application/json; charset=utf-8",
293
- ".svg": "image/svg+xml",
294
- ".png": "image/png",
295
- ".jpg": "image/jpeg",
296
- ".jpeg": "image/jpeg",
297
- ".ico": "image/x-icon"
298
- };
299
- function resolvePlaygroundDist() {
300
- const pkgPath = require$1.resolve("@mokup/playground/package.json");
301
- return pathe.join(pkgPath, "..", "dist");
302
- }
303
- function sendJson(res, data, statusCode = 200) {
304
- res.statusCode = statusCode;
305
- res.setHeader("Content-Type", "application/json; charset=utf-8");
306
- res.end(JSON.stringify(data, null, 2));
307
- }
308
- function sendFile(res, content, contentType) {
309
- res.statusCode = 200;
310
- res.setHeader("Content-Type", contentType);
311
- res.end(content);
312
+ return { enabled: true, path: "/__mokup", build: false };
312
313
  }
313
314
 
314
315
  function toPosixPath(value) {
@@ -1316,7 +1317,7 @@ function isConfigFile(file) {
1316
1317
  return configExtensions.includes(ext);
1317
1318
  }
1318
1319
 
1319
- const sourceRoot = pathe.dirname(node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/mokup.To7knvSq.cjs', document.baseURI).href))));
1320
+ const sourceRoot = pathe.dirname(node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/mokup.CYGG6ENd.cjs', document.baseURI).href))));
1320
1321
  const mokupSourceEntry = pathe.resolve(sourceRoot, "../index.ts");
1321
1322
  const mokupViteSourceEntry = pathe.resolve(sourceRoot, "../vite.ts");
1322
1323
  const hasMokupSourceEntry = node_fs.existsSync(mokupSourceEntry);
@@ -1341,7 +1342,7 @@ const workspaceResolvePlugin = createWorkspaceResolvePlugin();
1341
1342
  async function loadModule(file) {
1342
1343
  const ext = pathe.extname(file).toLowerCase();
1343
1344
  if (ext === ".cjs") {
1344
- const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/mokup.To7knvSq.cjs', document.baseURI).href)));
1345
+ const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/mokup.CYGG6ENd.cjs', document.baseURI).href)));
1345
1346
  delete require$1.cache[file];
1346
1347
  return require$1(file);
1347
1348
  }
@@ -2063,11 +2064,21 @@ exports.createDebouncer = createDebouncer;
2063
2064
  exports.createHonoApp = createHonoApp;
2064
2065
  exports.createMiddleware = createMiddleware;
2065
2066
  exports.createPlaygroundMiddleware = createPlaygroundMiddleware;
2067
+ exports.injectPlaygroundSw = injectPlaygroundSw;
2066
2068
  exports.isInDirs = isInDirs;
2069
+ exports.normalizePlaygroundPath = normalizePlaygroundPath;
2067
2070
  exports.resolveDirs = resolveDirs;
2071
+ exports.resolveGroupRoot = resolveGroupRoot;
2072
+ exports.resolveGroups = resolveGroups;
2073
+ exports.resolvePlaygroundDist = resolvePlaygroundDist;
2068
2074
  exports.resolvePlaygroundOptions = resolvePlaygroundOptions;
2075
+ exports.resolvePlaygroundRequestPath = resolvePlaygroundRequestPath;
2069
2076
  exports.resolveSwConfig = resolveSwConfig;
2070
2077
  exports.resolveSwUnregisterConfig = resolveSwUnregisterConfig;
2071
2078
  exports.scanRoutes = scanRoutes;
2072
2079
  exports.sortRoutes = sortRoutes;
2080
+ exports.toPlaygroundConfigFile = toPlaygroundConfigFile;
2081
+ exports.toPlaygroundDisabledRoute = toPlaygroundDisabledRoute;
2082
+ exports.toPlaygroundIgnoredRoute = toPlaygroundIgnoredRoute;
2083
+ exports.toPlaygroundRoute = toPlaygroundRoute;
2073
2084
  exports.toPosix = toPosix;
@@ -243,6 +243,34 @@ function buildManifestData(params) {
243
243
  };
244
244
  }
245
245
 
246
+ const require$1 = createRequire(import.meta.url);
247
+ const mimeTypes = {
248
+ ".html": "text/html; charset=utf-8",
249
+ ".css": "text/css; charset=utf-8",
250
+ ".js": "text/javascript; charset=utf-8",
251
+ ".map": "application/json; charset=utf-8",
252
+ ".json": "application/json; charset=utf-8",
253
+ ".svg": "image/svg+xml",
254
+ ".png": "image/png",
255
+ ".jpg": "image/jpeg",
256
+ ".jpeg": "image/jpeg",
257
+ ".ico": "image/x-icon"
258
+ };
259
+ function resolvePlaygroundDist() {
260
+ const pkgPath = require$1.resolve("@mokup/playground/package.json");
261
+ return join(pkgPath, "..", "dist");
262
+ }
263
+ function sendJson(res, data, statusCode = 200) {
264
+ res.statusCode = statusCode;
265
+ res.setHeader("Content-Type", "application/json; charset=utf-8");
266
+ res.end(JSON.stringify(data, null, 2));
267
+ }
268
+ function sendFile(res, content, contentType) {
269
+ res.statusCode = 200;
270
+ res.setHeader("Content-Type", contentType);
271
+ res.end(content);
272
+ }
273
+
246
274
  function normalizePlaygroundPath(value) {
247
275
  if (!value) {
248
276
  return "/__mokup";
@@ -269,43 +297,16 @@ function resolvePlaygroundRequestPath(base, playgroundPath) {
269
297
  }
270
298
  function resolvePlaygroundOptions(playground) {
271
299
  if (playground === false) {
272
- return { enabled: false, path: "/__mokup" };
300
+ return { enabled: false, path: "/__mokup", build: false };
273
301
  }
274
302
  if (playground && typeof playground === "object") {
275
303
  return {
276
304
  enabled: playground.enabled !== false,
277
- path: normalizePlaygroundPath(playground.path)
305
+ path: normalizePlaygroundPath(playground.path),
306
+ build: playground.build === true
278
307
  };
279
308
  }
280
- return { enabled: true, path: "/__mokup" };
281
- }
282
-
283
- const require$1 = createRequire(import.meta.url);
284
- const mimeTypes = {
285
- ".html": "text/html; charset=utf-8",
286
- ".css": "text/css; charset=utf-8",
287
- ".js": "text/javascript; charset=utf-8",
288
- ".map": "application/json; charset=utf-8",
289
- ".json": "application/json; charset=utf-8",
290
- ".svg": "image/svg+xml",
291
- ".png": "image/png",
292
- ".jpg": "image/jpeg",
293
- ".jpeg": "image/jpeg",
294
- ".ico": "image/x-icon"
295
- };
296
- function resolvePlaygroundDist() {
297
- const pkgPath = require$1.resolve("@mokup/playground/package.json");
298
- return join(pkgPath, "..", "dist");
299
- }
300
- function sendJson(res, data, statusCode = 200) {
301
- res.statusCode = statusCode;
302
- res.setHeader("Content-Type", "application/json; charset=utf-8");
303
- res.end(JSON.stringify(data, null, 2));
304
- }
305
- function sendFile(res, content, contentType) {
306
- res.statusCode = 200;
307
- res.setHeader("Content-Type", contentType);
308
- res.end(content);
309
+ return { enabled: true, path: "/__mokup", build: false };
309
310
  }
310
311
 
311
312
  function toPosixPath(value) {
@@ -2054,4 +2055,4 @@ async function scanRoutes(params) {
2054
2055
  return sortRoutes(routes);
2055
2056
  }
2056
2057
 
2057
- export { sortRoutes as a, buildSwScript as b, createHonoApp as c, createDebouncer as d, resolvePlaygroundOptions as e, resolveSwConfig as f, resolveSwUnregisterConfig as g, createPlaygroundMiddleware as h, isInDirs as i, createMiddleware as j, buildManifestData as k, resolveDirs as r, scanRoutes as s, toPosix as t };
2058
+ export { sortRoutes as a, buildSwScript as b, createHonoApp as c, createDebouncer as d, resolvePlaygroundOptions as e, resolveSwConfig as f, resolveSwUnregisterConfig as g, createPlaygroundMiddleware as h, isInDirs as i, createMiddleware as j, buildManifestData as k, resolvePlaygroundDist as l, injectPlaygroundSw as m, normalizePlaygroundPath as n, resolveGroupRoot as o, resolveGroups as p, resolvePlaygroundRequestPath as q, resolveDirs as r, scanRoutes as s, toPosix as t, toPlaygroundConfigFile as u, toPlaygroundIgnoredRoute as v, toPlaygroundDisabledRoute as w, toPlaygroundRoute as x };
package/dist/vite.cjs CHANGED
@@ -1,14 +1,14 @@
1
1
  'use strict';
2
2
 
3
3
  const process = require('node:process');
4
- const scanner = require('./shared/mokup.To7knvSq.cjs');
4
+ const scanner = require('./shared/mokup.CYGG6ENd.cjs');
5
+ const node_fs = require('node:fs');
6
+ const pathe = require('@mokup/shared/pathe');
5
7
  const logger = require('@mokup/shared/logger');
6
8
  const pc = require('picocolors');
7
9
  const node_path = require('node:path');
8
10
  const chokidar = require('@mokup/shared/chokidar');
9
- const node_fs = require('node:fs');
10
11
  const node_url = require('node:url');
11
- require('@mokup/shared/pathe');
12
12
  require('node:module');
13
13
  require('node:buffer');
14
14
  require('@mokup/shared/hono');
@@ -64,6 +64,79 @@ function buildBundleModule(params) {
64
64
  return lines.join("\n");
65
65
  }
66
66
 
67
+ function resolvePlaygroundOutDir(outDir, playgroundPath) {
68
+ const normalized = scanner.normalizePlaygroundPath(playgroundPath);
69
+ const trimmed = normalized.replace(/^\/+/, "");
70
+ return trimmed ? pathe.join(outDir, pathe.normalize(trimmed)) : outDir;
71
+ }
72
+ function stripSwLifecycle(html) {
73
+ return html.replace(
74
+ /<script[^>]*mokup-sw-lifecycle\.js[^>]*><\/script>\s*/gi,
75
+ ""
76
+ );
77
+ }
78
+ async function writeRoutesPayload(params, targetDir) {
79
+ const baseRoot = scanner.resolveGroupRoot(params.dirs, params.root);
80
+ const groups = scanner.resolveGroups(params.dirs, baseRoot);
81
+ const basePath = scanner.resolvePlaygroundRequestPath(params.base, params.playgroundPath);
82
+ const payload = {
83
+ basePath,
84
+ root: baseRoot,
85
+ count: params.routes.length,
86
+ groups: groups.map((group) => ({ key: group.key, label: group.label })),
87
+ routes: params.routes.map((route) => scanner.toPlaygroundRoute(route, baseRoot, groups)),
88
+ disabled: params.disabledRoutes.map(
89
+ (route) => scanner.toPlaygroundDisabledRoute(route, baseRoot, groups)
90
+ ),
91
+ ignored: params.ignoredRoutes.map(
92
+ (route) => scanner.toPlaygroundIgnoredRoute(route, baseRoot, groups)
93
+ ),
94
+ configs: params.configFiles.map((entry) => scanner.toPlaygroundConfigFile(entry, baseRoot, groups)),
95
+ disabledConfigs: params.disabledConfigFiles.map(
96
+ (entry) => scanner.toPlaygroundConfigFile(entry, baseRoot, groups)
97
+ )
98
+ };
99
+ await node_fs.promises.writeFile(
100
+ pathe.join(targetDir, "routes"),
101
+ JSON.stringify(payload, null, 2),
102
+ "utf8"
103
+ );
104
+ }
105
+ async function updateIndexHtml(targetDir, swScript) {
106
+ const indexPath = pathe.join(targetDir, "index.html");
107
+ const html = await node_fs.promises.readFile(indexPath, "utf8");
108
+ const cleaned = stripSwLifecycle(html);
109
+ const output = swScript ? scanner.injectPlaygroundSw(cleaned, swScript) : cleaned;
110
+ await node_fs.promises.writeFile(indexPath, output, "utf8");
111
+ }
112
+ async function removeLegacySwAsset(targetDir) {
113
+ const legacyFiles = [
114
+ pathe.join(targetDir, "assets", "mokup-sw-lifecycle.js"),
115
+ pathe.join(targetDir, "assets", "mokup-sw-lifecycle.js.map")
116
+ ];
117
+ await Promise.all(legacyFiles.map((file) => node_fs.promises.rm(file, { force: true })));
118
+ }
119
+ async function writePlaygroundBuild(params) {
120
+ const distDir = scanner.resolvePlaygroundDist();
121
+ const targetDir = resolvePlaygroundOutDir(params.outDir, params.playgroundPath);
122
+ if (targetDir === params.outDir) {
123
+ params.logger.error("Playground build path resolves to the Vite outDir. Aborting output.");
124
+ return;
125
+ }
126
+ try {
127
+ await node_fs.promises.stat(distDir);
128
+ } catch (error) {
129
+ params.logger.error("Failed to locate playground assets:", error);
130
+ return;
131
+ }
132
+ await node_fs.promises.rm(targetDir, { recursive: true, force: true });
133
+ await node_fs.promises.mkdir(params.outDir, { recursive: true });
134
+ await node_fs.promises.cp(distDir, targetDir, { recursive: true });
135
+ await removeLegacySwAsset(targetDir);
136
+ await updateIndexHtml(targetDir, params.swScript);
137
+ await writeRoutesPayload(params, targetDir);
138
+ }
139
+
67
140
  const legacyEntryKeys = [
68
141
  "dir",
69
142
  "prefix",
@@ -614,17 +687,35 @@ async function configurePreviewServer(params) {
614
687
  }
615
688
 
616
689
  const swModuleCandidates = [
617
- 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))),
618
- 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)))
690
+ "dist/sw.mjs",
691
+ "dist/sw.js",
692
+ "src/sw.ts",
693
+ "src/sw.js"
619
694
  ];
695
+ function resolvePackageRoot() {
696
+ const moduleDir = node_path.dirname(node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('vite.cjs', document.baseURI).href))));
697
+ let current = moduleDir;
698
+ for (let index = 0; index < 6; index += 1) {
699
+ if (node_fs.existsSync(node_path.resolve(current, "package.json"))) {
700
+ return current;
701
+ }
702
+ const parent = node_path.dirname(current);
703
+ if (parent === current) {
704
+ break;
705
+ }
706
+ current = parent;
707
+ }
708
+ return moduleDir;
709
+ }
620
710
  const localSwModulePath = (() => {
711
+ const packageRoot = resolvePackageRoot();
621
712
  for (const candidate of swModuleCandidates) {
622
- const filePath = node_url.fileURLToPath(candidate);
713
+ const filePath = node_path.resolve(packageRoot, candidate);
623
714
  if (node_fs.existsSync(filePath)) {
624
715
  return filePath;
625
716
  }
626
717
  }
627
- 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))));
718
+ return node_path.resolve(packageRoot, "src/sw.ts");
628
719
  })();
629
720
  async function resolveSwModuleImport(context) {
630
721
  const resolved = await context.resolve("mokup/sw");
@@ -678,12 +769,102 @@ function buildSwLifecycleScript(params) {
678
769
  "})()"
679
770
  ].join("\n");
680
771
  }
772
+ function buildSwLifecycleInlineScript(params) {
773
+ const {
774
+ swConfig,
775
+ unregisterConfig,
776
+ hasSwEntries,
777
+ hasSwRoutes,
778
+ resolveRequestPath,
779
+ resolveRegisterScope
780
+ } = params;
781
+ const shouldUnregister = unregisterConfig.unregister === true || !hasSwEntries;
782
+ if (shouldUnregister) {
783
+ const path2 = resolveRequestPath(unregisterConfig.path);
784
+ const scope2 = resolveRegisterScope(unregisterConfig.scope);
785
+ return [
786
+ "(async () => {",
787
+ " if (typeof window === 'undefined' || !('serviceWorker' in navigator)) {",
788
+ " return",
789
+ " }",
790
+ ` const path = ${JSON.stringify(path2)}`,
791
+ ` const scope = ${JSON.stringify(scope2)}`,
792
+ " const origin = window.location.origin",
793
+ " const normalizeScope = (value) => {",
794
+ " const url = new URL(value, origin)",
795
+ " if (!url.pathname.endsWith('/')) {",
796
+ " url.pathname = url.pathname + '/'",
797
+ " }",
798
+ " return url.href",
799
+ " }",
800
+ " const pathUrl = new URL(path, origin)",
801
+ " const scopeUrl = normalizeScope(scope)",
802
+ " const matchesScript = (scriptUrl) => {",
803
+ " if (!scriptUrl) {",
804
+ " return false",
805
+ " }",
806
+ " try {",
807
+ " const parsed = new URL(scriptUrl)",
808
+ " return parsed.origin === origin && parsed.pathname === pathUrl.pathname",
809
+ " }",
810
+ " catch {",
811
+ " return false",
812
+ " }",
813
+ " }",
814
+ " try {",
815
+ " const registrations = await navigator.serviceWorker.getRegistrations()",
816
+ " for (const registration of registrations) {",
817
+ " if (registration.scope !== scopeUrl) {",
818
+ " continue",
819
+ " }",
820
+ " const scriptUrls = [",
821
+ " registration.active?.scriptURL,",
822
+ " registration.waiting?.scriptURL,",
823
+ " registration.installing?.scriptURL,",
824
+ " ]",
825
+ " if (scriptUrls.some(matchesScript)) {",
826
+ " await registration.unregister()",
827
+ " }",
828
+ " }",
829
+ " }",
830
+ " catch (error) {",
831
+ " console.warn('Failed to unregister service worker:', error)",
832
+ " }",
833
+ "})()"
834
+ ].join("\n");
835
+ }
836
+ if (!swConfig || swConfig.register === false) {
837
+ return null;
838
+ }
839
+ if (!hasSwRoutes) {
840
+ return null;
841
+ }
842
+ const path = resolveRequestPath(swConfig.path);
843
+ const scope = resolveRegisterScope(swConfig.scope);
844
+ return [
845
+ "(async () => {",
846
+ " if (typeof window === 'undefined' || !('serviceWorker' in navigator)) {",
847
+ " return",
848
+ " }",
849
+ ` const path = ${JSON.stringify(path)}`,
850
+ ` const scope = ${JSON.stringify(scope)}`,
851
+ " try {",
852
+ " await navigator.serviceWorker.register(path, { type: 'module', scope })",
853
+ " }",
854
+ " catch (error) {",
855
+ " console.warn('Failed to register service worker:', error)",
856
+ " }",
857
+ "})()"
858
+ ].join("\n");
859
+ }
681
860
 
682
861
  function createMokupPlugin(options = {}) {
683
862
  let root = process.cwd();
684
863
  let base = "/";
685
864
  let command = "serve";
686
865
  let assetsDir = "assets";
866
+ let outDir = "dist";
867
+ let isSsrBuild = false;
687
868
  const state = {
688
869
  routes: [],
689
870
  serverRoutes: [],
@@ -902,6 +1083,8 @@ function createMokupPlugin(options = {}) {
902
1083
  base = config.base ?? "/";
903
1084
  command = config.command;
904
1085
  assetsDir = config.build.assetsDir ?? "assets";
1086
+ outDir = config.build.outDir ?? "dist";
1087
+ isSsrBuild = !!config.build.ssr;
905
1088
  },
906
1089
  async configureServer(server) {
907
1090
  currentServer = server;
@@ -941,9 +1124,35 @@ function createMokupPlugin(options = {}) {
941
1124
  previewWatcher = null;
942
1125
  });
943
1126
  },
944
- closeBundle() {
1127
+ async closeBundle() {
945
1128
  previewWatcher?.close();
946
1129
  previewWatcher = null;
1130
+ if (command !== "build" || isSsrBuild || !playgroundConfig.enabled || playgroundConfig.build !== true) {
1131
+ return;
1132
+ }
1133
+ await refreshRoutes();
1134
+ const swScript = buildSwLifecycleInlineScript({
1135
+ swConfig,
1136
+ unregisterConfig,
1137
+ hasSwEntries,
1138
+ hasSwRoutes: hasSwRoutes(),
1139
+ resolveRequestPath: resolveSwRequestPath,
1140
+ resolveRegisterScope: resolveSwRegisterScope
1141
+ });
1142
+ await writePlaygroundBuild({
1143
+ outDir,
1144
+ base,
1145
+ playgroundPath: playgroundConfig.path,
1146
+ root,
1147
+ routes: state.routes,
1148
+ disabledRoutes: state.disabledRoutes,
1149
+ ignoredRoutes: state.ignoredRoutes,
1150
+ configFiles: state.configFiles,
1151
+ disabledConfigFiles: state.disabledConfigFiles,
1152
+ dirs: resolveAllDirs(),
1153
+ swScript,
1154
+ logger: logger$1
1155
+ });
947
1156
  }
948
1157
  };
949
1158
  }
package/dist/vite.mjs CHANGED
@@ -1,12 +1,12 @@
1
1
  import { cwd } from 'node:process';
2
- import { k as buildManifestData, r as resolveDirs, s as scanRoutes, a as sortRoutes, c as createHonoApp, i as isInDirs, d as createDebouncer, b as buildSwScript, j as createMiddleware, e as resolvePlaygroundOptions, f as resolveSwConfig, g as resolveSwUnregisterConfig, h as createPlaygroundMiddleware } from './shared/mokup.ghra3mzH.mjs';
2
+ import { k as buildManifestData, l as resolvePlaygroundDist, n as normalizePlaygroundPath, m as injectPlaygroundSw, o as resolveGroupRoot, p as resolveGroups, q as resolvePlaygroundRequestPath, u as toPlaygroundConfigFile, v as toPlaygroundIgnoredRoute, w as toPlaygroundDisabledRoute, x as toPlaygroundRoute, r as resolveDirs, s as scanRoutes, a as sortRoutes, c as createHonoApp, i as isInDirs, d as createDebouncer, b as buildSwScript, j as createMiddleware, e as resolvePlaygroundOptions, f as resolveSwConfig, g as resolveSwUnregisterConfig, h as createPlaygroundMiddleware } from './shared/mokup.ClsvLg8n.mjs';
3
+ import { promises, existsSync } from 'node:fs';
4
+ import { join, normalize } from '@mokup/shared/pathe';
3
5
  import { createLogger } from '@mokup/shared/logger';
4
6
  import pc from 'picocolors';
5
- import { isAbsolute, resolve } from 'node:path';
7
+ import { isAbsolute, resolve, dirname } from 'node:path';
6
8
  import chokidar from '@mokup/shared/chokidar';
7
- import { existsSync } from 'node:fs';
8
9
  import { fileURLToPath } from 'node:url';
9
- import '@mokup/shared/pathe';
10
10
  import 'node:module';
11
11
  import 'node:buffer';
12
12
  import '@mokup/shared/hono';
@@ -56,6 +56,79 @@ function buildBundleModule(params) {
56
56
  return lines.join("\n");
57
57
  }
58
58
 
59
+ function resolvePlaygroundOutDir(outDir, playgroundPath) {
60
+ const normalized = normalizePlaygroundPath(playgroundPath);
61
+ const trimmed = normalized.replace(/^\/+/, "");
62
+ return trimmed ? join(outDir, normalize(trimmed)) : outDir;
63
+ }
64
+ function stripSwLifecycle(html) {
65
+ return html.replace(
66
+ /<script[^>]*mokup-sw-lifecycle\.js[^>]*><\/script>\s*/gi,
67
+ ""
68
+ );
69
+ }
70
+ async function writeRoutesPayload(params, targetDir) {
71
+ const baseRoot = resolveGroupRoot(params.dirs, params.root);
72
+ const groups = resolveGroups(params.dirs, baseRoot);
73
+ const basePath = resolvePlaygroundRequestPath(params.base, params.playgroundPath);
74
+ const payload = {
75
+ basePath,
76
+ root: baseRoot,
77
+ count: params.routes.length,
78
+ groups: groups.map((group) => ({ key: group.key, label: group.label })),
79
+ routes: params.routes.map((route) => toPlaygroundRoute(route, baseRoot, groups)),
80
+ disabled: params.disabledRoutes.map(
81
+ (route) => toPlaygroundDisabledRoute(route, baseRoot, groups)
82
+ ),
83
+ ignored: params.ignoredRoutes.map(
84
+ (route) => toPlaygroundIgnoredRoute(route, baseRoot, groups)
85
+ ),
86
+ configs: params.configFiles.map((entry) => toPlaygroundConfigFile(entry, baseRoot, groups)),
87
+ disabledConfigs: params.disabledConfigFiles.map(
88
+ (entry) => toPlaygroundConfigFile(entry, baseRoot, groups)
89
+ )
90
+ };
91
+ await promises.writeFile(
92
+ join(targetDir, "routes"),
93
+ JSON.stringify(payload, null, 2),
94
+ "utf8"
95
+ );
96
+ }
97
+ async function updateIndexHtml(targetDir, swScript) {
98
+ const indexPath = join(targetDir, "index.html");
99
+ const html = await promises.readFile(indexPath, "utf8");
100
+ const cleaned = stripSwLifecycle(html);
101
+ const output = swScript ? injectPlaygroundSw(cleaned, swScript) : cleaned;
102
+ await promises.writeFile(indexPath, output, "utf8");
103
+ }
104
+ async function removeLegacySwAsset(targetDir) {
105
+ const legacyFiles = [
106
+ join(targetDir, "assets", "mokup-sw-lifecycle.js"),
107
+ join(targetDir, "assets", "mokup-sw-lifecycle.js.map")
108
+ ];
109
+ await Promise.all(legacyFiles.map((file) => promises.rm(file, { force: true })));
110
+ }
111
+ async function writePlaygroundBuild(params) {
112
+ const distDir = resolvePlaygroundDist();
113
+ const targetDir = resolvePlaygroundOutDir(params.outDir, params.playgroundPath);
114
+ if (targetDir === params.outDir) {
115
+ params.logger.error("Playground build path resolves to the Vite outDir. Aborting output.");
116
+ return;
117
+ }
118
+ try {
119
+ await promises.stat(distDir);
120
+ } catch (error) {
121
+ params.logger.error("Failed to locate playground assets:", error);
122
+ return;
123
+ }
124
+ await promises.rm(targetDir, { recursive: true, force: true });
125
+ await promises.mkdir(params.outDir, { recursive: true });
126
+ await promises.cp(distDir, targetDir, { recursive: true });
127
+ await removeLegacySwAsset(targetDir);
128
+ await updateIndexHtml(targetDir, params.swScript);
129
+ await writeRoutesPayload(params, targetDir);
130
+ }
131
+
59
132
  const legacyEntryKeys = [
60
133
  "dir",
61
134
  "prefix",
@@ -606,17 +679,35 @@ async function configurePreviewServer(params) {
606
679
  }
607
680
 
608
681
  const swModuleCandidates = [
609
- new URL("../../sw.ts", import.meta.url),
610
- new URL("../../sw.js", import.meta.url)
682
+ "dist/sw.mjs",
683
+ "dist/sw.js",
684
+ "src/sw.ts",
685
+ "src/sw.js"
611
686
  ];
687
+ function resolvePackageRoot() {
688
+ const moduleDir = dirname(fileURLToPath(import.meta.url));
689
+ let current = moduleDir;
690
+ for (let index = 0; index < 6; index += 1) {
691
+ if (existsSync(resolve(current, "package.json"))) {
692
+ return current;
693
+ }
694
+ const parent = dirname(current);
695
+ if (parent === current) {
696
+ break;
697
+ }
698
+ current = parent;
699
+ }
700
+ return moduleDir;
701
+ }
612
702
  const localSwModulePath = (() => {
703
+ const packageRoot = resolvePackageRoot();
613
704
  for (const candidate of swModuleCandidates) {
614
- const filePath = fileURLToPath(candidate);
705
+ const filePath = resolve(packageRoot, candidate);
615
706
  if (existsSync(filePath)) {
616
707
  return filePath;
617
708
  }
618
709
  }
619
- return fileURLToPath(swModuleCandidates[0] ?? new URL("../../sw.ts", import.meta.url));
710
+ return resolve(packageRoot, "src/sw.ts");
620
711
  })();
621
712
  async function resolveSwModuleImport(context) {
622
713
  const resolved = await context.resolve("mokup/sw");
@@ -670,12 +761,102 @@ function buildSwLifecycleScript(params) {
670
761
  "})()"
671
762
  ].join("\n");
672
763
  }
764
+ function buildSwLifecycleInlineScript(params) {
765
+ const {
766
+ swConfig,
767
+ unregisterConfig,
768
+ hasSwEntries,
769
+ hasSwRoutes,
770
+ resolveRequestPath,
771
+ resolveRegisterScope
772
+ } = params;
773
+ const shouldUnregister = unregisterConfig.unregister === true || !hasSwEntries;
774
+ if (shouldUnregister) {
775
+ const path2 = resolveRequestPath(unregisterConfig.path);
776
+ const scope2 = resolveRegisterScope(unregisterConfig.scope);
777
+ return [
778
+ "(async () => {",
779
+ " if (typeof window === 'undefined' || !('serviceWorker' in navigator)) {",
780
+ " return",
781
+ " }",
782
+ ` const path = ${JSON.stringify(path2)}`,
783
+ ` const scope = ${JSON.stringify(scope2)}`,
784
+ " const origin = window.location.origin",
785
+ " const normalizeScope = (value) => {",
786
+ " const url = new URL(value, origin)",
787
+ " if (!url.pathname.endsWith('/')) {",
788
+ " url.pathname = url.pathname + '/'",
789
+ " }",
790
+ " return url.href",
791
+ " }",
792
+ " const pathUrl = new URL(path, origin)",
793
+ " const scopeUrl = normalizeScope(scope)",
794
+ " const matchesScript = (scriptUrl) => {",
795
+ " if (!scriptUrl) {",
796
+ " return false",
797
+ " }",
798
+ " try {",
799
+ " const parsed = new URL(scriptUrl)",
800
+ " return parsed.origin === origin && parsed.pathname === pathUrl.pathname",
801
+ " }",
802
+ " catch {",
803
+ " return false",
804
+ " }",
805
+ " }",
806
+ " try {",
807
+ " const registrations = await navigator.serviceWorker.getRegistrations()",
808
+ " for (const registration of registrations) {",
809
+ " if (registration.scope !== scopeUrl) {",
810
+ " continue",
811
+ " }",
812
+ " const scriptUrls = [",
813
+ " registration.active?.scriptURL,",
814
+ " registration.waiting?.scriptURL,",
815
+ " registration.installing?.scriptURL,",
816
+ " ]",
817
+ " if (scriptUrls.some(matchesScript)) {",
818
+ " await registration.unregister()",
819
+ " }",
820
+ " }",
821
+ " }",
822
+ " catch (error) {",
823
+ " console.warn('Failed to unregister service worker:', error)",
824
+ " }",
825
+ "})()"
826
+ ].join("\n");
827
+ }
828
+ if (!swConfig || swConfig.register === false) {
829
+ return null;
830
+ }
831
+ if (!hasSwRoutes) {
832
+ return null;
833
+ }
834
+ const path = resolveRequestPath(swConfig.path);
835
+ const scope = resolveRegisterScope(swConfig.scope);
836
+ return [
837
+ "(async () => {",
838
+ " if (typeof window === 'undefined' || !('serviceWorker' in navigator)) {",
839
+ " return",
840
+ " }",
841
+ ` const path = ${JSON.stringify(path)}`,
842
+ ` const scope = ${JSON.stringify(scope)}`,
843
+ " try {",
844
+ " await navigator.serviceWorker.register(path, { type: 'module', scope })",
845
+ " }",
846
+ " catch (error) {",
847
+ " console.warn('Failed to register service worker:', error)",
848
+ " }",
849
+ "})()"
850
+ ].join("\n");
851
+ }
673
852
 
674
853
  function createMokupPlugin(options = {}) {
675
854
  let root = cwd();
676
855
  let base = "/";
677
856
  let command = "serve";
678
857
  let assetsDir = "assets";
858
+ let outDir = "dist";
859
+ let isSsrBuild = false;
679
860
  const state = {
680
861
  routes: [],
681
862
  serverRoutes: [],
@@ -894,6 +1075,8 @@ function createMokupPlugin(options = {}) {
894
1075
  base = config.base ?? "/";
895
1076
  command = config.command;
896
1077
  assetsDir = config.build.assetsDir ?? "assets";
1078
+ outDir = config.build.outDir ?? "dist";
1079
+ isSsrBuild = !!config.build.ssr;
897
1080
  },
898
1081
  async configureServer(server) {
899
1082
  currentServer = server;
@@ -933,9 +1116,35 @@ function createMokupPlugin(options = {}) {
933
1116
  previewWatcher = null;
934
1117
  });
935
1118
  },
936
- closeBundle() {
1119
+ async closeBundle() {
937
1120
  previewWatcher?.close();
938
1121
  previewWatcher = null;
1122
+ if (command !== "build" || isSsrBuild || !playgroundConfig.enabled || playgroundConfig.build !== true) {
1123
+ return;
1124
+ }
1125
+ await refreshRoutes();
1126
+ const swScript = buildSwLifecycleInlineScript({
1127
+ swConfig,
1128
+ unregisterConfig,
1129
+ hasSwEntries,
1130
+ hasSwRoutes: hasSwRoutes(),
1131
+ resolveRequestPath: resolveSwRequestPath,
1132
+ resolveRegisterScope: resolveSwRegisterScope
1133
+ });
1134
+ await writePlaygroundBuild({
1135
+ outDir,
1136
+ base,
1137
+ playgroundPath: playgroundConfig.path,
1138
+ root,
1139
+ routes: state.routes,
1140
+ disabledRoutes: state.disabledRoutes,
1141
+ ignoredRoutes: state.ignoredRoutes,
1142
+ configFiles: state.configFiles,
1143
+ disabledConfigFiles: state.disabledConfigFiles,
1144
+ dirs: resolveAllDirs(),
1145
+ swScript,
1146
+ logger
1147
+ });
939
1148
  }
940
1149
  };
941
1150
  }
package/dist/webpack.cjs CHANGED
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
3
  const process = require('node:process');
4
- const scanner = require('./shared/mokup.To7knvSq.cjs');
4
+ const scanner = require('./shared/mokup.CYGG6ENd.cjs');
5
+ require('node:fs');
6
+ const pathe = require('@mokup/shared/pathe');
5
7
  const logger = require('@mokup/shared/logger');
6
8
  const esbuild = require('@mokup/shared/esbuild');
7
9
  const node_module = require('node:module');
8
- const pathe = require('@mokup/shared/pathe');
9
10
  const chokidar = require('@mokup/shared/chokidar');
10
- require('node:fs');
11
11
  require('node:buffer');
12
12
  require('@mokup/shared/hono');
13
13
  require('node:url');
package/dist/webpack.mjs CHANGED
@@ -1,11 +1,11 @@
1
1
  import { cwd } from 'node:process';
2
- import { b as buildSwScript, t as toPosix, r as resolveDirs, s as scanRoutes, a as sortRoutes, c as createHonoApp, i as isInDirs, d as createDebouncer, e as resolvePlaygroundOptions, f as resolveSwConfig, g as resolveSwUnregisterConfig, h as createPlaygroundMiddleware, j as createMiddleware } from './shared/mokup.ghra3mzH.mjs';
2
+ import { b as buildSwScript, t as toPosix, r as resolveDirs, s as scanRoutes, a as sortRoutes, c as createHonoApp, i as isInDirs, d as createDebouncer, e as resolvePlaygroundOptions, f as resolveSwConfig, g as resolveSwUnregisterConfig, h as createPlaygroundMiddleware, j as createMiddleware } from './shared/mokup.ClsvLg8n.mjs';
3
+ import 'node:fs';
4
+ import { isAbsolute, resolve } from '@mokup/shared/pathe';
3
5
  import { createLogger } from '@mokup/shared/logger';
4
6
  import { build } from '@mokup/shared/esbuild';
5
7
  import { createRequire } from 'node:module';
6
- import { isAbsolute, resolve } from '@mokup/shared/pathe';
7
8
  import chokidar from '@mokup/shared/chokidar';
8
- import 'node:fs';
9
9
  import 'node:buffer';
10
10
  import '@mokup/shared/hono';
11
11
  import 'node:url';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mokup",
3
3
  "type": "module",
4
- "version": "2.1.1",
4
+ "version": "2.2.0",
5
5
  "description": "Mock utilities and Vite plugin for mokup.",
6
6
  "license": "MIT",
7
7
  "homepage": "https://mokup.icebreaker.top",
@@ -92,11 +92,11 @@
92
92
  },
93
93
  "dependencies": {
94
94
  "picocolors": "^1.1.1",
95
- "@mokup/cli": "1.0.7",
96
- "@mokup/playground": "0.0.12",
97
- "@mokup/runtime": "1.0.3",
98
- "@mokup/server": "1.1.4",
99
- "@mokup/shared": "1.0.2"
95
+ "@mokup/cli": "1.0.8",
96
+ "@mokup/playground": "0.0.13",
97
+ "@mokup/runtime": "1.0.4",
98
+ "@mokup/server": "1.1.5",
99
+ "@mokup/shared": "1.1.0"
100
100
  },
101
101
  "devDependencies": {
102
102
  "@types/node": "^25.0.10",