olova 2.0.61 → 2.0.63

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.
Files changed (80) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +42 -61
  3. package/dist/compiler.d.ts +44 -0
  4. package/dist/compiler.js +2139 -0
  5. package/dist/compiler.js.map +1 -0
  6. package/dist/core.d.ts +4 -0
  7. package/dist/core.js +859 -0
  8. package/dist/core.js.map +1 -0
  9. package/dist/global.d.ts +15 -0
  10. package/dist/global.js +226 -0
  11. package/dist/global.js.map +1 -0
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.js +2302 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/runtime.d.ts +89 -0
  16. package/dist/runtime.js +633 -0
  17. package/dist/runtime.js.map +1 -0
  18. package/dist/signals-core-BdfWh1Yt.d.ts +43 -0
  19. package/dist/vite.d.ts +5 -0
  20. package/dist/vite.js +2302 -0
  21. package/dist/vite.js.map +1 -0
  22. package/package.json +83 -65
  23. package/dist/chunk-D7SIC5TC.js +0 -367
  24. package/dist/chunk-D7SIC5TC.js.map +0 -1
  25. package/dist/entry-server.cjs +0 -120
  26. package/dist/entry-server.cjs.map +0 -1
  27. package/dist/entry-server.js +0 -115
  28. package/dist/entry-server.js.map +0 -1
  29. package/dist/entry-worker.cjs +0 -133
  30. package/dist/entry-worker.cjs.map +0 -1
  31. package/dist/entry-worker.js +0 -127
  32. package/dist/entry-worker.js.map +0 -1
  33. package/dist/main.cjs +0 -18
  34. package/dist/main.cjs.map +0 -1
  35. package/dist/main.js +0 -16
  36. package/dist/main.js.map +0 -1
  37. package/dist/olova.cjs +0 -1680
  38. package/dist/olova.cjs.map +0 -1
  39. package/dist/olova.d.cts +0 -72
  40. package/dist/olova.d.ts +0 -72
  41. package/dist/olova.js +0 -1321
  42. package/dist/olova.js.map +0 -1
  43. package/dist/performance.cjs +0 -386
  44. package/dist/performance.cjs.map +0 -1
  45. package/dist/performance.js +0 -3
  46. package/dist/performance.js.map +0 -1
  47. package/dist/router.cjs +0 -646
  48. package/dist/router.cjs.map +0 -1
  49. package/dist/router.d.cts +0 -113
  50. package/dist/router.d.ts +0 -113
  51. package/dist/router.js +0 -632
  52. package/dist/router.js.map +0 -1
  53. package/main.tsx +0 -76
  54. package/olova.ts +0 -619
  55. package/src/entry-server.tsx +0 -165
  56. package/src/entry-worker.tsx +0 -201
  57. package/src/generator/index.ts +0 -409
  58. package/src/hydration/flight.ts +0 -320
  59. package/src/hydration/index.ts +0 -12
  60. package/src/hydration/types.ts +0 -225
  61. package/src/logger.ts +0 -182
  62. package/src/main.tsx +0 -24
  63. package/src/performance.ts +0 -488
  64. package/src/plugin/index.ts +0 -204
  65. package/src/router/ErrorBoundary.tsx +0 -145
  66. package/src/router/Link.tsx +0 -117
  67. package/src/router/OlovaRouter.tsx +0 -354
  68. package/src/router/Outlet.tsx +0 -8
  69. package/src/router/context.ts +0 -117
  70. package/src/router/index.ts +0 -29
  71. package/src/router/matching.ts +0 -63
  72. package/src/router/router.tsx +0 -23
  73. package/src/router/search-params.ts +0 -29
  74. package/src/scanner/index.ts +0 -114
  75. package/src/types/index.ts +0 -190
  76. package/src/utils/export.ts +0 -85
  77. package/src/utils/index.ts +0 -4
  78. package/src/utils/naming.ts +0 -54
  79. package/src/utils/path.ts +0 -45
  80. package/tsup.config.ts +0 -35
package/dist/olova.cjs DELETED
@@ -1,1680 +0,0 @@
1
- 'use strict';
2
-
3
- var fs3 = require('fs');
4
- var fs4 = require('fs/promises');
5
- var path5 = require('path');
6
- var url = require('url');
7
- var mdx = require('@mdx-js/rollup');
8
- var vite = require('vite');
9
- var pc = require('picocolors');
10
- var util = require('util');
11
- var zlib = require('zlib');
12
-
13
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
14
-
15
- var fs3__default = /*#__PURE__*/_interopDefault(fs3);
16
- var fs4__default = /*#__PURE__*/_interopDefault(fs4);
17
- var path5__default = /*#__PURE__*/_interopDefault(path5);
18
- var mdx__default = /*#__PURE__*/_interopDefault(mdx);
19
- var pc__default = /*#__PURE__*/_interopDefault(pc);
20
- var zlib__default = /*#__PURE__*/_interopDefault(zlib);
21
-
22
- // node_modules/tsup/assets/cjs_shims.js
23
- var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
24
- var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
25
- function extractBalancedBraces(content, startIndex) {
26
- if (content[startIndex] !== "{") return null;
27
- let depth = 0;
28
- for (let i = startIndex; i < content.length; i++) {
29
- if (content[i] === "{") depth++;
30
- else if (content[i] === "}") {
31
- depth--;
32
- if (depth === 0) return content.substring(startIndex, i + 1);
33
- }
34
- }
35
- return null;
36
- }
37
- function extractMetadataSource(content) {
38
- const match = content.match(/export\s+(?:const|let|var)\s+metadata\s*(?::\s*\w+\s*)?=\s*/);
39
- if (!match || match.index === void 0) return void 0;
40
- const afterEquals = match.index + match[0].length;
41
- return extractBalancedBraces(content, afterEquals) || void 0;
42
- }
43
- function detectExportType(filePath) {
44
- try {
45
- const content = fs3__default.default.readFileSync(filePath, "utf-8");
46
- const hasMetadata = /export\s+(?:const|let|var)\s+metadata\s*/.test(content) || /export\s*\{\s*metadata\s*\}/.test(content);
47
- const hasRoute = /export\s+(?:const|let|var)\s+route\s*=/.test(content) || /export\s*\{\s*route\s*\}/.test(content);
48
- const hasGetStaticPaths = /export\s+(?:async\s+)?function\s+getStaticPaths/.test(content) || /export\s+(?:const|let|var)\s+getStaticPaths\s*=/.test(content) || /export\s*\{[^}]*getStaticPaths[^}]*\}/.test(content);
49
- const hasLoader = /export\s+(?:async\s+)?function\s+loader/.test(content) || /export\s+(?:const|let|var)\s+loader\s*=/.test(content) || /export\s*\{[^}]*loader[^}]*\}/.test(content);
50
- const metadataSource = extractMetadataSource(content);
51
- if (filePath.toLowerCase().endsWith(".mdx")) {
52
- return {
53
- hasDefault: true,
54
- namedExport: null,
55
- hasMetadata: !!metadataSource,
56
- hasRoute: false,
57
- hasGetStaticPaths: false,
58
- hasLoader: false,
59
- metadataSource
60
- };
61
- }
62
- if (/export\s+default\s+/.test(content)) {
63
- return { hasDefault: true, namedExport: null, hasMetadata, metadataSource, hasRoute, hasGetStaticPaths, hasLoader };
64
- }
65
- const namedMatch = content.match(/export\s+(?:const|function|class)\s+(\w+)/);
66
- if (namedMatch) {
67
- return { hasDefault: false, namedExport: namedMatch[1], hasMetadata, metadataSource, hasRoute, hasGetStaticPaths, hasLoader };
68
- }
69
- const exportMatch = content.match(/export\s*\{\s*(\w+)(?:\s+as\s+default)?\s*\}/);
70
- if (exportMatch) {
71
- if (content.includes("as default")) {
72
- return { hasDefault: true, namedExport: null, hasMetadata, metadataSource, hasRoute, hasGetStaticPaths, hasLoader };
73
- }
74
- return { hasDefault: false, namedExport: exportMatch[1], hasMetadata, metadataSource, hasRoute, hasGetStaticPaths, hasLoader };
75
- }
76
- return { hasDefault: false, namedExport: null, hasMetadata, metadataSource, hasRoute, hasGetStaticPaths, hasLoader };
77
- } catch {
78
- return { hasDefault: true, namedExport: null, hasMetadata: false, hasRoute: false, hasGetStaticPaths: false, hasLoader: false };
79
- }
80
- }
81
-
82
- // src/utils/naming.ts
83
- function getRouteName(path6) {
84
- if (path6 === "/" || path6 === "") return "Root";
85
- const segments = path6.replace(/^\/|\/$/g, "").split(/[\\/]/);
86
- const nameSegments = segments.map((segment) => {
87
- let cleanSegment = segment;
88
- if (cleanSegment.startsWith(":")) {
89
- cleanSegment = cleanSegment.slice(1);
90
- }
91
- if (cleanSegment.startsWith("[") && cleanSegment.endsWith("]")) {
92
- cleanSegment = cleanSegment.slice(1, -1);
93
- if (cleanSegment.startsWith("...")) {
94
- cleanSegment = cleanSegment.slice(3);
95
- }
96
- }
97
- if (cleanSegment === "*") {
98
- return "All";
99
- }
100
- if (cleanSegment.toLowerCase() === "index") {
101
- return "";
102
- }
103
- if (cleanSegment.startsWith("(") && cleanSegment.endsWith(")")) {
104
- cleanSegment = cleanSegment.slice(1, -1);
105
- }
106
- return capitalize(cleanSegment);
107
- });
108
- const finalName = nameSegments.join("");
109
- if (/^\d/.test(finalName)) {
110
- return "Page" + finalName;
111
- }
112
- return finalName;
113
- }
114
- function capitalize(str) {
115
- return str.charAt(0).toUpperCase() + str.slice(1).replace(/[^a-zA-Z0-9]/g, "");
116
- }
117
-
118
- // src/utils/path.ts
119
- function parseDynamicSegment(segment) {
120
- if (segment.match(/^\[\.\.\.(.+)\]$/)) {
121
- const paramName = segment.match(/^\[\.\.\.(.+)\]$/)?.[1] || "slug";
122
- return { isDynamic: true, paramName, isCatchAll: true };
123
- }
124
- const bracketMatch = segment.match(/^\[(.+)\]$/);
125
- if (bracketMatch) {
126
- return { isDynamic: true, paramName: bracketMatch[1], isCatchAll: false };
127
- }
128
- return { isDynamic: false, paramName: null, isCatchAll: false };
129
- }
130
- function isRouteGroup(segment) {
131
- return /^\(.+\)$/.test(segment);
132
- }
133
- function pathToRoute(relativePath, sep) {
134
- const params = [];
135
- let hasCatchAll = false;
136
- const segments = relativePath.split(sep).filter(Boolean);
137
- const routeSegments = segments.filter((segment) => !isRouteGroup(segment)).map((segment) => {
138
- const { isDynamic, paramName, isCatchAll } = parseDynamicSegment(segment);
139
- if (isDynamic && paramName) {
140
- params.push(paramName);
141
- if (isCatchAll) {
142
- hasCatchAll = true;
143
- return `*`;
144
- }
145
- return `:${paramName}`;
146
- }
147
- return segment;
148
- });
149
- const routePath = "/" + routeSegments.join("/");
150
- return { routePath: routePath === "/" ? "/" : routePath, params, hasCatchAll };
151
- }
152
-
153
- // src/generator/index.ts
154
- function stripImportExtension(filePath) {
155
- return filePath.replace(/\.tsx?$/, "");
156
- }
157
- function pathToRouteId(routePath) {
158
- if (routePath === "/") return "_root";
159
- return routePath.replace(/^\//, "").replace(/\//g, "_").replace(/:/g, "$").replace(/\*/g, "$catchall");
160
- }
161
- function extractParamNames(routePath) {
162
- const params = [];
163
- for (const segment of routePath.split("/")) {
164
- if (segment.startsWith(":")) params.push(segment.slice(1));
165
- else if (segment === "*") params.push("*");
166
- }
167
- return params;
168
- }
169
- function generateParamType(routePath) {
170
- const params = extractParamNames(routePath);
171
- if (params.length === 0) return null;
172
- const fields = params.map(
173
- (p) => p === "*" ? "'*': string" : `${p}: string`
174
- );
175
- return `{ ${fields.join("; ")} }`;
176
- }
177
- function generateRouteTree(routes, notFoundPages, layouts, loadingPages, errorPages, middlewares, srcDir, packageName = "olovastart") {
178
- const usedNames = /* @__PURE__ */ new Map();
179
- const getUniqueName = (baseName) => {
180
- const count = usedNames.get(baseName) || 0;
181
- usedNames.set(baseName, count + 1);
182
- return count === 0 ? baseName : `${baseName}${count}`;
183
- };
184
- const getRouteName2 = (filePath, suffix = "") => {
185
- const relPath = path5__default.default.relative(srcDir, filePath);
186
- const pathNoExt = relPath.replace(/\.(tsx?|mdx)$/, "");
187
- if (pathNoExt === "" || pathNoExt === "." || pathNoExt === "index") {
188
- return getUniqueName("Root" + suffix);
189
- }
190
- const name = getRouteName(pathNoExt);
191
- if (!name) return getUniqueName("Root" + suffix);
192
- if (suffix && name.toLowerCase().endsWith(suffix.toLowerCase())) {
193
- return getUniqueName(name);
194
- }
195
- return getUniqueName(name + suffix);
196
- };
197
- const findClosestEntry = (routePath, entries) => {
198
- let best = null;
199
- for (const entry of entries) {
200
- const ep = entry.path;
201
- if (ep === "/" || routePath === ep || routePath.startsWith(ep + "/")) {
202
- if (!best || ep.length > best.path.length) best = entry;
203
- }
204
- }
205
- return best;
206
- };
207
- const routeNames = [];
208
- const routeImports = routes.map((route) => {
209
- const relativePath = stripImportExtension("./app/" + path5__default.default.relative(srcDir, route.component).replace(/\\/g, "/"));
210
- const moduleName = getRouteName2(route.component, "RouteModule");
211
- const lazyName = getRouteName2(route.component, "Route");
212
- routeNames.push({ moduleName, lazyName, eager: true });
213
- return `import * as ${moduleName} from '${relativePath}';`;
214
- }).join("\n");
215
- const notFoundNames = [];
216
- const notFoundImports = notFoundPages.map((nf) => {
217
- const relativePath = stripImportExtension("./app/" + path5__default.default.relative(srcDir, nf.filePath).replace(/\\/g, "/"));
218
- if (nf.hasMetadata) {
219
- const moduleName = getRouteName2(nf.filePath, "NotFoundModule");
220
- notFoundNames.push(moduleName);
221
- return `import * as ${moduleName} from '${relativePath}';`;
222
- }
223
- const importName = getRouteName2(nf.filePath, "NotFound");
224
- notFoundNames.push(importName);
225
- if (nf.hasDefault) return `import ${importName} from '${relativePath}';`;
226
- if (nf.namedExport) return `import { ${nf.namedExport} as ${importName} } from '${relativePath}';`;
227
- return `import ${importName} from '${relativePath}';`;
228
- }).join("\n");
229
- const layoutNames = [];
230
- const layoutImports = layouts.map((layout) => {
231
- const relativePath = stripImportExtension("./app/" + path5__default.default.relative(srcDir, layout.filePath).replace(/\\/g, "/"));
232
- if (layout.hasMetadata) {
233
- const moduleName = getRouteName2(layout.filePath, "LayoutModule");
234
- layoutNames.push(moduleName);
235
- return `import * as ${moduleName} from '${relativePath}';`;
236
- }
237
- const importName = getRouteName2(layout.filePath, "Layout");
238
- layoutNames.push(importName);
239
- if (layout.hasDefault) return `import ${importName} from '${relativePath}';`;
240
- if (layout.namedExport) return `import { ${layout.namedExport} as ${importName} } from '${relativePath}';`;
241
- return `import ${importName} from '${relativePath}';`;
242
- }).join("\n");
243
- const loadingNames = [];
244
- const loadingImports = loadingPages.map((lp) => {
245
- const relativePath = stripImportExtension("./app/" + path5__default.default.relative(srcDir, lp.filePath).replace(/\\/g, "/"));
246
- const importName = getRouteName2(lp.filePath, "Loading");
247
- loadingNames.push(importName);
248
- if (lp.hasDefault) return `import ${importName} from '${relativePath}';`;
249
- if (lp.namedExport) return `import { ${lp.namedExport} as ${importName} } from '${relativePath}';`;
250
- return `import ${importName} from '${relativePath}';`;
251
- }).join("\n");
252
- const errorNames = [];
253
- const errorImports = errorPages.map((ep) => {
254
- const relativePath = stripImportExtension("./app/" + path5__default.default.relative(srcDir, ep.filePath).replace(/\\/g, "/"));
255
- const importName = getRouteName2(ep.filePath, "Error");
256
- errorNames.push(importName);
257
- if (ep.hasDefault) return `import ${importName} from '${relativePath}';`;
258
- if (ep.namedExport) return `import { ${ep.namedExport} as ${importName} } from '${relativePath}';`;
259
- return `import ${importName} from '${relativePath}';`;
260
- }).join("\n");
261
- const middlewareNames = [];
262
- const middlewareImports = middlewares.map((mw) => {
263
- const relativePath = stripImportExtension("./app/" + path5__default.default.relative(srcDir, mw.filePath).replace(/\\/g, "/"));
264
- const importName = getRouteName2(mw.filePath, "Middleware");
265
- middlewareNames.push(importName);
266
- if (mw.hasDefault) return `import ${importName} from '${relativePath}';`;
267
- if (mw.namedExport) return `import { ${mw.namedExport} as ${importName} } from '${relativePath}';`;
268
- return `import ${importName} from '${relativePath}';`;
269
- }).join("\n");
270
- const routeObjects = routes.map((route, index) => {
271
- const { moduleName, lazyName, eager } = routeNames[index];
272
- const component = eager ? `${moduleName}.default` : lazyName;
273
- const routeId = pathToRouteId(route.path);
274
- const fields = [
275
- `id: '${routeId}'`,
276
- `path: '${route.path}'`,
277
- `component: ${component}`
278
- ];
279
- if (route.params && route.params.length > 0) {
280
- fields.push(`params: [${route.params.map((p) => `'${p}'`).join(", ")}]`);
281
- }
282
- if (route.metadataSource) {
283
- fields.push(`metadata: ${route.metadataSource}`);
284
- } else if (route.hasMetadata) {
285
- fields.push(`metadata: ${moduleName}.metadata`);
286
- }
287
- if (route.hasGetStaticPaths) {
288
- fields.push(`getStaticPaths: ${moduleName}.getStaticPaths`);
289
- }
290
- if (route.hasLoader) {
291
- fields.push(`loader: ${moduleName}.loader`);
292
- }
293
- const closestLoading = findClosestEntry(route.path, loadingPages);
294
- if (closestLoading) {
295
- const idx = loadingPages.indexOf(closestLoading);
296
- fields.push(`loading: ${loadingNames[idx]}`);
297
- }
298
- const closestError = findClosestEntry(route.path, errorPages);
299
- if (closestError) {
300
- const idx = errorPages.indexOf(closestError);
301
- fields.push(`error: ${errorNames[idx]}`);
302
- }
303
- return ` {
304
- ${fields.join(",\n ")}
305
- }`;
306
- }).join(",\n");
307
- const notFoundObjects = notFoundPages.map((nf, index) => {
308
- const name = notFoundNames[index];
309
- const isModule = nf.hasMetadata;
310
- const component = isModule ? `${name}.default` : name;
311
- const fields = [
312
- `pathPrefix: '${nf.pathPrefix}'`,
313
- `component: ${component}`
314
- ];
315
- if (isModule) fields.push(`metadata: ${name}.metadata`);
316
- return ` {
317
- ${fields.join(",\n ")}
318
- }`;
319
- }).join(",\n");
320
- const layoutObjects = layouts.map((layout, index) => {
321
- const name = layoutNames[index];
322
- const isModule = layout.hasMetadata;
323
- const component = isModule ? `${name}.default` : name;
324
- const childRouteIds = routes.filter((r) => {
325
- if (layout.path === "/") return true;
326
- return r.path === layout.path || r.path.startsWith(layout.path + "/");
327
- }).map((r) => `'${pathToRouteId(r.path)}'`);
328
- const fields = [
329
- `path: '${layout.path}'`,
330
- `layout: ${component}`,
331
- `children: [${childRouteIds.join(", ")}]`
332
- ];
333
- if (isModule) fields.push(`metadata: ${name}.metadata`);
334
- return ` {
335
- ${fields.join(",\n ")}
336
- }`;
337
- }).join(",\n");
338
- const middlewareEntries = middlewares.map((mw, index) => {
339
- return ` '${mw.path}': ${middlewareNames[index]}`;
340
- }).join(",\n");
341
- const routeParamTypes = routes.filter((r) => r.params && r.params.length > 0).map((r) => {
342
- const paramType = generateParamType(r.path);
343
- return paramType ? ` '${r.path}': ${paramType};` : null;
344
- }).filter(Boolean).join("\n");
345
- const routePaths = routes.length > 0 ? routes.map((r) => `'${r.path}'`).join(" | ") : "never";
346
- const routeIds = routes.length > 0 ? routes.map((r) => `'${pathToRouteId(r.path)}'`).join(" | ") : "never";
347
- const manifestEntries = routes.map((r) => {
348
- const paramNames = extractParamNames(r.path);
349
- const isDynamic = paramNames.length > 0;
350
- const hasCatchAll = r.path.includes("*");
351
- return ` '${pathToRouteId(r.path)}': { id: '${pathToRouteId(r.path)}', path: '${r.path}', params: [${paramNames.map((p) => `'${p}'`).join(", ")}], isDynamic: ${isDynamic}, hasCatchAll: ${hasCatchAll}, hasMetadata: ${r.hasMetadata}, hasGetStaticPaths: ${r.hasGetStaticPaths} }`;
352
- }).join(",\n");
353
- const allImports = [
354
- routeImports,
355
- notFoundImports,
356
- layoutImports,
357
- loadingImports,
358
- errorImports,
359
- middlewareImports
360
- ].filter(Boolean).join("\n");
361
- return `/* prettier-ignore-start */
362
-
363
- /* eslint-disable */
364
-
365
- // @ts-nocheck
366
-
367
- // noinspection JSUnusedGlobalSymbols
368
-
369
- /**
370
- * This file was automatically generated by Olova Router.
371
- * DO NOT MODIFY IT BY HAND. Instead, modify the source route files
372
- * and regenerate this file by running the dev server or build command.
373
- *
374
- * @generated Olova Route Tree
375
- * @routes ${routes.length}
376
- * @layouts ${layouts.length}
377
- * @404s ${notFoundPages.length}
378
- * @loading ${loadingPages.length}
379
- * @errors ${errorPages.length}
380
- * @middleware ${middlewares.length}
381
- */
382
-
383
- import { lazy } from 'react';
384
- import {
385
- createLink,
386
- OlovaRouter,
387
- Outlet,
388
- redirect,
389
- useIsNavigating,
390
- useNavigationEvent,
391
- useParams,
392
- usePathname,
393
- useRedirect,
394
- useRouter,
395
- useSearchParams,
396
- useSelectedLayoutSegment,
397
- useSelectedLayoutSegments,
398
- } from '${packageName}/router';
399
- ${allImports}
400
-
401
- /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
402
- * Route Definitions
403
- * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
404
-
405
- export const routes = [
406
- ${routeObjects}
407
- ];
408
-
409
- export const notFoundPages = [
410
- ${notFoundObjects}
411
- ];
412
-
413
- export const layouts = [
414
- ${layoutObjects}
415
- ];
416
- ${middlewares.length > 0 ? `
417
- export const middlewares = {
418
- ${middlewareEntries}
419
- };
420
- ` : `
421
- export const middlewares = {};
422
- `}
423
- /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
424
- * Route Manifest (build-time introspection, sitemap generation, etc.)
425
- * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
426
-
427
- export const routeManifest = {
428
- ${manifestEntries}
429
- } as const;
430
-
431
- /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
432
- * Type-Safe Route Types
433
- * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
434
-
435
- export type RoutePaths = ${routePaths};
436
-
437
- export type RouteIds = ${routeIds};
438
-
439
- export interface RouteParams {
440
- ${routeParamTypes || " // No dynamic routes"}
441
- }
442
-
443
- export type ParamsFor<P extends RoutePaths> = P extends keyof RouteParams ? RouteParams[P] : Record<string, never>;
444
-
445
- /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
446
- * Route Lookup Helpers
447
- * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
448
-
449
- const _routeById = new Map(routes.map(r => [r.id, r]));
450
-
451
- export function getRouteById(id: RouteIds) {
452
- return _routeById.get(id);
453
- }
454
-
455
- export function getRouteByPath(path: RoutePaths) {
456
- return routes.find(r => r.path === path);
457
- }
458
-
459
- /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
460
- * Exports
461
- * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
462
-
463
- export const Link = createLink<RoutePaths>();
464
-
465
- export {
466
- OlovaRouter,
467
- Outlet,
468
- redirect,
469
- useIsNavigating,
470
- useNavigationEvent,
471
- useParams,
472
- usePathname,
473
- useRedirect,
474
- useRouter,
475
- useSearchParams,
476
- useSelectedLayoutSegment,
477
- useSelectedLayoutSegments,
478
- };
479
-
480
- export type {
481
- NavigateOptions,
482
- NotFoundPageConfig,
483
- SearchParams,
484
- SetSearchParamsOptions,
485
- LayoutRoute,
486
- Metadata,
487
- } from '${packageName}/router';
488
-
489
- /* prettier-ignore-end */
490
- `;
491
- }
492
- var RESERVED_NAMES = /* @__PURE__ */ new Set([
493
- "page",
494
- "layout",
495
- "loading",
496
- "error",
497
- "not-found",
498
- "middleware",
499
- "route.tree"
500
- ]);
501
- function scanDirectory(dir, rootDir, extensions, routes, notFoundPages, layouts, loadingPages, errorPages, middlewares, isRoot = false) {
502
- if (!fs3__default.default.existsSync(dir)) return;
503
- const entries = fs3__default.default.readdirSync(dir, { withFileTypes: true });
504
- for (const entry of entries) {
505
- const fullPath = path5__default.default.join(dir, entry.name);
506
- if (entry.isDirectory()) {
507
- if (entry.name === "node_modules" || entry.name === "assets" || entry.name.startsWith("_")) continue;
508
- scanDirectory(fullPath, rootDir, extensions, routes, notFoundPages, layouts, loadingPages, errorPages, middlewares, false);
509
- } else if (entry.isFile()) {
510
- const ext = path5__default.default.extname(entry.name);
511
- const baseName = path5__default.default.basename(entry.name, ext);
512
- if (baseName === "layout" && extensions.includes(ext)) {
513
- const relativePath = path5__default.default.relative(rootDir, dir);
514
- const { routePath } = pathToRoute(relativePath, path5__default.default.sep);
515
- layouts.push({
516
- path: isRoot ? "/" : routePath,
517
- filePath: fullPath
518
- });
519
- } else if (baseName === "loading" && extensions.includes(ext)) {
520
- const relativePath = path5__default.default.relative(rootDir, dir);
521
- const { routePath } = pathToRoute(relativePath, path5__default.default.sep);
522
- loadingPages.push({
523
- path: isRoot ? "/" : routePath,
524
- filePath: fullPath
525
- });
526
- } else if (baseName === "error" && extensions.includes(ext)) {
527
- const relativePath = path5__default.default.relative(rootDir, dir);
528
- const { routePath } = pathToRoute(relativePath, path5__default.default.sep);
529
- errorPages.push({
530
- path: isRoot ? "/" : routePath,
531
- filePath: fullPath
532
- });
533
- } else if (baseName === "middleware" && extensions.includes(ext)) {
534
- const relativePath = path5__default.default.relative(rootDir, dir);
535
- const { routePath } = pathToRoute(relativePath, path5__default.default.sep);
536
- middlewares.push({
537
- path: isRoot ? "/" : routePath,
538
- filePath: fullPath
539
- });
540
- } else if ((baseName === "not-found" || baseName === "404") && extensions.includes(ext)) {
541
- const relativeParts = path5__default.default.relative(rootDir, dir).split(path5__default.default.sep).filter(Boolean);
542
- const filteredParts = relativeParts.filter((p) => !isRouteGroup(p));
543
- const pathPrefix = isRoot ? "" : "/" + filteredParts.join("/");
544
- notFoundPages.push({ pathPrefix: pathPrefix || "", filePath: fullPath });
545
- } else if (baseName === "page" && extensions.includes(ext)) {
546
- const relativePath = path5__default.default.relative(rootDir, dir);
547
- const { routePath, params } = pathToRoute(relativePath, path5__default.default.sep);
548
- routes.push({ path: routePath, filePath: fullPath, isDynamic: params.length > 0, params });
549
- } else if (!RESERVED_NAMES.has(baseName) && !baseName.endsWith(".d") && !baseName.startsWith("_") && extensions.includes(ext)) {
550
- const relativePath = path5__default.default.relative(rootDir, fullPath);
551
- const relativePathNoExt = relativePath.substring(0, relativePath.length - ext.length);
552
- const { routePath, params } = pathToRoute(relativePathNoExt, path5__default.default.sep);
553
- routes.push({ path: routePath, filePath: fullPath, isDynamic: params.length > 0, params });
554
- }
555
- }
556
- }
557
- }
558
- function scanRoutes(rootDir, extensions) {
559
- const routes = [];
560
- const notFoundPages = [];
561
- const layouts = [];
562
- const loadingPages = [];
563
- const errorPages = [];
564
- const middlewares = [];
565
- const absoluteRoot = path5__default.default.isAbsolute(rootDir) ? rootDir : path5__default.default.resolve(rootDir);
566
- if (!fs3__default.default.existsSync(absoluteRoot)) {
567
- throw new Error(`Olova Router: Root directory does not exist: ${absoluteRoot}`);
568
- }
569
- scanDirectory(absoluteRoot, absoluteRoot, extensions, routes, notFoundPages, layouts, loadingPages, errorPages, middlewares, true);
570
- routes.sort((a, b) => a.isDynamic !== b.isDynamic ? a.isDynamic ? 1 : -1 : a.path.localeCompare(b.path));
571
- notFoundPages.sort((a, b) => b.pathPrefix.length - a.pathPrefix.length);
572
- layouts.sort((a, b) => a.path.length - b.path.length);
573
- loadingPages.sort((a, b) => b.path.length - a.path.length);
574
- errorPages.sort((a, b) => b.path.length - a.path.length);
575
- middlewares.sort((a, b) => a.path.length - b.path.length);
576
- return { routes, notFoundPages, layouts, loadingPages, errorPages, middlewares };
577
- }
578
-
579
- // src/plugin/index.ts
580
- function olovaRouter(options = {}) {
581
- const rootDir = options.rootDir || "src/app";
582
- const extensions = options.extensions || [".tsx", ".ts", ".mdx"];
583
- const packageName = options.packageName || "olovastart";
584
- let config;
585
- let absoluteRootDir;
586
- let watcher = null;
587
- let timer = null;
588
- function generateRouteTreeFile() {
589
- const { routes, notFoundPages, layouts, loadingPages, errorPages, middlewares } = scanRoutes(absoluteRootDir, extensions);
590
- const routeConfigs = routes.map((r) => {
591
- let exportInfo = detectExportType(r.filePath);
592
- if (r.filePath.toLowerCase().endsWith(".mdx")) {
593
- exportInfo = {
594
- ...exportInfo,
595
- hasDefault: true,
596
- namedExport: null
597
- };
598
- }
599
- return {
600
- path: r.path,
601
- component: r.filePath.replace(/\\/g, "/"),
602
- params: r.params.length > 0 ? r.params : void 0,
603
- hasDefault: exportInfo.hasDefault,
604
- namedExport: exportInfo.namedExport,
605
- hasMetadata: exportInfo.hasMetadata,
606
- metadataSource: exportInfo.metadataSource,
607
- hasRoute: exportInfo.hasRoute,
608
- hasGetStaticPaths: exportInfo.hasGetStaticPaths,
609
- hasLoader: exportInfo.hasLoader
610
- };
611
- });
612
- const notFoundConfigs = notFoundPages.map((nf) => {
613
- const exportInfo = detectExportType(nf.filePath);
614
- return {
615
- pathPrefix: nf.pathPrefix,
616
- filePath: nf.filePath.replace(/\\/g, "/"),
617
- hasDefault: exportInfo.hasDefault,
618
- namedExport: exportInfo.namedExport,
619
- hasMetadata: exportInfo.hasMetadata
620
- };
621
- });
622
- const layoutConfigs = layouts.map((l) => {
623
- const exportInfo = detectExportType(l.filePath);
624
- return {
625
- path: l.path,
626
- filePath: l.filePath.replace(/\\/g, "/"),
627
- hasDefault: exportInfo.hasDefault,
628
- namedExport: exportInfo.namedExport,
629
- hasMetadata: exportInfo.hasMetadata
630
- };
631
- });
632
- const loadingConfigs = loadingPages.map((lp) => {
633
- const exportInfo = detectExportType(lp.filePath);
634
- return {
635
- path: lp.path,
636
- filePath: lp.filePath.replace(/\\/g, "/"),
637
- hasDefault: exportInfo.hasDefault,
638
- namedExport: exportInfo.namedExport
639
- };
640
- });
641
- const errorConfigs = errorPages.map((ep) => {
642
- const exportInfo = detectExportType(ep.filePath);
643
- return {
644
- path: ep.path,
645
- filePath: ep.filePath.replace(/\\/g, "/"),
646
- hasDefault: exportInfo.hasDefault,
647
- namedExport: exportInfo.namedExport
648
- };
649
- });
650
- const middlewareConfigs = middlewares.map((mw) => {
651
- const exportInfo = detectExportType(mw.filePath);
652
- return {
653
- path: mw.path,
654
- filePath: mw.filePath.replace(/\\/g, "/"),
655
- hasDefault: exportInfo.hasDefault,
656
- namedExport: exportInfo.namedExport
657
- };
658
- });
659
- const content = generateRouteTree(routeConfigs, notFoundConfigs, layoutConfigs, loadingConfigs, errorConfigs, middlewareConfigs, absoluteRootDir, packageName);
660
- const treePath = path5__default.default.resolve(config.root, "src", "route.tree.ts");
661
- const existing = fs3__default.default.existsSync(treePath) ? fs3__default.default.readFileSync(treePath, "utf-8") : "";
662
- if (existing !== content) {
663
- fs3__default.default.writeFileSync(treePath, content);
664
- console.log("\x1B[32m[olova]\x1B[0m Route tree updated");
665
- }
666
- }
667
- function startWatcher() {
668
- if (watcher) return;
669
- watcher = fs3__default.default.watch(absoluteRootDir, { recursive: true }, (eventType, filename) => {
670
- if (!filename) return;
671
- if (filename.includes("route.tree.ts")) return;
672
- const ext = path5__default.default.extname(filename);
673
- const isConfiguredExtension = extensions.includes(ext);
674
- const isPageFile = filename.includes("page") && isConfiguredExtension;
675
- const is404File = filename.includes("404") && isConfiguredExtension;
676
- const isNotFoundFile = filename.includes("not-found") && isConfiguredExtension;
677
- const isLayoutFile = filename.includes("layout") && isConfiguredExtension;
678
- const isLoadingFile = filename.includes("loading") && isConfiguredExtension;
679
- const isErrorFile = filename.includes("error") && isConfiguredExtension;
680
- const isMiddlewareFile = filename.includes("middleware") && isConfiguredExtension;
681
- const isDirectory = !filename.includes(".");
682
- const isDynamicSegment = filename.includes("[");
683
- const isRenameEvent = eventType === "rename";
684
- if (isPageFile || is404File || isNotFoundFile || isLayoutFile || isLoadingFile || isErrorFile || isMiddlewareFile || isDirectory || isDynamicSegment || isRenameEvent) {
685
- if (isPageFile && filename) {
686
- const fullPath = path5__default.default.join(absoluteRootDir, filename);
687
- if (fs3__default.default.existsSync(fullPath)) {
688
- const stat = fs3__default.default.statSync(fullPath);
689
- if (stat.size === 0 && !filename.endsWith(".mdx")) {
690
- const relativeDir = path5__default.default.relative(absoluteRootDir, path5__default.default.dirname(fullPath));
691
- const pascalCaseName = getRouteName(relativeDir);
692
- const boilerplate = `
693
- export const metadata = {
694
- title: "${pascalCaseName}",
695
- description: "${pascalCaseName} page",
696
- }
697
-
698
- export default function ${pascalCaseName}() {
699
- return (
700
- <div>
701
- <h1>${pascalCaseName}</h1>
702
- </div>
703
- );
704
- }
705
- `;
706
- fs3__default.default.writeFileSync(fullPath, boilerplate);
707
- console.log(`\x1B[32m[olova]\x1B[0m Generated boilerplate for ${filename}`);
708
- }
709
- }
710
- }
711
- if (timer) clearTimeout(timer);
712
- timer = setTimeout(() => {
713
- try {
714
- generateRouteTreeFile();
715
- } catch (error2) {
716
- console.error("\x1B[31m[olova]\x1B[0m Error generating route tree:", error2);
717
- }
718
- }, 100);
719
- }
720
- });
721
- console.log("\x1B[32m[olova]\x1B[0m Watching for route changes...");
722
- }
723
- const routerPlugin = {
724
- name: "olova-router",
725
- configResolved(resolvedConfig) {
726
- config = resolvedConfig;
727
- absoluteRootDir = path5__default.default.resolve(config.root, rootDir);
728
- },
729
- buildStart() {
730
- generateRouteTreeFile();
731
- if (config.command === "serve") {
732
- startWatcher();
733
- }
734
- },
735
- buildEnd() {
736
- if (watcher) {
737
- watcher.close();
738
- watcher = null;
739
- }
740
- }
741
- };
742
- return [
743
- { enforce: "pre", ...mdx__default.default() },
744
- routerPlugin
745
- ];
746
- }
747
- var VERSION = "0.0.14";
748
- function printBanner() {
749
- console.log("");
750
- console.log(pc__default.default.cyan(` \u25B2 Olova`) + pc__default.default.dim(` ${VERSION}`));
751
- console.log("");
752
- }
753
- function printDevReady(url, networkUrl) {
754
- console.log("");
755
- console.log(` ${pc__default.default.green("\u2713")} ${pc__default.default.bold("Ready")} in ${pc__default.default.cyan("~1s")}`);
756
- console.log("");
757
- console.log(` ${pc__default.default.dim("Local:")} ${pc__default.default.cyan(url)}`);
758
- if (networkUrl) {
759
- console.log(` ${pc__default.default.dim("Network:")} ${pc__default.default.cyan(networkUrl)}`);
760
- }
761
- console.log("");
762
- }
763
- function printBuildStart() {
764
- console.log("");
765
- console.log(` ${pc__default.default.dim("Creating an optimized production build...")}`);
766
- console.log("");
767
- }
768
- function printSSGStart(buildId) {
769
- console.log("");
770
- console.log(pc__default.default.bold(pc__default.default.cyan(` \u2713 Compiled successfully`)));
771
- console.log("");
772
- console.log(` ${pc__default.default.dim("Build ID:")} ${pc__default.default.yellow(buildId)}`);
773
- console.log("");
774
- }
775
- function printRoutes(routes) {
776
- console.log(` ${pc__default.default.bold("Route")}${" ".repeat(32)}${pc__default.default.bold("Type")}`);
777
- console.log(` ${pc__default.default.dim("\u250C")}${pc__default.default.dim("\u2500".repeat(43))}${pc__default.default.dim("\u2510")}`);
778
- for (const route of routes) {
779
- const icon = route.type === "static" ? pc__default.default.green("\u25CB") : pc__default.default.magenta("\u03BB");
780
- const typeLabel = route.type === "static" ? pc__default.default.green("Static") : pc__default.default.magenta("Dynamic");
781
- const pathDisplay = route.path === "/" ? "/" : route.path;
782
- const padding = " ".repeat(Math.max(1, 35 - pathDisplay.length));
783
- console.log(` ${pc__default.default.dim("\u2502")} ${icon} ${pc__default.default.white(pathDisplay)}${padding}${typeLabel}`);
784
- }
785
- console.log(` ${pc__default.default.dim("\u2514")}${pc__default.default.dim("\u2500".repeat(43))}${pc__default.default.dim("\u2518")}`);
786
- console.log("");
787
- }
788
- function printPageGenerated(path6, hasFlightData = true) {
789
- const badge = hasFlightData ? pc__default.default.dim(pc__default.default.cyan(" [Flight]")) : "";
790
- console.log(` ${pc__default.default.dim("\u2713")} ${pc__default.default.dim("Generated")} ${pc__default.default.white(path6)}${badge}`);
791
- }
792
- function printPageError(path6, error2) {
793
- console.log(` ${pc__default.default.red("\u2717")} ${pc__default.default.red("Failed")} ${path6}`);
794
- console.log(` ${pc__default.default.dim(error2)}`);
795
- }
796
- function printSSGComplete(stats) {
797
- console.log("");
798
- console.log(` ${pc__default.default.dim("\u2500".repeat(45))}`);
799
- console.log("");
800
- if (stats.failedPages > 0) {
801
- console.log(` ${pc__default.default.yellow("\u26A0")} ${pc__default.default.yellow("Build completed with warnings")}`);
802
- } else {
803
- console.log(` ${pc__default.default.green("\u2713")} ${pc__default.default.green("Build completed successfully")}`);
804
- }
805
- console.log("");
806
- console.log(` ${pc__default.default.dim("Pages:")} ${pc__default.default.bold(stats.successPages.toString())} generated`);
807
- if (stats.failedPages > 0) {
808
- console.log(` ${pc__default.default.red(stats.failedPages.toString())} failed`);
809
- }
810
- console.log(` ${pc__default.default.dim("Time:")} ${pc__default.default.cyan(stats.buildTime + "ms")}`);
811
- console.log("");
812
- }
813
- function printFlightInfo() {
814
- console.log(` ${pc__default.default.cyan("\u25CB")} ${pc__default.default.dim("Flight hydration enabled")}`);
815
- console.log(` ${pc__default.default.dim("\u2022 JSON-LD structured data")}`);
816
- console.log(` ${pc__default.default.dim("\u2022 Resource hints")}`);
817
- console.log(` ${pc__default.default.dim("\u2022 $OLOVA global")}`);
818
- console.log("");
819
- }
820
- function info(message) {
821
- console.log(` ${pc__default.default.cyan("\u25CB")} ${message}`);
822
- }
823
- function success(message) {
824
- console.log(` ${pc__default.default.green("\u2713")} ${pc__default.default.green(message)}`);
825
- }
826
- function warn(message) {
827
- console.log(` ${pc__default.default.yellow("\u26A0")} ${pc__default.default.yellow(message)}`);
828
- }
829
- function error(message) {
830
- console.log(` ${pc__default.default.red("\u2717")} ${pc__default.default.red(message)}`);
831
- }
832
- function printSSRRender(path6) {
833
- console.log(` ${pc__default.default.cyan("\u2192")} ${pc__default.default.dim("SSR")} ${path6}`);
834
- }
835
- var logger_default = {
836
- printBanner,
837
- printDevReady,
838
- printBuildStart,
839
- printSSGStart,
840
- printRoutes,
841
- printPageGenerated,
842
- printPageError,
843
- printSSGComplete,
844
- printFlightInfo,
845
- printSSRRender,
846
- info,
847
- success,
848
- warn,
849
- error
850
- };
851
- var gzip = util.promisify(zlib__default.default.gzip);
852
- var brotliCompress = util.promisify(zlib__default.default.brotliCompress);
853
- function createManualChunks() {
854
- const seenModules = /* @__PURE__ */ new Map();
855
- return (id, { getModuleInfo }) => {
856
- if (id.includes("node_modules/react-dom")) {
857
- return "vendor-react-dom";
858
- }
859
- if (id.includes("node_modules/react")) {
860
- return "vendor-react";
861
- }
862
- if (id.includes("olova-router") || id.includes("olovastart/dist/router")) {
863
- return "framework-router";
864
- }
865
- if (id.includes("node_modules")) {
866
- const match = id.match(/node_modules[\\/]([^/\\]+)/);
867
- if (match) {
868
- const pkg = match[1];
869
- if (["scheduler", "object-assign", "prop-types"].includes(pkg)) {
870
- return "vendor-react";
871
- }
872
- if (["lodash", "moment", "axios", "date-fns"].includes(pkg)) {
873
- return `vendor-${pkg}`;
874
- }
875
- }
876
- return "vendor";
877
- }
878
- if (id.includes("/components/")) {
879
- return "common-components";
880
- }
881
- if (id.includes("/utils/") || id.includes("/lib/") || id.includes("/helpers/")) {
882
- return "common-utils";
883
- }
884
- if (id.endsWith(".css") || id.endsWith(".scss")) {
885
- return void 0;
886
- }
887
- if (id.includes("/(auth)/") || id.includes("\\(auth)\\") || id.includes("/search/") || id.includes("\\search\\")) {
888
- return "page-auth";
889
- }
890
- if (id.includes("/src/") && (id.endsWith("/index.tsx") || id.endsWith("/index.mdx"))) {
891
- const moduleInfo = getModuleInfo(id);
892
- if (moduleInfo) {
893
- for (const importer of moduleInfo.importers) {
894
- if (importer.includes("/src/") && importer.includes("/index.") && !importer.includes(id)) {
895
- return "common-routes";
896
- }
897
- }
898
- }
899
- const routeMatch = id.match(/[\\/]src[\\/](.+?)[\\/]index\.(tsx|mdx)$/);
900
- if (routeMatch) {
901
- const routePath = routeMatch[1].replace(/\([^)]+\)[\\/]/g, "").replace(/\[.*?\]/g, "dynamic").replace(/[\\/]/g, "-");
902
- const baseRoute = routePath.split("-")[0];
903
- if (seenModules.has(baseRoute)) {
904
- const existingChunk = seenModules.get(baseRoute);
905
- if (existingChunk.startsWith("page-")) {
906
- return existingChunk;
907
- }
908
- }
909
- const chunkName = `page-${routePath}`;
910
- seenModules.set(baseRoute, chunkName);
911
- return chunkName;
912
- }
913
- }
914
- return void 0;
915
- };
916
- }
917
- function compressionPlugin(options = {}) {
918
- const {
919
- gzip: enableGzip = true,
920
- brotli: enableBrotli = true,
921
- threshold = 1024,
922
- extensions = ["js", "css", "html", "json", "svg", "xml"]
923
- } = options;
924
- let config;
925
- return {
926
- name: "olova-compression",
927
- apply: "build",
928
- configResolved(resolvedConfig) {
929
- config = resolvedConfig;
930
- },
931
- async closeBundle() {
932
- if (config.command !== "build" || config.build.ssr) return;
933
- const outDir = config.build.outDir;
934
- const stats = { gzip: 0, brotli: 0, skipped: 0 };
935
- const files = await findFilesToCompress(outDir, extensions);
936
- for (const file of files) {
937
- const content = await fs4__default.default.readFile(file);
938
- if (content.length < threshold) {
939
- stats.skipped++;
940
- continue;
941
- }
942
- if (enableGzip) {
943
- try {
944
- const compressed = await gzip(content, { level: 9 });
945
- await fs4__default.default.writeFile(`${file}.gz`, compressed);
946
- stats.gzip++;
947
- } catch (e) {
948
- }
949
- }
950
- if (enableBrotli) {
951
- try {
952
- const compressed = await brotliCompress(content, {
953
- params: {
954
- [zlib__default.default.constants.BROTLI_PARAM_QUALITY]: 11
955
- }
956
- });
957
- await fs4__default.default.writeFile(`${file}.br`, compressed);
958
- stats.brotli++;
959
- } catch (e) {
960
- }
961
- }
962
- }
963
- if (stats.gzip > 0 || stats.brotli > 0) {
964
- logger_default.info(`Compressed ${stats.gzip} files (gzip), ${stats.brotli} files (brotli)`);
965
- }
966
- }
967
- };
968
- }
969
- function chunkAnalysisPlugin(options = {}) {
970
- const {
971
- chunkSizeWarning = true,
972
- maxChunkSize = 250
973
- } = options;
974
- const chunks = [];
975
- return {
976
- name: "olova-chunk-analysis",
977
- apply: "build",
978
- generateBundle(_options, bundle) {
979
- for (const [fileName, chunk] of Object.entries(bundle)) {
980
- if (chunk.type === "chunk") {
981
- const sizeKB = Buffer.byteLength(chunk.code, "utf8") / 1024;
982
- let type = "other";
983
- if (fileName.includes("vendor")) type = "vendor";
984
- else if (fileName.includes("framework")) type = "framework";
985
- else if (fileName.includes("common")) type = "common";
986
- else if (fileName.includes("page-")) type = "route";
987
- chunks.push({
988
- name: fileName,
989
- size: Math.round(sizeKB * 100) / 100,
990
- isEntry: chunk.isEntry,
991
- type
992
- });
993
- if (chunkSizeWarning && sizeKB > maxChunkSize) {
994
- logger_default.warn(`Chunk "${fileName}" is ${sizeKB.toFixed(2)}KB (exceeds ${maxChunkSize}KB limit)`);
995
- }
996
- }
997
- }
998
- },
999
- closeBundle() {
1000
- if (chunks.length === 0) return;
1001
- chunks.sort((a, b) => b.size - a.size);
1002
- console.log("");
1003
- logger_default.info("Bundle Analysis:");
1004
- const typeGroups = {};
1005
- let totalSize = 0;
1006
- for (const chunk of chunks) {
1007
- typeGroups[chunk.type] = (typeGroups[chunk.type] || 0) + chunk.size;
1008
- totalSize += chunk.size;
1009
- }
1010
- console.log(` Vendor: ${(typeGroups.vendor || 0).toFixed(2)} KB`);
1011
- console.log(` Framework: ${(typeGroups.framework || 0).toFixed(2)} KB`);
1012
- console.log(` Common: ${(typeGroups.common || 0).toFixed(2)} KB`);
1013
- console.log(` Routes: ${(typeGroups.route || 0).toFixed(2)} KB`);
1014
- console.log(` Other: ${(typeGroups.other || 0).toFixed(2)} KB`);
1015
- console.log(` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
1016
- console.log(` Total: ${totalSize.toFixed(2)} KB`);
1017
- console.log("");
1018
- }
1019
- };
1020
- }
1021
- function generatePreloadHints(chunks, entryChunk) {
1022
- const hints = [];
1023
- hints.push({
1024
- href: `/${entryChunk}`,
1025
- as: "script",
1026
- priority: "critical"
1027
- });
1028
- for (const chunk of chunks) {
1029
- if (chunk === entryChunk) continue;
1030
- if (chunk.includes("vendor")) {
1031
- hints.push({
1032
- href: `/${chunk}`,
1033
- as: "script",
1034
- priority: "high"
1035
- });
1036
- } else if (chunk.includes("framework")) {
1037
- hints.push({
1038
- href: `/${chunk}`,
1039
- as: "script",
1040
- priority: "high"
1041
- });
1042
- } else if (chunk.includes("common")) {
1043
- hints.push({
1044
- href: `/${chunk}`,
1045
- as: "script",
1046
- priority: "high"
1047
- });
1048
- } else if (chunk.includes("page-")) {
1049
- hints.push({
1050
- href: `/${chunk}`,
1051
- as: "script",
1052
- priority: "low"
1053
- });
1054
- }
1055
- }
1056
- return hints;
1057
- }
1058
- function generatePreloadTags(hints) {
1059
- return hints.map((hint) => {
1060
- const rel = hint.priority === "low" ? "prefetch" : "modulepreload";
1061
- const crossorigin = hint.crossorigin ? " crossorigin" : "";
1062
- return `<link rel="${rel}" href="${hint.href}"${crossorigin}>`;
1063
- }).join("");
1064
- }
1065
- async function findFilesToCompress(dir, extensions) {
1066
- const files = [];
1067
- try {
1068
- const entries = await fs4__default.default.readdir(dir, { withFileTypes: true });
1069
- for (const entry of entries) {
1070
- const fullPath = path5__default.default.join(dir, entry.name);
1071
- if (entry.isDirectory()) {
1072
- files.push(...await findFilesToCompress(fullPath, extensions));
1073
- } else if (entry.isFile()) {
1074
- const ext = path5__default.default.extname(entry.name).slice(1);
1075
- if (extensions.includes(ext)) {
1076
- files.push(fullPath);
1077
- }
1078
- }
1079
- }
1080
- } catch (e) {
1081
- }
1082
- return files;
1083
- }
1084
- function olovaPerformance(options = {}) {
1085
- return [
1086
- chunkAnalysisPlugin(options),
1087
- compressionPlugin(options)
1088
- ];
1089
- }
1090
-
1091
- // src/hydration/flight.ts
1092
- function safeStringify(data) {
1093
- return JSON.stringify(data).replace(/[<>\/\u2028\u2029]/g, (char) => {
1094
- switch (char) {
1095
- case "<":
1096
- return "\\u003c";
1097
- case ">":
1098
- return "\\u003e";
1099
- case "/":
1100
- return "\\u002f";
1101
- case "\u2028":
1102
- return "\\u2028";
1103
- case "\u2029":
1104
- return "\\u2029";
1105
- default:
1106
- return char;
1107
- }
1108
- });
1109
- }
1110
- function generatePageName(route) {
1111
- if (route === "/") return "HomePage";
1112
- return route.slice(1).split("/").filter(Boolean).map((s) => s.charAt(0).toUpperCase() + s.slice(1).replace(/[^a-zA-Z0-9]/g, "")).join("") + "Page";
1113
- }
1114
- function generatePattern(route) {
1115
- if (route === "/") return "/";
1116
- return route.replace(/\[\.\.\.([^\]]+)\]/g, "*").replace(/\[([^\]]+)\]/g, ":$1");
1117
- }
1118
- function generateFlightRuntime() {
1119
- return `<script>
1120
- (function(){
1121
- var f=self.__olova_f||[];
1122
- var p={R:'$route',M:'$meta',T:'$tree',D:'$schema',A:'$assets',H:'$hints',S:'$state',L:'$loader',Q:'$query'};
1123
- var g=self.$OLOVA={};
1124
- function h(c){var t=c[1],d=c[2];if(t==='E')return;var k=p[t];if(k){if(t==='L'||t==='Q'){g[k]={data:d,timestamp:c[3]||Date.now()}}else{g[k]=d}}}
1125
- for(var i=0;i<f.length;i++)h(f[i]);
1126
- self.__olova_f={push:h,length:0};
1127
- })();
1128
- </script>`;
1129
- }
1130
- function generateOlovaHydration(data, buildId) {
1131
- const meta = data.metadata || {};
1132
- const chunks = [];
1133
- const routeData = {
1134
- path: data.route,
1135
- params: data.params || {},
1136
- pattern: generatePattern(data.route),
1137
- isStatic: data.isStatic ?? true,
1138
- buildId
1139
- };
1140
- chunks.push(`<script>(self.__olova_f=self.__olova_f||[]).push([0,"R",${safeStringify(routeData)}])</script>`);
1141
- const metadataData = {
1142
- title: meta.title || "Olova App",
1143
- description: meta.description || "",
1144
- keywords: Array.isArray(meta.keywords) ? meta.keywords : [],
1145
- robots: meta.robots || "index, follow",
1146
- canonical: meta.canonical || null,
1147
- og: {
1148
- type: "website",
1149
- locale: "en_US",
1150
- ...meta.openGraph || {}
1151
- },
1152
- twitter: {
1153
- card: "summary_large_image",
1154
- ...meta.twitter || {}
1155
- }
1156
- };
1157
- chunks.push(`<script>(self.__olova_f).push([1,"M",${safeStringify(metadataData)}])</script>`);
1158
- const treeData = {
1159
- layout: "RootLayout",
1160
- page: generatePageName(data.route),
1161
- template: null,
1162
- loading: null,
1163
- error: null,
1164
- notFound: null
1165
- };
1166
- chunks.push(`<script>(self.__olova_f).push([2,"T",${safeStringify(treeData)}])</script>`);
1167
- const assetsData = {
1168
- chunks: data.chunks || [],
1169
- styles: [],
1170
- prefetch: (data.chunks || []).slice(0, 5)
1171
- };
1172
- chunks.push(`<script>(self.__olova_f).push([3,"A",${safeStringify(assetsData)}])</script>`);
1173
- const hintsData = {
1174
- dnsPrefetch: ["fonts.googleapis.com", "fonts.gstatic.com"],
1175
- preconnect: ["https://fonts.googleapis.com", "https://fonts.gstatic.com"],
1176
- modulePreload: (data.chunks || []).slice(0, 3)
1177
- };
1178
- chunks.push(`<script>(self.__olova_f).push([4,"H",${safeStringify(hintsData)}])</script>`);
1179
- const stateData = {
1180
- hydrated: false,
1181
- streaming: false,
1182
- ready: true,
1183
- timestamp: Date.now(),
1184
- version: "1.0.0",
1185
- buildId
1186
- };
1187
- chunks.push(`<script>(self.__olova_f).push([5,"S",${safeStringify(stateData)}])</script>`);
1188
- if (data.loaderData) {
1189
- chunks.push(`<script>(self.__olova_f).push([6,"L",${safeStringify(data.loaderData)},${Date.now()}])</script>`);
1190
- }
1191
- if (data.queryState) {
1192
- chunks.push(`<script>(self.__olova_f).push([7,"Q",${safeStringify(data.queryState)},${Date.now()}])</script>`);
1193
- }
1194
- chunks.push(`<script>(self.__olova_f).push([8,"E",null])</script>`);
1195
- chunks.push(generateFlightRuntime());
1196
- return chunks.join("");
1197
- }
1198
- function generateJsonLd(data) {
1199
- const meta = data.metadata || {};
1200
- const jsonLd = {
1201
- "@context": "https://schema.org",
1202
- "@graph": [
1203
- {
1204
- "@type": "WebPage",
1205
- "@id": data.route,
1206
- name: meta.title || "Olova App",
1207
- description: meta.description || "",
1208
- url: data.route,
1209
- isPartOf: {
1210
- "@type": "WebSite",
1211
- name: "Olova App"
1212
- }
1213
- },
1214
- {
1215
- "@type": "BreadcrumbList",
1216
- itemListElement: data.route.split("/").filter(Boolean).map((segment, index, arr) => ({
1217
- "@type": "ListItem",
1218
- position: index + 1,
1219
- name: segment.charAt(0).toUpperCase() + segment.slice(1),
1220
- item: "/" + arr.slice(0, index + 1).join("/")
1221
- }))
1222
- }
1223
- ]
1224
- };
1225
- if (meta.schema) {
1226
- const graph = jsonLd["@graph"];
1227
- if (Array.isArray(meta.schema)) {
1228
- graph.push(...meta.schema);
1229
- } else {
1230
- graph.push(meta.schema);
1231
- }
1232
- }
1233
- return `<script type="application/ld+json">${JSON.stringify(jsonLd)}</script>`;
1234
- }
1235
- function generateResourceHints(data) {
1236
- const hints = [];
1237
- hints.push(`<link rel="dns-prefetch" href="//fonts.googleapis.com">`);
1238
- hints.push(`<link rel="dns-prefetch" href="//fonts.gstatic.com">`);
1239
- hints.push(`<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>`);
1240
- hints.push(`<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>`);
1241
- if (data.chunks) {
1242
- for (const chunk of data.chunks.slice(0, 3)) {
1243
- hints.push(`<link rel="modulepreload" href="/${chunk}">`);
1244
- }
1245
- }
1246
- return hints.join("");
1247
- }
1248
- function generateBuildId() {
1249
- const timestamp = Date.now().toString(36);
1250
- const random = Math.random().toString(36).substring(2, 8);
1251
- return `${timestamp}-${random}`;
1252
- }
1253
-
1254
- // olova.ts
1255
- function olova(options = {}) {
1256
- const virtualModuleId = "virtual:olova-entry";
1257
- const serverVirtualModuleId = "virtual:olova-server-entry";
1258
- const workerVirtualModuleId = "virtual:olova-worker-entry";
1259
- const appVirtualModuleId = "virtual:olova-app";
1260
- const resolvedAppVirtualModuleId = "\0" + appVirtualModuleId;
1261
- let config;
1262
- const htmlContent = `<!--app-html-->`;
1263
- const minifyHtml = (html) => {
1264
- return html.replace(/>\s+</g, "><").replace(/\s{2,}/g, " ").replace(/<!--[\s\S]*?-->/g, "").trim();
1265
- };
1266
- return [
1267
- olovaRouter({ packageName: options.packageName }),
1268
- {
1269
- name: "vite-plugin-olova",
1270
- config(userConfig, { isSsrBuild }) {
1271
- const perfEnabled = options.performance?.enabled !== false;
1272
- if (isSsrBuild) {
1273
- return {
1274
- build: {
1275
- rollupOptions: {
1276
- input: userConfig.build?.rollupOptions?.input || virtualModuleId,
1277
- output: {
1278
- // Simple output for SSR
1279
- entryFileNames: "index.js",
1280
- chunkFileNames: "[name].js",
1281
- assetFileNames: "[name].[ext]",
1282
- format: "esm",
1283
- manualChunks: void 0
1284
- }
1285
- }
1286
- }
1287
- };
1288
- }
1289
- const buildConfig = {
1290
- // Output directory for assets
1291
- assetsDir: "assets/_olova",
1292
- // Report compressed size in build output
1293
- reportCompressedSize: true,
1294
- rollupOptions: {
1295
- input: userConfig.build?.rollupOptions?.input || virtualModuleId,
1296
- output: {
1297
- // Optimized chunk naming for caching
1298
- chunkFileNames: "assets/_olova/[name]-[hash].js",
1299
- entryFileNames: "assets/_olova/[name]-[hash].js",
1300
- assetFileNames: "assets/_olova/[name]-[hash].[ext]",
1301
- // Enable smart code splitting
1302
- ...perfEnabled && {
1303
- manualChunks: createManualChunks()
1304
- }
1305
- }
1306
- },
1307
- // Increase warning limit since we're doing smart chunking
1308
- chunkSizeWarningLimit: 500,
1309
- // Inline small assets (< 4KB)
1310
- assetsInlineLimit: 4096,
1311
- // Enable terser minification for smaller bundles
1312
- minify: "terser",
1313
- terserOptions: {
1314
- compress: {
1315
- // Aggressive optimizations for production
1316
- drop_console: false,
1317
- // Keep console for debugging
1318
- drop_debugger: true,
1319
- pure_funcs: ["console.debug"],
1320
- passes: 2
1321
- },
1322
- mangle: {
1323
- properties: false
1324
- },
1325
- format: {
1326
- comments: false
1327
- }
1328
- },
1329
- // Disable source maps for smaller builds
1330
- sourcemap: false,
1331
- // CSS code splitting
1332
- cssCodeSplit: true,
1333
- // Target modern browsers (smaller bundles)
1334
- target: "es2020"
1335
- };
1336
- return {
1337
- build: buildConfig,
1338
- // Optimize deps for faster dev startup
1339
- optimizeDeps: {
1340
- include: ["react", "react-dom"],
1341
- exclude: ["olova"]
1342
- },
1343
- // SSR options
1344
- ssr: {
1345
- noExternal: ["olova"]
1346
- },
1347
- // esbuild optimizations
1348
- esbuild: {
1349
- treeShaking: true,
1350
- legalComments: "none"
1351
- },
1352
- // Preview server configuration (for testing production builds)
1353
- preview: {
1354
- headers: {
1355
- // Long-term caching for static assets
1356
- "Cache-Control": "public, max-age=31536000"
1357
- }
1358
- }
1359
- };
1360
- },
1361
- async configResolved(resolvedConfig) {
1362
- config = resolvedConfig;
1363
- },
1364
- async resolveId(id) {
1365
- if (id === virtualModuleId || id === serverVirtualModuleId || id === workerVirtualModuleId) {
1366
- const isServer = id === serverVirtualModuleId;
1367
- const isWorker = id === workerVirtualModuleId;
1368
- const fileName = isWorker ? "entry-worker" : isServer ? "entry-server" : "main";
1369
- const possibleLocalPaths = [
1370
- path5__default.default.resolve(config.root, `src/${fileName}.tsx`),
1371
- path5__default.default.resolve(config.root, `src/${fileName}.ts`),
1372
- path5__default.default.resolve(config.root, `${fileName}.tsx`),
1373
- path5__default.default.resolve(config.root, `plugins/${fileName}.tsx`)
1374
- ];
1375
- for (const p of possibleLocalPaths) {
1376
- if (fs3.existsSync(p)) return p;
1377
- }
1378
- const exportName = isWorker ? "olova/entry-worker" : isServer ? "olova/entry-server" : "olova/main";
1379
- try {
1380
- const resolved = await this.resolve(exportName, void 0, { skipSelf: true });
1381
- if (resolved && !resolved.external) {
1382
- return resolved.id;
1383
- }
1384
- } catch (e) {
1385
- }
1386
- const pkgDir = path5__default.default.dirname(url.fileURLToPath(importMetaUrl));
1387
- const possiblePkgPaths = [
1388
- path5__default.default.resolve(pkgDir, `dist/${fileName}.js`),
1389
- path5__default.default.resolve(pkgDir, `${fileName}.js`),
1390
- path5__default.default.resolve(pkgDir, `${fileName}.mjs`),
1391
- path5__default.default.resolve(pkgDir, `${fileName}.ts`),
1392
- path5__default.default.resolve(pkgDir, `${fileName}.tsx`),
1393
- path5__default.default.resolve(pkgDir, `src/${fileName}.tsx`),
1394
- path5__default.default.resolve(pkgDir, `src/${fileName}.ts`),
1395
- // If running from dist, check parent directories
1396
- path5__default.default.resolve(pkgDir, "..", `dist/${fileName}.js`),
1397
- path5__default.default.resolve(pkgDir, "..", `${fileName}.js`),
1398
- path5__default.default.resolve(pkgDir, "..", `${fileName}.tsx`),
1399
- path5__default.default.resolve(pkgDir, "..", `src/${fileName}.tsx`)
1400
- ];
1401
- for (const p of possiblePkgPaths) {
1402
- if (fs3.existsSync(p)) return p;
1403
- }
1404
- }
1405
- if (id === appVirtualModuleId) {
1406
- return resolvedAppVirtualModuleId;
1407
- }
1408
- return null;
1409
- },
1410
- load(id) {
1411
- if (id === resolvedAppVirtualModuleId) {
1412
- return `
1413
- export { OlovaRouter, Outlet, routes, layouts, notFoundPages } from '@/route.tree';
1414
- import '@/index.css';
1415
- `;
1416
- }
1417
- return null;
1418
- },
1419
- configureServer(server) {
1420
- const devBuildId = generateBuildId();
1421
- logger_default.printBanner();
1422
- server.middlewares.use(async (req, res, next) => {
1423
- const url = req.url?.split("?")[0];
1424
- if (url === "/" || url === "/index.html" || req.headers.accept?.includes("text/html") && !url?.match(/\.[a-z]+$/)) {
1425
- try {
1426
- logger_default.printSSRRender(url || "/");
1427
- let template = htmlContent;
1428
- const { render } = await server.ssrLoadModule(
1429
- serverVirtualModuleId
1430
- );
1431
- const renderResult = await render(url || "/");
1432
- const appHtml = typeof renderResult === "string" ? renderResult : renderResult.html;
1433
- const routeMetadata = typeof renderResult === "string" ? {} : renderResult.metadata || {};
1434
- const loaderData = typeof renderResult === "string" ? void 0 : renderResult.loaderData;
1435
- const queryState = typeof renderResult === "string" ? void 0 : renderResult.queryState;
1436
- let fullHtml = template.replace("<!--app-html-->", appHtml);
1437
- const hydrationData = {
1438
- route: url || "/",
1439
- params: {},
1440
- metadata: routeMetadata,
1441
- chunks: [],
1442
- // Dev mode doesn't have pre-built chunks
1443
- isStatic: false,
1444
- loaderData,
1445
- queryState
1446
- };
1447
- const flightScripts = generateOlovaHydration(hydrationData, devBuildId);
1448
- const jsonLdScript = generateJsonLd(hydrationData);
1449
- const resourceHints = `<link rel="dns-prefetch" href="//fonts.googleapis.com"><link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>`;
1450
- if (fullHtml.includes("</head>")) {
1451
- fullHtml = fullHtml.replace("</head>", `${jsonLdScript}${resourceHints}</head>`);
1452
- }
1453
- if (fullHtml.includes("</body>")) {
1454
- fullHtml = fullHtml.replace(
1455
- "</body>",
1456
- `${flightScripts}<script type="module" src="/@id/${virtualModuleId}"></script></body>`
1457
- );
1458
- } else {
1459
- fullHtml += `${flightScripts}<script type="module" src="/@id/${virtualModuleId}"></script>`;
1460
- }
1461
- fullHtml = await server.transformIndexHtml(url || "/", fullHtml);
1462
- if (!fullHtml.trim().toLowerCase().startsWith("<!doctype html>")) {
1463
- fullHtml = `<!DOCTYPE html>${fullHtml}`;
1464
- }
1465
- res.statusCode = 200;
1466
- res.setHeader("Content-Type", "text/html");
1467
- res.end(minifyHtml(fullHtml));
1468
- return;
1469
- } catch (e) {
1470
- server.ssrFixStacktrace(e);
1471
- console.error(e);
1472
- res.statusCode = 500;
1473
- res.end(e.stack);
1474
- return;
1475
- }
1476
- }
1477
- next();
1478
- });
1479
- },
1480
- async writeBundle(_options, bundle) {
1481
- if (config.command === "serve" || config.build.ssr) return;
1482
- const buildStartTime = Date.now();
1483
- logger_default.printBuildStart();
1484
- const outDir = config.build.outDir;
1485
- const serverOutDir = path5__default.default.resolve(config.root, "dist/server");
1486
- const clientEntry = Object.values(bundle).find(
1487
- (chunk) => chunk.type === "chunk" && chunk.isEntry && (chunk.facadeModuleId?.includes("main") || chunk.name === "main")
1488
- );
1489
- const clientEntryFileName = clientEntry ? clientEntry.fileName : "assets/index.js";
1490
- const cssAssets = Object.values(bundle).filter(
1491
- (chunk) => chunk.type === "asset" && chunk.fileName.endsWith(".css")
1492
- );
1493
- const cssLinks = cssAssets.map(
1494
- (css) => `<link rel="stylesheet" crossorigin href="/${css.fileName}">`
1495
- ).join("");
1496
- await vite.build({
1497
- configFile: config.configFile,
1498
- root: config.root,
1499
- build: {
1500
- ssr: true,
1501
- emptyOutDir: false,
1502
- outDir: serverOutDir,
1503
- minify: false,
1504
- // Keep readable for debugging
1505
- rollupOptions: {
1506
- input: { index: serverVirtualModuleId },
1507
- output: {
1508
- entryFileNames: "index.js",
1509
- chunkFileNames: "[name].js",
1510
- assetFileNames: "[name].[ext]",
1511
- format: "esm",
1512
- // Explicitly set to undefined to prevent client-side chunking config
1513
- manualChunks: void 0
1514
- }
1515
- }
1516
- },
1517
- logLevel: "error"
1518
- });
1519
- const serverEntryPath = path5__default.default.resolve(serverOutDir, "index.js");
1520
- const serverEntryUrl = url.pathToFileURL(serverEntryPath).toString();
1521
- const { routes } = await import(serverEntryUrl);
1522
- const paths = ["/"];
1523
- function extractPaths(routesArr) {
1524
- routesArr.forEach((r) => {
1525
- if (r.path && !r.path.includes("*") && !r.path.includes(":")) {
1526
- paths.push(r.path);
1527
- }
1528
- });
1529
- }
1530
- if (Array.isArray(routes)) extractPaths(routes);
1531
- if (Array.isArray(routes)) {
1532
- for (const r of routes) {
1533
- const isDynamic = r.path.includes(":") || r.path.includes("*");
1534
- if (r.getStaticPaths && isDynamic) {
1535
- try {
1536
- const staticPaths = await r.getStaticPaths();
1537
- if (Array.isArray(staticPaths)) {
1538
- for (const entry of staticPaths) {
1539
- let expandedPath = r.path;
1540
- if (entry.params) {
1541
- for (const [key, value] of Object.entries(entry.params)) {
1542
- expandedPath = expandedPath.replace(`:${key}`, value);
1543
- expandedPath = expandedPath.replace("*", value);
1544
- }
1545
- }
1546
- paths.push(expandedPath);
1547
- }
1548
- logger_default.info(`getStaticPaths for ${r.path}: ${staticPaths.length} paths expanded`);
1549
- }
1550
- } catch (e) {
1551
- logger_default.warn(`getStaticPaths() failed for ${r.path}: ${e.message}`);
1552
- }
1553
- }
1554
- }
1555
- }
1556
- if (options.staticPaths) {
1557
- options.staticPaths.forEach((p) => paths.push(p));
1558
- }
1559
- const uniquePaths = [...new Set(paths)];
1560
- const buildId = generateBuildId();
1561
- logger_default.printSSGStart(buildId);
1562
- const routeInfo = uniquePaths.map((p) => ({
1563
- path: p,
1564
- type: p.includes(":") || p.includes("*") ? "dynamic" : "static"
1565
- }));
1566
- logger_default.printRoutes(routeInfo);
1567
- logger_default.printFlightInfo();
1568
- const jsChunks = Object.values(bundle).filter((chunk) => chunk.type === "chunk" && chunk.fileName.endsWith(".js")).map((chunk) => chunk.fileName);
1569
- let successCount = 0;
1570
- let failCount = 0;
1571
- for (const p of uniquePaths) {
1572
- try {
1573
- if (typeof globalThis.window !== "undefined") {
1574
- globalThis.window.location.pathname = p;
1575
- }
1576
- const cacheBuster = `?t=${Date.now()}-${Math.random()}`;
1577
- const { render } = await import(serverEntryUrl + cacheBuster);
1578
- const renderResult = await render(p);
1579
- const appHtml = typeof renderResult === "string" ? renderResult : renderResult.html;
1580
- const routeMetadata = typeof renderResult === "string" ? {} : renderResult.metadata || {};
1581
- const loaderData = typeof renderResult === "string" ? void 0 : renderResult.loaderData;
1582
- const queryState = typeof renderResult === "string" ? void 0 : renderResult.queryState;
1583
- let html = htmlContent.replace("<!--app-html-->", appHtml);
1584
- const preloadHints = generatePreloadHints(jsChunks, clientEntryFileName);
1585
- const preloadTags = generatePreloadTags(preloadHints);
1586
- const hydrationData = {
1587
- route: p,
1588
- params: {},
1589
- metadata: routeMetadata,
1590
- chunks: jsChunks,
1591
- isStatic: true,
1592
- loaderData,
1593
- queryState
1594
- };
1595
- const flightScripts = generateOlovaHydration(hydrationData, buildId);
1596
- const jsonLdScript = generateJsonLd(hydrationData);
1597
- const resourceHints = generateResourceHints(hydrationData);
1598
- if (html.includes("</head>")) {
1599
- html = html.replace("</head>", `${jsonLdScript}${resourceHints}${cssLinks}${preloadTags}</head>`);
1600
- }
1601
- if (html.includes("</body>")) {
1602
- html = html.replace(
1603
- "</body>",
1604
- `${flightScripts}<script type="module" src="/${clientEntryFileName}"></script></body>`
1605
- );
1606
- } else {
1607
- html += `${flightScripts}<script type="module" src="/${clientEntryFileName}"></script>`;
1608
- }
1609
- if (!html.trim().toLowerCase().startsWith("<!doctype html>")) {
1610
- html = `<!DOCTYPE html>${html}`;
1611
- }
1612
- const itemPath = p === "/" ? "index.html" : `${p.substring(1)}/index.html`;
1613
- const finalPath = path5__default.default.resolve(outDir, itemPath);
1614
- await fs4__default.default.mkdir(path5__default.default.dirname(finalPath), { recursive: true });
1615
- await fs4__default.default.writeFile(finalPath, minifyHtml(html));
1616
- logger_default.printPageGenerated(itemPath, true);
1617
- successCount++;
1618
- } catch (e) {
1619
- logger_default.printPageError(p, e.message);
1620
- failCount++;
1621
- }
1622
- }
1623
- try {
1624
- const notFoundPath = "/__olova_404__";
1625
- if (typeof globalThis.window !== "undefined") {
1626
- globalThis.window.location.pathname = notFoundPath;
1627
- }
1628
- const cacheBuster404 = `?t=${Date.now()}-${Math.random()}`;
1629
- const { render: render404 } = await import(serverEntryUrl + cacheBuster404);
1630
- const result404 = await render404(notFoundPath);
1631
- const html404Content = typeof result404 === "string" ? result404 : result404.html;
1632
- let html404 = htmlContent.replace("<!--app-html-->", html404Content);
1633
- const preloadHints404 = generatePreloadHints(jsChunks, clientEntryFileName);
1634
- const preloadTags404 = generatePreloadTags(preloadHints404);
1635
- const hydrationData404 = {
1636
- route: "/404",
1637
- params: {},
1638
- metadata: { title: "404 - Page Not Found" },
1639
- chunks: jsChunks,
1640
- isStatic: true
1641
- };
1642
- const flightScripts404 = generateOlovaHydration(hydrationData404, buildId);
1643
- const jsonLd404 = generateJsonLd(hydrationData404);
1644
- const resourceHints404 = generateResourceHints(hydrationData404);
1645
- if (html404.includes("</head>")) {
1646
- html404 = html404.replace("</head>", `${jsonLd404}${resourceHints404}${cssLinks}${preloadTags404}</head>`);
1647
- }
1648
- if (html404.includes("</body>")) {
1649
- html404 = html404.replace("</body>", `${flightScripts404}<script type="module" src="/${clientEntryFileName}"></script></body>`);
1650
- } else {
1651
- html404 += `${flightScripts404}<script type="module" src="/${clientEntryFileName}"></script>`;
1652
- }
1653
- if (!html404.trim().toLowerCase().startsWith("<!doctype html>")) {
1654
- html404 = `<!DOCTYPE html>${html404}`;
1655
- }
1656
- const notFoundFinalPath = path5__default.default.resolve(outDir, "404.html");
1657
- await fs4__default.default.writeFile(notFoundFinalPath, minifyHtml(html404));
1658
- logger_default.printPageGenerated("404.html", true);
1659
- successCount++;
1660
- } catch (e) {
1661
- logger_default.warn(`Failed to generate 404.html: ${e.message}`);
1662
- }
1663
- await fs4__default.default.rm(serverOutDir, { recursive: true, force: true });
1664
- const buildTime = Date.now() - buildStartTime;
1665
- logger_default.printSSGComplete({
1666
- totalPages: successCount,
1667
- successPages: successCount,
1668
- failedPages: failCount,
1669
- buildTime
1670
- });
1671
- }
1672
- },
1673
- // Add performance optimization plugins
1674
- ...options.performance?.enabled !== false ? olovaPerformance(options.performance) : []
1675
- ];
1676
- }
1677
-
1678
- exports.olova = olova;
1679
- //# sourceMappingURL=olova.cjs.map
1680
- //# sourceMappingURL=olova.cjs.map