olova 2.0.55 → 2.0.56

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 (84) hide show
  1. package/README.md +28 -288
  2. package/dist/chunk-23UAGQ6N.js +2208 -0
  3. package/dist/chunk-23UAGQ6N.js.map +1 -0
  4. package/dist/chunk-D7SIC5TC.js +367 -0
  5. package/dist/chunk-D7SIC5TC.js.map +1 -0
  6. package/dist/entry-server.cjs +2341 -0
  7. package/dist/entry-server.cjs.map +1 -0
  8. package/dist/entry-server.js +114 -0
  9. package/dist/entry-server.js.map +1 -0
  10. package/dist/entry-worker.cjs +2354 -0
  11. package/dist/entry-worker.cjs.map +1 -0
  12. package/dist/entry-worker.js +126 -0
  13. package/dist/entry-worker.js.map +1 -0
  14. package/dist/main.cjs +18 -0
  15. package/dist/main.cjs.map +1 -0
  16. package/dist/main.js +16 -0
  17. package/dist/main.js.map +1 -0
  18. package/dist/olova.cjs +1684 -0
  19. package/dist/olova.cjs.map +1 -0
  20. package/dist/olova.d.cts +72 -0
  21. package/dist/olova.d.ts +72 -0
  22. package/dist/olova.js +1325 -0
  23. package/dist/olova.js.map +1 -0
  24. package/dist/performance.cjs +386 -0
  25. package/dist/performance.cjs.map +1 -0
  26. package/dist/performance.js +3 -0
  27. package/dist/performance.js.map +1 -0
  28. package/dist/router.cjs +646 -0
  29. package/dist/router.cjs.map +1 -0
  30. package/dist/router.d.cts +113 -0
  31. package/dist/router.d.ts +113 -0
  32. package/dist/router.js +632 -0
  33. package/dist/router.js.map +1 -0
  34. package/main.tsx +76 -0
  35. package/olova.ts +619 -0
  36. package/package.json +42 -61
  37. package/src/entry-server.tsx +165 -0
  38. package/src/entry-worker.tsx +201 -0
  39. package/src/generator/index.ts +409 -0
  40. package/src/hydration/flight.ts +320 -0
  41. package/src/hydration/index.ts +12 -0
  42. package/src/hydration/types.ts +225 -0
  43. package/src/logger.ts +182 -0
  44. package/src/main.tsx +24 -0
  45. package/src/performance.ts +488 -0
  46. package/src/plugin/index.ts +204 -0
  47. package/src/router/ErrorBoundary.tsx +145 -0
  48. package/src/router/Link.tsx +117 -0
  49. package/src/router/OlovaRouter.tsx +354 -0
  50. package/src/router/Outlet.tsx +8 -0
  51. package/src/router/context.ts +117 -0
  52. package/src/router/index.ts +29 -0
  53. package/src/router/matching.ts +63 -0
  54. package/src/router/router.tsx +23 -0
  55. package/src/router/search-params.ts +29 -0
  56. package/src/scanner/index.ts +116 -0
  57. package/src/types/index.ts +191 -0
  58. package/src/utils/export.ts +85 -0
  59. package/src/utils/index.ts +4 -0
  60. package/src/utils/naming.ts +54 -0
  61. package/src/utils/path.ts +45 -0
  62. package/tsup.config.ts +35 -0
  63. package/CHANGELOG.md +0 -31
  64. package/LICENSE +0 -21
  65. package/dist/index.cjs +0 -883
  66. package/dist/index.cjs.map +0 -1
  67. package/dist/index.d.cts +0 -138
  68. package/dist/index.d.ts +0 -138
  69. package/dist/index.js +0 -832
  70. package/dist/index.js.map +0 -1
  71. package/dist/plugin.cjs +0 -927
  72. package/dist/plugin.cjs.map +0 -1
  73. package/dist/plugin.d.cts +0 -18
  74. package/dist/plugin.d.ts +0 -18
  75. package/dist/plugin.js +0 -894
  76. package/dist/plugin.js.map +0 -1
  77. package/dist/ssg.cjs +0 -637
  78. package/dist/ssg.cjs.map +0 -1
  79. package/dist/ssg.d.cts +0 -191
  80. package/dist/ssg.d.ts +0 -191
  81. package/dist/ssg.js +0 -585
  82. package/dist/ssg.js.map +0 -1
  83. package/dist/types-BT6YsBGO.d.cts +0 -143
  84. package/dist/types-BT6YsBGO.d.ts +0 -143
package/dist/ssg.cjs DELETED
@@ -1,637 +0,0 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/ssg/index.ts
31
- var ssg_exports = {};
32
- __export(ssg_exports, {
33
- cleanupSSREntry: () => cleanupSSREntry,
34
- crawlRoutes: () => crawlRoutes,
35
- createSSGConfig: () => createSSGConfig,
36
- discoverBuildAssets: () => discoverBuildAssets,
37
- generateHTML: () => generateHTML,
38
- generateHydrationScript: () => generateHydrationScript,
39
- generateMetaTags: () => generateMetaTags,
40
- generateRobotsTxt: () => generateRobotsTxt,
41
- generateSSREntry: () => generateSSREntry,
42
- generateSitemap: () => generateSitemap,
43
- getDynamicPages: () => getDynamicPages,
44
- getStaticPages: () => getStaticPages,
45
- injectContentIntoHTML: () => injectContentIntoHTML,
46
- renderPage: () => renderPage,
47
- renderPages: () => renderPages,
48
- runSSG: () => runSSG
49
- });
50
- module.exports = __toCommonJS(ssg_exports);
51
-
52
- // src/ssg/prerender.ts
53
- var import_fs5 = __toESM(require("fs"), 1);
54
- var import_path5 = __toESM(require("path"), 1);
55
-
56
- // src/ssg/crawler.ts
57
- var import_fs = __toESM(require("fs"), 1);
58
- var import_path = __toESM(require("path"), 1);
59
- async function crawlRoutes(config) {
60
- const appPath = import_path.default.resolve(config.root, config.appDir);
61
- if (!import_fs.default.existsSync(appPath)) {
62
- console.warn(`[olova-ssg] App directory not found: ${appPath}`);
63
- return [];
64
- }
65
- const pages = [];
66
- await scanDirectory(appPath, "/", config, pages);
67
- return pages;
68
- }
69
- async function scanDirectory(dir, routePath, config, pages) {
70
- const entries = import_fs.default.readdirSync(dir, { withFileTypes: true });
71
- for (const entry of entries) {
72
- const fullPath = import_path.default.join(dir, entry.name);
73
- if (entry.isDirectory()) {
74
- const segment = entry.name;
75
- if (segment.startsWith("(") && segment.endsWith(")")) {
76
- await scanDirectory(fullPath, routePath, config, pages);
77
- continue;
78
- }
79
- if (segment.startsWith("@")) {
80
- continue;
81
- }
82
- if (segment.startsWith("[")) {
83
- const newRoutePath2 = buildDynamicRoutePath(routePath, segment);
84
- await scanDirectory(fullPath, newRoutePath2, config, pages);
85
- continue;
86
- }
87
- const newRoutePath = routePath === "/" ? `/${segment}` : `${routePath}/${segment}`;
88
- await scanDirectory(fullPath, newRoutePath, config, pages);
89
- } else if (entry.isFile()) {
90
- const isPage = config.extensions.some((ext) => entry.name === `page${ext}`);
91
- if (isPage) {
92
- const isDynamicRoute = routePath.includes(":") || routePath.includes("*");
93
- const { metadata, hasGenerateMetadata } = await extractPageMetadata(fullPath);
94
- pages.push({
95
- path: routePath || "/",
96
- componentPath: fullPath,
97
- isStatic: !isDynamicRoute,
98
- params: {},
99
- metadata,
100
- hasGenerateMetadata
101
- });
102
- }
103
- }
104
- }
105
- }
106
- function buildDynamicRoutePath(basePath, segment) {
107
- let pathSegment;
108
- if (segment.startsWith("[[...") && segment.endsWith("]]")) {
109
- const paramName = segment.slice(5, -2);
110
- pathSegment = `:${paramName}*`;
111
- } else if (segment.startsWith("[...") && segment.endsWith("]")) {
112
- const paramName = segment.slice(4, -1);
113
- pathSegment = `:${paramName}*`;
114
- } else if (segment.startsWith("[") && segment.endsWith("]")) {
115
- const paramName = segment.slice(1, -1);
116
- pathSegment = `:${paramName}`;
117
- } else {
118
- pathSegment = segment;
119
- }
120
- return basePath === "/" ? `/${pathSegment}` : `${basePath}/${pathSegment}`;
121
- }
122
- async function extractPageMetadata(filePath) {
123
- try {
124
- const content = import_fs.default.readFileSync(filePath, "utf-8");
125
- const hasGenerateMetadata = /export\s+(async\s+)?function\s+generateMetadata/.test(content);
126
- const metadataMatch = content.match(/export\s+const\s+metadata\s*=\s*(\{[\s\S]*?\n\};?)/);
127
- if (metadataMatch) {
128
- try {
129
- const metadataStr = metadataMatch[1];
130
- const metadata = Function('"use strict"; return (' + metadataStr + ")")();
131
- return { metadata, hasGenerateMetadata };
132
- } catch {
133
- return { metadata: extractMetadataSimple(content), hasGenerateMetadata };
134
- }
135
- }
136
- return { metadata: null, hasGenerateMetadata };
137
- } catch (e) {
138
- console.warn(`[olova-ssg] Failed to extract metadata from ${filePath}`);
139
- return { metadata: null, hasGenerateMetadata: false };
140
- }
141
- }
142
- function extractMetadataSimple(content) {
143
- const metadata = {};
144
- const titleMatch = content.match(/title:\s*['"`]([^'"`]+)['"`]/);
145
- if (titleMatch) metadata.title = titleMatch[1];
146
- const descMatch = content.match(/description:\s*['"`]([^'"`]+)['"`]/);
147
- if (descMatch) metadata.description = descMatch[1];
148
- const keywordsMatch = content.match(/keywords:\s*\[([^\]]+)\]/);
149
- if (keywordsMatch) {
150
- const keywords = keywordsMatch[1].split(",").map((k) => k.trim().replace(/['"`]/g, "")).filter(Boolean);
151
- if (keywords.length) metadata.keywords = keywords;
152
- }
153
- return Object.keys(metadata).length > 0 ? metadata : null;
154
- }
155
- function getStaticPages(pages) {
156
- return pages.filter((page) => page.isStatic);
157
- }
158
- function getDynamicPages(pages) {
159
- return pages.filter((page) => !page.isStatic);
160
- }
161
-
162
- // src/ssg/generator.ts
163
- var import_fs2 = __toESM(require("fs"), 1);
164
- var import_path2 = __toESM(require("path"), 1);
165
- function generateSSREntry(pages, config) {
166
- const entryPath = import_path2.default.resolve(config.root, ".olova-ssg-entry.tsx");
167
- const imports = [];
168
- const routeMap = [];
169
- const appDir = import_path2.default.resolve(config.root, config.appDir);
170
- const layoutPath = findLayoutFile(appDir, config.extensions);
171
- if (layoutPath) {
172
- const relativePath = import_path2.default.relative(config.root, layoutPath).replace(/\\/g, "/");
173
- imports.push(`import Layout from './${relativePath}';`);
174
- }
175
- pages.forEach((page, index) => {
176
- const relativePath = import_path2.default.relative(config.root, page.componentPath).replace(/\\/g, "/");
177
- imports.push(`import Page${index} from './${relativePath}';`);
178
- routeMap.push(` '${page.path}': Page${index},`);
179
- });
180
- const entryContent = `
181
- // Auto-generated SSR entry for Olova SSG
182
- import React from 'react';
183
- import { renderToString } from 'react-dom/server';
184
- import { setSSRContext } from 'olova';
185
-
186
- ${imports.join("\n")}
187
-
188
- const routeComponents: Record<string, React.ComponentType<any>> = {
189
- ${routeMap.join("\n")}
190
- };
191
-
192
- export async function render(routePath: string, params: Record<string, string> = {}) {
193
- const Component = routeComponents[routePath];
194
-
195
- if (!Component) {
196
- console.warn('[olova-ssg] No component found for route:', routePath);
197
- return '';
198
- }
199
-
200
- try {
201
- // Set the SSR context before rendering
202
- setSSRContext(routePath, params);
203
-
204
- // Build component hierarchy
205
- const pageElement = React.createElement(Component, { params, searchParams: {} });
206
- ${layoutPath ? `const element = React.createElement(Layout, { children: pageElement, params });` : `const element = pageElement;`}
207
-
208
- return renderToString(element);
209
- } catch (error: any) {
210
- console.error('[olova-ssg] SSR Error for', routePath, ':', error.message);
211
- throw error;
212
- }
213
- }
214
-
215
- export const routes = ${JSON.stringify(pages.map((p) => ({ path: p.path, isStatic: p.isStatic })), null, 2)};
216
- `;
217
- import_fs2.default.writeFileSync(entryPath, entryContent, "utf-8");
218
- return entryPath;
219
- }
220
- function findLayoutFile(dir, extensions) {
221
- for (const ext of extensions) {
222
- const layoutPath = import_path2.default.join(dir, `layout${ext}`);
223
- if (import_fs2.default.existsSync(layoutPath)) {
224
- return layoutPath;
225
- }
226
- }
227
- return null;
228
- }
229
- function cleanupSSREntry(entryPath) {
230
- try {
231
- if (import_fs2.default.existsSync(entryPath)) {
232
- import_fs2.default.unlinkSync(entryPath);
233
- }
234
- } catch (e) {
235
- console.warn("[olova-ssg] Failed to cleanup SSR entry file");
236
- }
237
- }
238
- function generateHydrationScript(routePath, params) {
239
- return `
240
- <script>
241
- window.__OLOVA_DATA__ = ${JSON.stringify({ route: routePath, params, hydrated: false })};
242
- </script>
243
- `;
244
- }
245
-
246
- // src/ssg/renderer.ts
247
- var import_fs3 = __toESM(require("fs"), 1);
248
- var import_path3 = __toESM(require("path"), 1);
249
- var import_url = require("url");
250
- var import_vite = require("vite");
251
- async function renderPage(page, config, ssrEntryPath) {
252
- const tempSSRDir = import_path3.default.join(config.root, ".olova", "ssr");
253
- if (!import_fs3.default.existsSync(tempSSRDir)) {
254
- import_fs3.default.mkdirSync(tempSSRDir, { recursive: true });
255
- }
256
- const pkgPath = import_path3.default.join(tempSSRDir, "package.json");
257
- if (!import_fs3.default.existsSync(pkgPath)) {
258
- import_fs3.default.writeFileSync(pkgPath, JSON.stringify({ type: "module" }));
259
- }
260
- const outputFileName = `ssr-entry-${Date.now()}.js`;
261
- const outputPath = import_path3.default.join(tempSSRDir, outputFileName);
262
- try {
263
- await (0, import_vite.build)({
264
- configFile: false,
265
- root: config.root,
266
- logLevel: "silent",
267
- build: {
268
- ssr: true,
269
- write: true,
270
- outDir: tempSSRDir,
271
- emptyOutDir: false,
272
- rollupOptions: {
273
- input: ssrEntryPath,
274
- output: {
275
- format: "esm",
276
- entryFileNames: outputFileName
277
- },
278
- onwarn: (warning, handler) => {
279
- if (warning.code === "MODULE_LEVEL_DIRECTIVE") return;
280
- handler(warning);
281
- }
282
- }
283
- },
284
- plugins: [
285
- {
286
- name: "olova-ssr-transforms",
287
- transform(code) {
288
- return code.replace(/['"]use client['"];?/g, "").replace(/['"]use static['"];?/g, "");
289
- }
290
- }
291
- ]
292
- });
293
- if (import_fs3.default.existsSync(outputPath)) {
294
- const moduleUrl = (0, import_url.pathToFileURL)(outputPath).href;
295
- const mod = await import(moduleUrl);
296
- const content = await mod.render(page.path, page.params);
297
- return {
298
- content: content || "",
299
- metadata: page.metadata
300
- };
301
- }
302
- throw new Error("Built SSR artifact not found");
303
- } finally {
304
- if (import_fs3.default.existsSync(outputPath)) {
305
- try {
306
- import_fs3.default.unlinkSync(outputPath);
307
- } catch {
308
- }
309
- }
310
- }
311
- }
312
- async function renderPages(pages, config, ssrEntryPath, onProgress) {
313
- const results = /* @__PURE__ */ new Map();
314
- for (let i = 0; i < pages.length; i++) {
315
- const page = pages[i];
316
- if (onProgress) {
317
- onProgress(page, i, pages.length);
318
- }
319
- try {
320
- const result = await renderPage(page, config, ssrEntryPath);
321
- results.set(page.path, result);
322
- } catch (error) {
323
- console.error(`[olova-ssg] Failed to render ${page.path}:`, error.message);
324
- results.set(page.path, { content: "", metadata: page.metadata });
325
- }
326
- }
327
- return results;
328
- }
329
-
330
- // src/ssg/html.ts
331
- var import_fs4 = __toESM(require("fs"), 1);
332
- var import_path4 = __toESM(require("path"), 1);
333
- function generateHTML(options) {
334
- const {
335
- content,
336
- jsEntry,
337
- cssEntries,
338
- metadata,
339
- routePath,
340
- params
341
- } = options;
342
- const metaTags = metadata ? generateMetaTags(metadata) : "";
343
- const cssLinks = cssEntries.map((css) => `<link rel="stylesheet" href="${css}">`).join("\n ");
344
- return `<!doctype html>
345
- <html lang="en">
346
- <head>
347
- <meta charset="UTF-8" />
348
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
349
- ${metaTags}
350
- ${cssLinks}
351
- </head>
352
- <body>
353
- <div id="root">${content}</div>
354
- <script>
355
- window.__OLOVA_DATA__ = ${JSON.stringify({ route: routePath, params, hydrated: false })};
356
- </script>
357
- ${jsEntry ? `<script type="module" src="${jsEntry}"></script>` : ""}
358
- </body>
359
- </html>`;
360
- }
361
- function generateMetaTags(metadata) {
362
- const tags = [];
363
- if (metadata.title) {
364
- tags.push(`<title>${escapeHtml(metadata.title)}</title>`);
365
- }
366
- if (metadata.description) {
367
- tags.push(`<meta name="description" content="${escapeHtml(metadata.description)}" />`);
368
- }
369
- if (metadata.keywords?.length) {
370
- tags.push(`<meta name="keywords" content="${escapeHtml(metadata.keywords.join(", "))}" />`);
371
- }
372
- if (metadata.robots) {
373
- tags.push(`<meta name="robots" content="${escapeHtml(metadata.robots)}" />`);
374
- }
375
- if (metadata.canonical) {
376
- tags.push(`<link rel="canonical" href="${escapeHtml(metadata.canonical)}" />`);
377
- }
378
- if (metadata.openGraph) {
379
- const og = metadata.openGraph;
380
- if (og.title) {
381
- tags.push(`<meta property="og:title" content="${escapeHtml(og.title)}" />`);
382
- }
383
- if (og.description) {
384
- tags.push(`<meta property="og:description" content="${escapeHtml(og.description)}" />`);
385
- }
386
- if (og.url) {
387
- tags.push(`<meta property="og:url" content="${escapeHtml(og.url)}" />`);
388
- }
389
- if (og.siteName) {
390
- tags.push(`<meta property="og:site_name" content="${escapeHtml(og.siteName)}" />`);
391
- }
392
- if (og.type) {
393
- tags.push(`<meta property="og:type" content="${og.type}" />`);
394
- }
395
- if (og.images?.length) {
396
- for (const image of og.images) {
397
- tags.push(`<meta property="og:image" content="${escapeHtml(image.url)}" />`);
398
- if (image.width) {
399
- tags.push(`<meta property="og:image:width" content="${image.width}" />`);
400
- }
401
- if (image.height) {
402
- tags.push(`<meta property="og:image:height" content="${image.height}" />`);
403
- }
404
- if (image.alt) {
405
- tags.push(`<meta property="og:image:alt" content="${escapeHtml(image.alt)}" />`);
406
- }
407
- }
408
- }
409
- }
410
- if (metadata.twitter) {
411
- const tw = metadata.twitter;
412
- if (tw.card) {
413
- tags.push(`<meta name="twitter:card" content="${tw.card}" />`);
414
- }
415
- if (tw.title) {
416
- tags.push(`<meta name="twitter:title" content="${escapeHtml(tw.title)}" />`);
417
- }
418
- if (tw.description) {
419
- tags.push(`<meta name="twitter:description" content="${escapeHtml(tw.description)}" />`);
420
- }
421
- if (tw.creator) {
422
- tags.push(`<meta name="twitter:creator" content="${escapeHtml(tw.creator)}" />`);
423
- }
424
- if (tw.site) {
425
- tags.push(`<meta name="twitter:site" content="${escapeHtml(tw.site)}" />`);
426
- }
427
- if (tw.images?.length) {
428
- tags.push(`<meta name="twitter:image" content="${escapeHtml(tw.images[0])}" />`);
429
- }
430
- }
431
- if (metadata.authors?.length) {
432
- for (const author of metadata.authors) {
433
- tags.push(`<meta name="author" content="${escapeHtml(author.name)}" />`);
434
- }
435
- }
436
- return tags.join("\n ");
437
- }
438
- function discoverBuildAssets(distDir) {
439
- let jsEntry = "";
440
- const cssEntries = [];
441
- const assetsDir = import_path4.default.join(distDir, "assets");
442
- if (import_fs4.default.existsSync(assetsDir)) {
443
- const assets = import_fs4.default.readdirSync(assetsDir);
444
- for (const asset of assets) {
445
- if (asset.startsWith("index") && asset.endsWith(".js")) {
446
- jsEntry = `/assets/${asset}`;
447
- } else if (asset.endsWith(".css")) {
448
- cssEntries.push(`/assets/${asset}`);
449
- }
450
- }
451
- }
452
- return { jsEntry, cssEntries };
453
- }
454
- function injectContentIntoHTML(baseHtml, content, metadata) {
455
- let html = baseHtml;
456
- html = html.replace(
457
- /<div id="root"[^>]*>[\s\S]*?<\/div>/,
458
- `<div id="root">${content}</div>`
459
- );
460
- if (metadata) {
461
- const metaTags = generateMetaTags(metadata);
462
- if (metadata.title) {
463
- html = html.replace(/<title>[^<]*<\/title>/g, "");
464
- }
465
- if (metadata.description) {
466
- html = html.replace(/<meta\s+name="description"[^>]*>/g, "");
467
- }
468
- if (metadata.openGraph) {
469
- html = html.replace(/<meta\s+property="og:[^"]*"[^>]*>/g, "");
470
- }
471
- if (metadata.twitter) {
472
- html = html.replace(/<meta\s+name="twitter:[^"]*"[^>]*>/g, "");
473
- }
474
- html = html.replace(/<head>/, `<head>
475
- ${metaTags}`);
476
- }
477
- return html;
478
- }
479
- function escapeHtml(text) {
480
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
481
- }
482
- function generateSitemap(pages, siteUrl) {
483
- const urls = pages.map((page) => ` <url>
484
- <loc>${siteUrl}${page.path === "/" ? "" : page.path}</loc>
485
- <lastmod>${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}</lastmod>
486
- <changefreq>daily</changefreq>
487
- <priority>${page.path === "/" ? "1.0" : "0.8"}</priority>
488
- </url>`).join("\n");
489
- return `<?xml version="1.0" encoding="UTF-8"?>
490
- <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
491
- ${urls}
492
- </urlset>`;
493
- }
494
- function generateRobotsTxt(siteUrl) {
495
- return `User-agent: *
496
- Allow: /
497
-
498
- Sitemap: ${siteUrl}/sitemap.xml`;
499
- }
500
-
501
- // src/ssg/prerender.ts
502
- async function runSSG(config) {
503
- const startTime = Date.now();
504
- const failedPages = [];
505
- console.log("\n\u{1F4E6} Olova SSG - Starting static generation...\n");
506
- console.log("\u{1F50D} Discovering routes...");
507
- const allPages = await crawlRoutes(config);
508
- const staticPages = getStaticPages(allPages);
509
- console.log(` Found ${allPages.length} total routes`);
510
- console.log(` ${staticPages.length} static routes will be pre-rendered
511
- `);
512
- if (staticPages.length === 0) {
513
- console.log("\u26A0\uFE0F No static pages found to pre-render\n");
514
- return {
515
- totalPages: allPages.length,
516
- staticPages: 0,
517
- failedPages: [],
518
- duration: Date.now() - startTime
519
- };
520
- }
521
- console.log("\u{1F4DD} Generating SSR entry...");
522
- const ssrEntryPath = generateSSREntry(staticPages, config);
523
- const distDir = import_path5.default.resolve(config.root, config.outDir);
524
- const { jsEntry, cssEntries } = discoverBuildAssets(distDir);
525
- console.log(` JS entry: ${jsEntry || "(none)"}`);
526
- console.log(` CSS files: ${cssEntries.length}
527
- `);
528
- const baseHtmlPath = import_path5.default.join(distDir, "index.html");
529
- let baseHtml = "";
530
- if (import_fs5.default.existsSync(baseHtmlPath)) {
531
- baseHtml = import_fs5.default.readFileSync(baseHtmlPath, "utf-8");
532
- } else {
533
- console.warn("\u26A0\uFE0F No index.html found in dist, generating from scratch");
534
- }
535
- console.log("\u{1F528} Pre-rendering pages...\n");
536
- for (const page of staticPages) {
537
- const pageStartTime = Date.now();
538
- try {
539
- const result = await renderPage(page, config, ssrEntryPath);
540
- const outputPath = page.path === "/" ? import_path5.default.join(distDir, "index.html") : import_path5.default.join(distDir, page.path, "index.html");
541
- const outputDir = import_path5.default.dirname(outputPath);
542
- if (!import_fs5.default.existsSync(outputDir)) {
543
- import_fs5.default.mkdirSync(outputDir, { recursive: true });
544
- }
545
- let html;
546
- if (baseHtml) {
547
- html = injectContentIntoHTML(baseHtml, result.content, result.metadata);
548
- } else {
549
- html = generateHTML({
550
- content: result.content,
551
- jsEntry,
552
- cssEntries,
553
- metadata: result.metadata,
554
- routePath: page.path,
555
- params: page.params
556
- });
557
- }
558
- if (!html.includes("__OLOVA_DATA__")) {
559
- html = html.replace(
560
- "</body>",
561
- `<script>window.__OLOVA_DATA__ = ${JSON.stringify({ route: page.path, params: page.params, hydrated: false })};</script>
562
- </body>`
563
- );
564
- }
565
- import_fs5.default.writeFileSync(outputPath, html, "utf-8");
566
- const duration2 = Date.now() - pageStartTime;
567
- console.log(` \u2705 ${page.path} (${duration2}ms)`);
568
- } catch (error) {
569
- failedPages.push(page.path);
570
- console.log(` \u274C ${page.path} - ${error.message}`);
571
- }
572
- }
573
- console.log("\n\u{1F4C4} Generating SEO files...");
574
- const siteUrl = "https://example.com";
575
- const sitemap = generateSitemap(staticPages, siteUrl);
576
- import_fs5.default.writeFileSync(import_path5.default.join(distDir, "sitemap.xml"), sitemap, "utf-8");
577
- console.log(" \u2705 sitemap.xml");
578
- const robotsPath = import_path5.default.join(distDir, "robots.txt");
579
- if (!import_fs5.default.existsSync(robotsPath)) {
580
- import_fs5.default.writeFileSync(robotsPath, generateRobotsTxt(siteUrl), "utf-8");
581
- console.log(" \u2705 robots.txt");
582
- }
583
- cleanupSSREntry(ssrEntryPath);
584
- const buildManifest = {
585
- version: Date.now().toString(36),
586
- buildTime: (/* @__PURE__ */ new Date()).toISOString(),
587
- pages: allPages.map((p) => ({ path: p.path, isStatic: p.isStatic })),
588
- assets: { js: jsEntry, css: cssEntries }
589
- };
590
- import_fs5.default.writeFileSync(
591
- import_path5.default.join(distDir, "build-manifest.json"),
592
- JSON.stringify(buildManifest, null, 2),
593
- "utf-8"
594
- );
595
- const duration = Date.now() - startTime;
596
- const successCount = staticPages.length - failedPages.length;
597
- console.log(`
598
- \u2728 SSG Complete!`);
599
- console.log(` ${successCount}/${staticPages.length} pages generated`);
600
- console.log(` Duration: ${duration}ms
601
- `);
602
- return {
603
- totalPages: allPages.length,
604
- staticPages: successCount,
605
- failedPages,
606
- duration
607
- };
608
- }
609
- function createSSGConfig(root, options = {}) {
610
- return {
611
- root,
612
- appDir: options.appDir || "src/app",
613
- outDir: options.outDir || "dist",
614
- extensions: options.extensions || [".tsx", ".ts", ".jsx", ".js"],
615
- basePath: options.basePath || ""
616
- };
617
- }
618
- // Annotate the CommonJS export names for ESM import in node:
619
- 0 && (module.exports = {
620
- cleanupSSREntry,
621
- crawlRoutes,
622
- createSSGConfig,
623
- discoverBuildAssets,
624
- generateHTML,
625
- generateHydrationScript,
626
- generateMetaTags,
627
- generateRobotsTxt,
628
- generateSSREntry,
629
- generateSitemap,
630
- getDynamicPages,
631
- getStaticPages,
632
- injectContentIntoHTML,
633
- renderPage,
634
- renderPages,
635
- runSSG
636
- });
637
- //# sourceMappingURL=ssg.cjs.map