olova 2.0.54 → 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 (96) hide show
  1. package/README.md +34 -283
  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 +37 -55
  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/dist/client-BBLXpllK.d.ts +0 -487
  64. package/dist/client-C0av_vTZ.d.cts +0 -487
  65. package/dist/client.cjs +0 -850
  66. package/dist/client.cjs.map +0 -1
  67. package/dist/client.d.cts +0 -5
  68. package/dist/client.d.ts +0 -5
  69. package/dist/client.js +0 -816
  70. package/dist/client.js.map +0 -1
  71. package/dist/image.cjs +0 -25
  72. package/dist/image.cjs.map +0 -1
  73. package/dist/image.d.cts +0 -1
  74. package/dist/image.d.ts +0 -1
  75. package/dist/image.js +0 -3
  76. package/dist/image.js.map +0 -1
  77. package/dist/index.cjs +0 -907
  78. package/dist/index.cjs.map +0 -1
  79. package/dist/index.d.cts +0 -31
  80. package/dist/index.d.ts +0 -31
  81. package/dist/index.js +0 -868
  82. package/dist/index.js.map +0 -1
  83. package/dist/plugin/index.cjs +0 -1550
  84. package/dist/plugin/index.cjs.map +0 -1
  85. package/dist/plugin/index.d.cts +0 -131
  86. package/dist/plugin/index.d.ts +0 -131
  87. package/dist/plugin/index.js +0 -1490
  88. package/dist/plugin/index.js.map +0 -1
  89. package/dist/serialization-xKcOESDh.d.cts +0 -122
  90. package/dist/serialization-xKcOESDh.d.ts +0 -122
  91. package/dist/server.cjs +0 -547
  92. package/dist/server.cjs.map +0 -1
  93. package/dist/server.d.cts +0 -148
  94. package/dist/server.d.ts +0 -148
  95. package/dist/server.js +0 -493
  96. package/dist/server.js.map +0 -1
@@ -1,1490 +0,0 @@
1
- // src/plugin/hooks/config.ts
2
- import path7 from "path";
3
-
4
- // src/plugin/config.ts
5
- import fs from "fs";
6
- import path from "path";
7
- import { pathToFileURL } from "url";
8
- import { createRequire } from "module";
9
- var userConfig = {};
10
- async function loadOlovaConfig() {
11
- const configPath = path.resolve(process.cwd(), "olova.config.ts");
12
- if (!fs.existsSync(configPath)) {
13
- console.log(" \u26A0 No olova.config.ts found, using defaults");
14
- return {};
15
- }
16
- try {
17
- const require2 = createRequire(import.meta.url);
18
- const esbuild = require2("esbuild");
19
- const result = await esbuild.build({
20
- entryPoints: [configPath],
21
- bundle: true,
22
- platform: "node",
23
- format: "cjs",
24
- write: false,
25
- external: [
26
- "vite",
27
- "esbuild",
28
- "util",
29
- "path",
30
- "fs",
31
- "url",
32
- "os",
33
- "crypto",
34
- "stream",
35
- "events",
36
- "buffer",
37
- "querystring",
38
- "http",
39
- "https",
40
- "net",
41
- "tls",
42
- "child_process",
43
- "cluster",
44
- "dgram",
45
- "dns",
46
- "domain",
47
- "readline",
48
- "repl",
49
- "tty",
50
- "v8",
51
- "vm",
52
- "zlib",
53
- "assert",
54
- "async_hooks",
55
- "console",
56
- "constants",
57
- "module",
58
- "perf_hooks",
59
- "process",
60
- "string_decoder",
61
- "timers",
62
- "trace_events",
63
- "worker_threads"
64
- ]
65
- });
66
- const code = result.outputFiles[0].text;
67
- const tempPath = path.resolve(process.cwd(), ".olova/temp-config.cjs");
68
- const olovaDir = path.resolve(process.cwd(), ".olova");
69
- if (!fs.existsSync(olovaDir)) {
70
- fs.mkdirSync(olovaDir, { recursive: true });
71
- }
72
- fs.writeFileSync(tempPath, code);
73
- const mod = await import(pathToFileURL(tempPath).href);
74
- fs.unlinkSync(tempPath);
75
- userConfig = mod.default?.default || mod.default || {};
76
- return userConfig;
77
- } catch (err) {
78
- console.error(" \u26A0 Failed to load olova.config.ts:", err.message);
79
- return {};
80
- }
81
- }
82
- function getConfig() {
83
- return {
84
- outDir: ".olova/dist",
85
- basePath: "/",
86
- trailingSlash: false,
87
- experimental: {
88
- prefetch: true,
89
- ...userConfig.experimental
90
- },
91
- staticGeneration: {
92
- timeout: 3e4,
93
- fallback: "blocking",
94
- ...userConfig.staticGeneration
95
- },
96
- ...userConfig
97
- };
98
- }
99
- function getUserConfig() {
100
- return userConfig;
101
- }
102
-
103
- // src/plugin/css/detection.ts
104
- import fs2 from "fs";
105
- import path2 from "path";
106
- async function detectTailwindConfig(baseDir = process.cwd()) {
107
- const configFiles = ["tailwind.config.js", "tailwind.config.ts", "tailwind.config.mjs", "tailwind.config.cjs"];
108
- for (const configFile of configFiles) {
109
- const configPath = path2.resolve(baseDir, configFile);
110
- if (fs2.existsSync(configPath)) {
111
- const content = fs2.readFileSync(configPath, "utf-8");
112
- const isV4 = content.includes("@tailwindcss") || content.includes("theme:");
113
- return { detected: true, configPath, version: isV4 ? "4" : "3" };
114
- }
115
- }
116
- const packageJsonPath = path2.resolve(baseDir, "package.json");
117
- if (fs2.existsSync(packageJsonPath)) {
118
- try {
119
- const pkg = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
120
- const deps = { ...pkg.dependencies, ...pkg.devDependencies };
121
- if (deps["tailwindcss"]) {
122
- const version = deps["tailwindcss"].replace(/^[\^~>=<]+/, "");
123
- return { detected: true, version: version.startsWith("4") ? "4" : "3" };
124
- }
125
- } catch {
126
- }
127
- }
128
- return { detected: false };
129
- }
130
- async function detectPostCSSConfig(baseDir = process.cwd()) {
131
- const configFiles = ["postcss.config.js", "postcss.config.cjs", "postcss.config.mjs", "postcss.config.ts", ".postcssrc", ".postcssrc.js", ".postcssrc.json"];
132
- for (const configFile of configFiles) {
133
- const configPath = path2.resolve(baseDir, configFile);
134
- if (fs2.existsSync(configPath)) return { detected: true, configPath };
135
- }
136
- return { detected: false };
137
- }
138
-
139
- // src/plugin/css/collection.ts
140
- import fs3 from "fs";
141
- import path3 from "path";
142
- function collectCSSFiles(srcDir) {
143
- const globalCSS = [];
144
- const cssModules = [];
145
- function scanDirectory(dir) {
146
- if (!fs3.existsSync(dir)) return;
147
- const entries = fs3.readdirSync(dir, { withFileTypes: true });
148
- for (const entry of entries) {
149
- const fullPath = path3.join(dir, entry.name);
150
- if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
151
- scanDirectory(fullPath);
152
- } else if (entry.isFile()) {
153
- if (entry.name.endsWith(".module.css") || entry.name.endsWith(".module.scss")) {
154
- cssModules.push(fullPath);
155
- } else if (entry.name.endsWith(".css") || entry.name.endsWith(".scss")) {
156
- if (dir === srcDir) globalCSS.push(fullPath);
157
- }
158
- }
159
- }
160
- }
161
- scanDirectory(srcDir);
162
- return { globalCSS, cssModules };
163
- }
164
- function getCSSForBuild(outDir) {
165
- const cssFiles = [];
166
- function scanCSSDir(dir, basePath) {
167
- if (!fs3.existsSync(dir)) return;
168
- const entries = fs3.readdirSync(dir, { withFileTypes: true });
169
- for (const entry of entries) {
170
- if (entry.isDirectory()) scanCSSDir(path3.join(dir, entry.name), basePath + entry.name + "/");
171
- else if (entry.isFile() && entry.name.endsWith(".css")) cssFiles.push(basePath + entry.name);
172
- }
173
- }
174
- const olovaCssDir = path3.join(outDir, "_olova", "static", "css");
175
- if (fs3.existsSync(olovaCssDir)) scanCSSDir(olovaCssDir, "/_olova/static/css/");
176
- const legacyCssDir = path3.join(outDir, "assets", "css");
177
- if (cssFiles.length === 0 && fs3.existsSync(legacyCssDir)) scanCSSDir(legacyCssDir, "/assets/css/");
178
- return cssFiles;
179
- }
180
-
181
- // src/plugin/css/generator.ts
182
- import path4 from "path";
183
- function generateCSSLinks(cssFiles, basePath = "/") {
184
- return cssFiles.map((file) => {
185
- const href = basePath + file.replace(/\\/g, "/");
186
- return `<link rel="stylesheet" href="${href}" />`;
187
- }).join("\n ");
188
- }
189
- function generateCSSImports(cssFiles, srcDir) {
190
- return cssFiles.map((file) => {
191
- const relativePath = path4.relative(srcDir, file).replace(/\\/g, "/");
192
- return `import '@/${relativePath}';`;
193
- }).join("\n");
194
- }
195
-
196
- // src/plugin/css/config.ts
197
- function createDefaultPostCSSConfig(tailwindResult) {
198
- const plugins = [];
199
- if (tailwindResult.detected && tailwindResult.version !== "4") {
200
- plugins.push(["tailwindcss", tailwindResult.configPath ? { config: tailwindResult.configPath } : {}]);
201
- }
202
- if (plugins.length > 0) plugins.push(["autoprefixer", {}]);
203
- return plugins.length > 0 ? { plugins } : void 0;
204
- }
205
- async function createViteCSSConfig(cssConfig = {}, baseDir = process.cwd()) {
206
- const tailwindResult = cssConfig.tailwind !== false ? await detectTailwindConfig(baseDir) : { detected: false };
207
- const postcssResult = await detectPostCSSConfig(baseDir);
208
- const cssOptions = {
209
- modules: cssConfig.modules !== false ? { localsConvention: "camelCaseOnly", generateScopedName: "[name]__[local]___[hash:base64:5]" } : false
210
- };
211
- if (cssConfig.postcss !== false && !postcssResult.detected) {
212
- cssOptions.postcss = createDefaultPostCSSConfig(tailwindResult);
213
- }
214
- return cssOptions;
215
- }
216
-
217
- // src/plugin/css/utils.ts
218
- import path5 from "path";
219
- function isCSSModule(filePath) {
220
- return /\.module\.(css|scss|sass|less)$/.test(filePath);
221
- }
222
- function isCSSFile(filePath) {
223
- return /\.(css|scss|sass|less)$/.test(filePath);
224
- }
225
- function logCSSStatus(tailwindResult, postcssResult, globalCSS) {
226
- console.log("\n \x1B[1m\x1B[36m\u{1F3A8} CSS Configuration\x1B[0m");
227
- if (tailwindResult.detected) console.log(` \u2713 Tailwind CSS ${tailwindResult.version === "4" ? "v4" : "v3"} detected`);
228
- if (postcssResult.detected) console.log(` \u2713 PostCSS config found: ${path5.basename(postcssResult.configPath)}`);
229
- else console.log(" \u25CB Using default PostCSS config (autoprefixer)");
230
- if (globalCSS.length > 0) console.log(` \u2713 Global CSS files: ${globalCSS.map((f) => path5.basename(f)).join(", ")}`);
231
- console.log("");
232
- }
233
-
234
- // src/plugin/chunks/collector.ts
235
- function createChunkCollector() {
236
- return {
237
- routes: /* @__PURE__ */ new Map(),
238
- shared: /* @__PURE__ */ new Set(),
239
- assets: /* @__PURE__ */ new Map(),
240
- framework: { react: null, reactDom: null, scheduler: null, router: null },
241
- chunkGroups: /* @__PURE__ */ new Map()
242
- };
243
- }
244
- function addRouteChunk(collector, routePath, chunkFile, size, isStatic = false, isDynamic = false, css = [], dependencies = [], priority = "normal") {
245
- collector.routes.set(routePath, { chunk: chunkFile, size, isStatic, isDynamic, css, dependencies, priority });
246
- }
247
- function addSharedChunk(collector, chunkFile) {
248
- collector.shared.add(chunkFile);
249
- }
250
- function trackFrameworkChunk(collector, chunkName, fileName) {
251
- if (chunkName === "framework-react") collector.framework.react = fileName;
252
- else if (chunkName === "framework-react-dom") collector.framework.reactDom = fileName;
253
- else if (chunkName === "framework-scheduler") collector.framework.scheduler = fileName;
254
- }
255
- function addToChunkGroup(collector, groupName, chunkFile) {
256
- if (!collector.chunkGroups.has(groupName)) collector.chunkGroups.set(groupName, /* @__PURE__ */ new Set());
257
- collector.chunkGroups.get(groupName).add(chunkFile);
258
- }
259
-
260
- // src/plugin/chunks/manifest.ts
261
- import fs4 from "fs";
262
- import path6 from "path";
263
- function generatePreloadHints(chunk, css, dependencies) {
264
- const hints = [{ href: chunk, as: "script", priority: "critical", crossorigin: true }];
265
- for (const cssFile of css) hints.push({ href: cssFile, as: "style", priority: "high" });
266
- for (const dep of dependencies) hints.push({ href: dep.chunk, as: "script", priority: dep.priority, crossorigin: true });
267
- return hints;
268
- }
269
- function generateChunkManifest(collector) {
270
- const routes = {};
271
- const preloadMap = {};
272
- collector.routes.forEach((info, routePath) => {
273
- const preloadHints = generatePreloadHints(info.chunk, info.css, info.dependencies);
274
- routes[routePath] = { ...info, preloadHints };
275
- preloadMap[routePath] = preloadHints;
276
- });
277
- const assets = {};
278
- collector.assets.forEach((info, fileName) => {
279
- assets[fileName] = info;
280
- });
281
- const chunkGroups = {};
282
- collector.chunkGroups.forEach((chunks, groupName) => {
283
- chunkGroups[groupName] = Array.from(chunks);
284
- });
285
- return { version: 2, buildTime: (/* @__PURE__ */ new Date()).toISOString(), routes, shared: Array.from(collector.shared), assets, framework: collector.framework, preloadMap, chunkGroups };
286
- }
287
- function writeChunkManifest(outDir, manifest) {
288
- const olovaDir = path6.join(outDir, "_olova");
289
- if (!fs4.existsSync(olovaDir)) fs4.mkdirSync(olovaDir, { recursive: true });
290
- fs4.writeFileSync(path6.join(olovaDir, "chunks-manifest.json"), JSON.stringify(manifest, null, 2));
291
- console.log(` \u2713 Generated chunks-manifest.json (${Object.keys(manifest.routes).length} routes)`);
292
- }
293
-
294
- // src/plugin/chunks/utils.ts
295
- function routePathToChunkName(routePath) {
296
- if (routePath === "/") return "index";
297
- return routePath.replace(/^\//, "").replace(/\[\.\.\.(\w+)\]/g, "$1").replace(/\[(\w+)\]/g, "$1").replace(/:/g, "").replace(/\*/g, "").replace(/\//g, "-").toLowerCase();
298
- }
299
- function isPageModule(id, srcDir) {
300
- if (!id.includes(srcDir)) return false;
301
- const relativePath = id.replace(srcDir, "").replace(/\\/g, "/");
302
- return /\/page\.(tsx?|jsx?)$/.test(relativePath);
303
- }
304
- function extractRoutePath(id, srcDir) {
305
- if (!isPageModule(id, srcDir)) return null;
306
- const relativePath = id.replace(srcDir, "").replace(/\\/g, "/").replace(/\/page\.(tsx?|jsx?)$/, "");
307
- if (relativePath === "" || relativePath === "/") return "/";
308
- return relativePath.replace(/\[\.\.\.(\w+)\]/g, "*$1").replace(/\[(\w+)\]/g, ":$1");
309
- }
310
-
311
- // src/plugin/chunks/manual.ts
312
- var isOfType = (id, srcDir, pattern) => {
313
- if (!id.includes(srcDir)) return false;
314
- return pattern.test(id.replace(srcDir, "").replace(/\\/g, "/"));
315
- };
316
- var getVendorChunkGroup = (packageName) => {
317
- if (packageName === "react" || packageName.startsWith("react-")) return `framework-${packageName}`;
318
- if (packageName === "scheduler") return "framework-scheduler";
319
- const groups = {
320
- "vendor-ui": ["@radix-ui", "@headlessui", "@heroicons", "lucide-react", "clsx", "class-variance-authority"],
321
- "vendor-forms": ["react-hook-form", "zod", "yup", "@hookform"],
322
- "vendor-date": ["date-fns", "dayjs", "moment", "luxon"],
323
- "vendor-animation": ["framer-motion", "gsap", "animejs", "@react-spring"],
324
- "vendor-state": ["zustand", "jotai", "recoil", "@tanstack/query", "swr"]
325
- };
326
- for (const [group, libs] of Object.entries(groups)) {
327
- if (libs.some((lib) => packageName.startsWith(lib))) return group;
328
- }
329
- return `vendor-${packageName}`;
330
- };
331
- function createManualChunks(srcDir) {
332
- const normSrc = srcDir.replace(/\\/g, "/");
333
- return (id) => {
334
- const normId = id.replace(/\\/g, "/");
335
- if (normId.includes("node_modules/react-dom")) return "framework-react-dom";
336
- if (normId.includes("node_modules/react/")) return "framework-react";
337
- if (normId.includes("node_modules/scheduler")) return "framework-scheduler";
338
- if (isOfType(normId, normSrc, /\/layout\.(tsx?|jsx?)$/)) {
339
- const rel = normId.replace(normSrc, "");
340
- if (rel === "/layout.tsx" || rel === "/layout.jsx") return "layouts/root";
341
- return `layouts/${rel.replace(/\/layout\.(tsx?|jsx?)$/, "").replace(/^\//, "").replace(/\//g, "-") || "root"}`;
342
- }
343
- if (isOfType(normId, normSrc, /\/template\.(tsx?|jsx?)$/)) return "shared/template";
344
- if (isOfType(normId, normSrc, /\/loading\.(tsx?|jsx?)$/)) return "shared/loading";
345
- if (isOfType(normId, normSrc, /\/error\.(tsx?|jsx?)$/)) return "shared/error";
346
- if (isPageModule(normId, normSrc)) {
347
- const route = extractRoutePath(normId, normSrc);
348
- if (route) return `pages/${routePathToChunkName(route)}`;
349
- }
350
- if (normId.includes("/components/")) {
351
- const match = normId.replace(normSrc, "").match(/\/components\/([^/]+)\//);
352
- return match ? `components/${match[1]}` : "components/shared";
353
- }
354
- if (normId.includes("/hooks/")) return "shared/hooks";
355
- if (normId.includes("/lib/") || normId.includes("/utils/") || normId.includes("/helpers/")) return "shared/utils";
356
- if (normId.includes("node_modules")) {
357
- const parts = normId.split("node_modules/");
358
- const pkg = parts[parts.length - 1];
359
- const pkgName = pkg.startsWith("@") ? pkg.split("/").slice(0, 2).join("-").replace("@", "") : pkg.split("/")[0];
360
- return getVendorChunkGroup(pkgName);
361
- }
362
- return void 0;
363
- };
364
- }
365
-
366
- // src/plugin/hooks/config.ts
367
- async function handleConfig() {
368
- const userConfig2 = await loadOlovaConfig();
369
- const olovaConfig = getConfig();
370
- console.log("\n \x1B[1m\x1B[35m\u{1F52E} Olova Framework\x1B[0m");
371
- if (Object.keys(userConfig2).length > 0) {
372
- console.log(" \u2713 Loaded olova.config.ts");
373
- }
374
- const cssConfig = userConfig2.css || {};
375
- const tailwindResult = cssConfig.tailwind !== false ? await detectTailwindConfig() : { detected: false };
376
- const postcssResult = await detectPostCSSConfig();
377
- const srcDir = path7.resolve(process.cwd(), "src");
378
- const cssFiles = collectCSSFiles(srcDir);
379
- logCSSStatus(tailwindResult, postcssResult, cssFiles.globalCSS);
380
- let postcssConfig = void 0;
381
- if (cssConfig.postcss !== false && !postcssResult.detected) {
382
- postcssConfig = createDefaultPostCSSConfig(tailwindResult);
383
- }
384
- const config = {
385
- build: {
386
- outDir: olovaConfig.outDir,
387
- chunkSizeWarningLimit: 500,
388
- copyPublicDir: true,
389
- rollupOptions: {
390
- input: "virtual:olova-entry-client",
391
- output: {
392
- manualChunks: createManualChunks(path7.resolve(process.cwd(), "src")),
393
- chunkFileNames: (chunkInfo) => {
394
- const name = chunkInfo.name || "";
395
- if (name.startsWith("framework-react-dom")) return "_olova/static/chunks/framework-[hash].js";
396
- if (name.startsWith("framework-") || name.startsWith("vendor-")) return "_olova/static/chunks/[name]-[hash].js";
397
- if (name.startsWith("pages/") || name.startsWith("pages-")) return "_olova/static/chunks/pages/[name]-[hash].js";
398
- return "_olova/static/chunks/[name]-[hash].js";
399
- },
400
- entryFileNames: "_olova/static/chunks/main-[hash].js",
401
- assetFileNames: (assetInfo) => {
402
- const fileName = assetInfo.name || "";
403
- if (fileName.endsWith(".css")) {
404
- const baseName = fileName.split("/").pop()?.replace(".css", "") || "style";
405
- return `_olova/static/css/${baseName}-[hash][extname]`;
406
- }
407
- return "_olova/static/media/[name]-[hash][extname]";
408
- }
409
- }
410
- },
411
- minify: "terser",
412
- terserOptions: { compress: { drop_console: false, drop_debugger: true } },
413
- sourcemap: false,
414
- target: "esnext"
415
- },
416
- css: {
417
- modules: cssConfig.modules !== false ? {
418
- localsConvention: "camelCaseOnly",
419
- generateScopedName: "[name]__[local]___[hash:base64:5]"
420
- } : false,
421
- postcss: postcssConfig,
422
- devSourcemap: cssConfig.devSourceMap !== false
423
- },
424
- resolve: { alias: { "@": path7.resolve(process.cwd(), "src") } },
425
- ...olovaConfig.vite
426
- };
427
- return config;
428
- }
429
-
430
- // src/plugin/hooks/server.ts
431
- import path11 from "path";
432
- import fs8 from "fs";
433
-
434
- // src/plugin/utils.ts
435
- import fs5 from "fs";
436
- import path8 from "path";
437
- function findPages(dir, baseDir, userConfig2, pages = [], context = { layouts: [] }) {
438
- const files = fs5.readdirSync(dir);
439
- const currentContext = {
440
- layouts: [...context.layouts],
441
- loading: context.loading,
442
- error: context.error,
443
- notFound: context.notFound,
444
- template: context.template
445
- };
446
- for (const file of files) {
447
- const fullPath = path8.join(dir, file).replace(/\\/g, "/");
448
- if (file === "layout.tsx" || file === "layout.jsx") currentContext.layouts.push(fullPath);
449
- if (file === "loading.tsx" || file === "loading.jsx") currentContext.loading = fullPath;
450
- if (file === "error.tsx" || file === "error.jsx") currentContext.error = fullPath;
451
- if (file === "not-found.tsx" || file === "not-found.jsx") currentContext.notFound = fullPath;
452
- if (file === "template.tsx" || file === "template.jsx") currentContext.template = fullPath;
453
- }
454
- for (const file of files) {
455
- const fullPath = path8.join(dir, file);
456
- const isDirectory = fs5.statSync(fullPath).isDirectory();
457
- if (isDirectory && file.startsWith("(") && file.endsWith(")")) {
458
- findPages(fullPath, baseDir, userConfig2, pages, currentContext);
459
- continue;
460
- }
461
- if (isDirectory && file !== "assets" && file !== "node_modules") {
462
- findPages(fullPath, baseDir, userConfig2, pages, currentContext);
463
- } else if (file === "page.tsx" || file === "page.jsx") {
464
- let relativePath = path8.relative(baseDir, dir);
465
- relativePath = relativePath.replace(/\([^)]+\)\/?/g, "");
466
- let routePath = "/" + relativePath.replace(/\\/g, "/");
467
- routePath = routePath.replace(/\/+/g, "/");
468
- const isDynamic = routePath.includes("[") && routePath.includes("]");
469
- if (isDynamic) {
470
- routePath = routePath.replace(/\[\[\.{3}(.+?)\]\]/g, "*$1?").replace(/\[\.{3}(.+?)\]/g, "*$1").replace(/\[(.+?)\]/g, ":$1");
471
- }
472
- const finalPath = routePath === "/" ? "/" : routePath.replace(/\/$/, "");
473
- const content = fs5.readFileSync(fullPath, "utf-8");
474
- const hasStaticDirective = content.trimStart().startsWith('"use static"') || content.trimStart().startsWith("'use static'");
475
- const isStatic = !isDynamic && (hasStaticDirective || !!userConfig2.ssg?.enabled);
476
- pages.push({
477
- path: finalPath,
478
- componentPath: fullPath.replace(/\\/g, "/"),
479
- layoutPaths: currentContext.layouts,
480
- loadingPath: currentContext.loading,
481
- errorPath: currentContext.error,
482
- notFoundPath: currentContext.notFound,
483
- templatePath: currentContext.template,
484
- isStatic,
485
- isDynamic
486
- });
487
- }
488
- }
489
- return pages;
490
- }
491
-
492
- // src/plugin/hooks/server/manifests.ts
493
- import fs7 from "fs";
494
- import path10 from "path";
495
-
496
- // src/plugin/cache.ts
497
- import fs6 from "fs";
498
- import path9 from "path";
499
- import crypto from "crypto";
500
- var OLOVA_DIR = ".olova";
501
- var CACHE_DIR = ".olova/cache";
502
- var PAGES_CACHE = ".olova/cache/pages";
503
- var DATA_CACHE = ".olova/cache/fetch-cache";
504
- var SERVER_DIR = ".olova/server";
505
- function generateFileHash(filePath) {
506
- if (!fs6.existsSync(filePath)) return "";
507
- const content = fs6.readFileSync(filePath, "utf-8");
508
- return crypto.createHash("md5").update(content).digest("hex").slice(0, 8);
509
- }
510
- function generateBuildId() {
511
- return Date.now().toString(36) + Math.random().toString(36).slice(2, 6);
512
- }
513
- function initCacheDir(baseDir, mode = "production") {
514
- const olovaDir = path9.join(baseDir, OLOVA_DIR);
515
- const cacheDir = path9.join(baseDir, CACHE_DIR);
516
- const pagesCache = path9.join(baseDir, PAGES_CACHE);
517
- const dataCache = path9.join(baseDir, DATA_CACHE);
518
- const serverDir = path9.join(baseDir, SERVER_DIR);
519
- [olovaDir, cacheDir, pagesCache, dataCache, serverDir].forEach((dir) => {
520
- if (!fs6.existsSync(dir)) {
521
- fs6.mkdirSync(dir, { recursive: true });
522
- }
523
- });
524
- const buildInfo = {
525
- version: "1.0.0",
526
- buildId: generateBuildId(),
527
- startTime: (/* @__PURE__ */ new Date()).toISOString(),
528
- mode,
529
- nodeVersion: process.version,
530
- olovaVersion: "2.0.48"
531
- };
532
- fs6.writeFileSync(path9.join(olovaDir, "build-info.json"), JSON.stringify(buildInfo, null, 2));
533
- const packageInfo = {
534
- name: "olova",
535
- version: "2.0.48"
536
- };
537
- fs6.writeFileSync(path9.join(olovaDir, "package.json"), JSON.stringify(packageInfo, null, 2));
538
- const serverFiles = {
539
- version: 1,
540
- config: {
541
- env: {},
542
- basePath: "",
543
- trailingSlash: false
544
- },
545
- files: []
546
- };
547
- fs6.writeFileSync(path9.join(olovaDir, "required-server-files.json"), JSON.stringify(serverFiles, null, 2));
548
- }
549
- function getCachedPage(baseDir, pagePath) {
550
- const cacheFile = path9.join(baseDir, PAGES_CACHE, `${pagePath.replace(/\//g, "_")}.json`);
551
- if (fs6.existsSync(cacheFile)) {
552
- try {
553
- return JSON.parse(fs6.readFileSync(cacheFile, "utf-8"));
554
- } catch {
555
- return null;
556
- }
557
- }
558
- return null;
559
- }
560
- function setCachedPage(baseDir, pagePath, data, hash) {
561
- const cacheFile = path9.join(baseDir, PAGES_CACHE, `${pagePath.replace(/\//g, "_") || "_root"}.json`);
562
- const entry = {
563
- hash,
564
- timestamp: Date.now(),
565
- data
566
- };
567
- fs6.writeFileSync(cacheFile, JSON.stringify(entry, null, 2));
568
- }
569
- function getCachedData(baseDir, pagePath) {
570
- const cacheFile = path9.join(baseDir, DATA_CACHE, `${pagePath.replace(/\//g, "_") || "_root"}.json`);
571
- if (fs6.existsSync(cacheFile)) {
572
- try {
573
- return JSON.parse(fs6.readFileSync(cacheFile, "utf-8"));
574
- } catch {
575
- return null;
576
- }
577
- }
578
- return null;
579
- }
580
- function setCachedData(baseDir, pagePath, data, hash) {
581
- const cacheFile = path9.join(baseDir, DATA_CACHE, `${pagePath.replace(/\//g, "_") || "_root"}.json`);
582
- const entry = {
583
- hash,
584
- timestamp: Date.now(),
585
- data
586
- };
587
- fs6.writeFileSync(cacheFile, JSON.stringify(entry, null, 2));
588
- }
589
- function isCacheValid(cached, currentHash) {
590
- if (!cached) return false;
591
- return cached.hash === currentHash;
592
- }
593
- function generatePrerenderManifest(baseDir, pages) {
594
- const manifest = {
595
- version: "1.0",
596
- routes: {},
597
- dynamicRoutes: {}
598
- };
599
- for (const page of pages) {
600
- manifest.routes[page.path] = {
601
- dataRoute: page.isStatic ? `/data${page.path === "/" ? "/index" : page.path}.json` : null,
602
- isStatic: page.isStatic,
603
- srcHash: generateFileHash(page.componentPath)
604
- };
605
- }
606
- const manifestPath = path9.join(baseDir, ".olova", "prerender-manifest.json");
607
- fs6.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
608
- return manifest;
609
- }
610
- function clearCache(baseDir) {
611
- const cacheDir = path9.join(baseDir, CACHE_DIR);
612
- if (fs6.existsSync(cacheDir)) {
613
- fs6.rmSync(cacheDir, { recursive: true, force: true });
614
- }
615
- initCacheDir(baseDir);
616
- }
617
- function getCacheAge(cached) {
618
- return Math.floor((Date.now() - cached.timestamp) / 1e3);
619
- }
620
-
621
- // src/plugin/hooks/server/manifests.ts
622
- function setupServerManifests(baseDir, srcDir, pages) {
623
- initCacheDir(baseDir, "development");
624
- const routesManifest = {
625
- version: 1,
626
- basePath: "",
627
- pages: pages.map((p) => ({
628
- path: p.path,
629
- componentPath: p.componentPath,
630
- isStatic: p.isStatic,
631
- isDynamic: p.isDynamic || false
632
- })),
633
- staticRoutes: pages.filter((p) => p.isStatic).map((p) => ({ path: p.path })),
634
- dynamicRoutes: pages.filter((p) => p.isDynamic).map((p) => ({
635
- path: p.path,
636
- regex: p.path.replace(/:\w+/g, "[^/]+").replace(/\*/g, ".*")
637
- }))
638
- };
639
- const olovaDir = path10.join(baseDir, ".olova");
640
- fs7.writeFileSync(path10.join(olovaDir, "routes-manifest.json"), JSON.stringify(routesManifest, null, 2));
641
- const appPathsManifest = {};
642
- pages.forEach((p) => {
643
- appPathsManifest[p.path] = [p.componentPath.replace(srcDir, "").replace(/\\/g, "/")];
644
- });
645
- fs7.writeFileSync(path10.join(olovaDir, "app-paths-manifest.json"), JSON.stringify(appPathsManifest, null, 2));
646
- generatePrerenderManifest(baseDir, pages);
647
- }
648
-
649
- // src/plugin/hooks/server/logging.ts
650
- function logServerRoutes(pages) {
651
- console.log("\n \x1B[1m\x1B[36m\u26A1 Olova Dev Server\x1B[0m\n");
652
- console.log(" \x1B[90m\u25B2 .olova directory created\x1B[0m\n");
653
- console.log(" \x1B[1mRoutes:\x1B[0m");
654
- console.log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
655
- for (const page of pages) {
656
- let icon = "\x1B[33m\u25CB\x1B[0m";
657
- let type = "\x1B[33mCSR\x1B[0m";
658
- if (page.isStatic) {
659
- icon = "\x1B[32m\u25CF\x1B[0m";
660
- type = "\x1B[32mSSG\x1B[0m";
661
- }
662
- console.log(` \u2502 ${icon} ${page.path.padEnd(20)} ${type.padEnd(10)}\u2502`);
663
- }
664
- console.log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
665
- console.log(" \x1B[32m\u25CF\x1B[0m SSG (Static) \x1B[33m\u25CB\x1B[0m CSR (Client)\n");
666
- }
667
-
668
- // src/plugin/html/head.ts
669
- function generateMetaTags(metadata, siteUrl = "", route = "", isCanonicalEnabled = true) {
670
- let metaTags = "";
671
- if (!metadata) return "";
672
- const tags = {
673
- description: metadata.description,
674
- keywords: metadata.keywords,
675
- author: metadata.author,
676
- robots: metadata.robots
677
- };
678
- for (const [name, content] of Object.entries(tags)) {
679
- if (content) metaTags += ` <meta name="${name}" content="${content}" />
680
- `;
681
- }
682
- if (metadata.canonical) {
683
- metaTags += ` <link rel="canonical" href="${metadata.canonical}" />
684
- `;
685
- } else if (isCanonicalEnabled && siteUrl && route) {
686
- const canonicalUrl = `${siteUrl}${route === "/" ? "" : route}`;
687
- metaTags += ` <link rel="canonical" href="${canonicalUrl}" />
688
- `;
689
- }
690
- if (metadata.openGraph) {
691
- for (const [prop, content] of Object.entries(metadata.openGraph)) {
692
- if (content) metaTags += ` <meta property="og:${prop}" content="${content}" />
693
- `;
694
- }
695
- }
696
- if (metadata.twitter) {
697
- for (const [name, content] of Object.entries(metadata.twitter)) {
698
- if (content) metaTags += ` <meta name="twitter:${name}" content="${content}" />
699
- `;
700
- }
701
- }
702
- return metaTags;
703
- }
704
-
705
- // src/hydration/serialization.ts
706
- function safeStringify(data) {
707
- return JSON.stringify(data).replace(/[<>\/\u2028\u2029]/g, (char) => {
708
- switch (char) {
709
- case "<":
710
- return "\\u003c";
711
- case ">":
712
- return "\\u003e";
713
- case "/":
714
- return "\\u002f";
715
- case "\u2028":
716
- return "\\u2028";
717
- case "\u2029":
718
- return "\\u2029";
719
- default:
720
- return char;
721
- }
722
- });
723
- }
724
-
725
- // src/hydration/generation.ts
726
- function generateOlovaHydration(data, buildId) {
727
- const meta = data.metadata || {};
728
- const scripts = [];
729
- scripts.push(`<script>self.__olova_f=self.__olova_f||[];function _oF(d){self.__olova_f.push(d)}</script>`);
730
- const routeChunk = {
731
- id: "0",
732
- html: "",
733
- ready: true,
734
- data: {
735
- path: data.route,
736
- params: data.params || {},
737
- pattern: data.route === "/" ? "/" : data.route.replace(/\/[^/]+$/, "/:slug"),
738
- isStatic: data.isStatic ?? true,
739
- buildId
740
- },
741
- order: 0
742
- };
743
- scripts.push(`<script>_oF([0,"R",${safeStringify(routeChunk.data)}])</script>`);
744
- const metadataChunk = {
745
- id: "1",
746
- html: "",
747
- ready: true,
748
- data: {
749
- title: meta.title || "Olova App",
750
- description: meta.description || "",
751
- keywords: Array.isArray(meta.keywords) ? meta.keywords : [],
752
- robots: meta.robots || "index, follow",
753
- canonical: meta.canonical || null,
754
- og: { type: "website", locale: "en_US", ...meta.openGraph || {} },
755
- twitter: { card: "summary_large_image", ...meta.twitter || {} }
756
- },
757
- order: 1
758
- };
759
- scripts.push(`<script>_oF([1,"M",${safeStringify(metadataChunk.data)}])</script>`);
760
- const treeChunk = {
761
- id: "2",
762
- html: "",
763
- ready: true,
764
- data: { layout: "RootLayout", page: "Page", template: null, loading: null, error: null, notFound: null },
765
- order: 2
766
- };
767
- scripts.push(`<script>_oF([2,"T",${safeStringify(treeChunk.data)}])</script>`);
768
- const structuredData = {
769
- id: "3",
770
- html: "",
771
- ready: true,
772
- data: [
773
- { "@context": "https://schema.org", "@type": "WebPage", name: meta.title || "Olova App", description: meta.description || "", url: data.route },
774
- { "@context": "https://schema.org", "@type": "WebApplication", name: "Olova", applicationCategory: "WebApplication", operatingSystem: "Any" }
775
- ],
776
- order: 3
777
- };
778
- scripts.push(`<script>_oF([3,"D",${safeStringify(structuredData.data)}])</script>`);
779
- const assetsChunk = {
780
- id: "4",
781
- html: "",
782
- ready: true,
783
- data: { chunks: data.chunks || [], styles: [], prefetch: (data.chunks || []).slice(0, 5) },
784
- order: 4
785
- };
786
- scripts.push(`<script>_oF([4,"A",${safeStringify(assetsChunk.data)}])</script>`);
787
- const hintsChunk = {
788
- id: "5",
789
- html: "",
790
- ready: true,
791
- data: { dnsPrefetch: ["fonts.googleapis.com"], preconnect: ["https://fonts.googleapis.com"], modulePreload: (data.chunks || []).slice(0, 3) },
792
- order: 5
793
- };
794
- scripts.push(`<script>_oF([5,"H",${safeStringify(hintsChunk.data)}])</script>`);
795
- const stateChunk = {
796
- id: "6",
797
- html: "",
798
- ready: true,
799
- data: { hydrated: false, streaming: false, ready: true, timestamp: Date.now(), version: "1.0.0", buildId },
800
- order: 6
801
- };
802
- scripts.push(`<script>_oF([6,"S",${safeStringify(stateChunk.data)}])</script>`);
803
- scripts.push(`<script>_oF([7,"E",null])</script>`);
804
- const globalPayload = { $route: routeChunk.data, $meta: metadataChunk.data, $tree: treeChunk.data, $schema: structuredData.data, $assets: assetsChunk.data, $hints: hintsChunk.data, $state: stateChunk.data, $build: { id: buildId, version: "1.0.0", timestamp: Date.now(), env: "production" } };
805
- scripts.push(`<script>$OLOVA=${safeStringify(globalPayload)}</script>`);
806
- return scripts.join("");
807
- }
808
- function generateJsonLd(data) {
809
- const meta = data.metadata || {};
810
- const jsonLd = {
811
- "@context": "https://schema.org",
812
- "@graph": [
813
- { "@type": "WebPage", "@id": data.route, name: meta.title || "Olova App", description: meta.description || "", url: data.route, isPartOf: { "@type": "WebSite", name: "Olova App" } },
814
- { "@type": "BreadcrumbList", itemListElement: data.route.split("/").filter(Boolean).map((segment, index, arr) => ({ "@type": "ListItem", position: index + 1, name: segment.charAt(0).toUpperCase() + segment.slice(1), item: "/" + arr.slice(0, index + 1).join("/") })) }
815
- ]
816
- };
817
- if (meta.schema) {
818
- const schemas = Array.isArray(meta.schema) ? meta.schema : [meta.schema];
819
- jsonLd["@graph"].push(...schemas);
820
- }
821
- return `<script type="application/ld+json">${JSON.stringify(jsonLd)}</script>`;
822
- }
823
-
824
- // src/plugin/html/hydration.ts
825
- function handleHtmlHydration(content, pageData, metadata, flightPayload, buildId) {
826
- const hydrationData = {
827
- route: flightPayload?.route || "/",
828
- metadata: {
829
- title: metadata?.title,
830
- description: metadata?.description,
831
- keywords: metadata?.keywords,
832
- robots: metadata?.robots,
833
- canonical: metadata?.canonical,
834
- openGraph: metadata?.openGraph,
835
- twitter: metadata?.twitter,
836
- schema: metadata?.schema
837
- },
838
- params: flightPayload?.params || {},
839
- chunks: [],
840
- isStatic: !!pageData || !!content
841
- };
842
- const flightHydration = generateOlovaHydration(hydrationData, buildId);
843
- const jsonLdScript = generateJsonLd(hydrationData);
844
- const olovaData = {
845
- props: { pageProps: pageData || {} },
846
- page: flightPayload?.route || "/",
847
- query: {},
848
- buildId,
849
- flight: flightPayload || null,
850
- runtimeConfig: {},
851
- isFallback: false,
852
- gsp: !!pageData,
853
- gssp: false
854
- };
855
- const olovaDataScript = `<script id="__OLOVA_DATA__" type="application/json">${JSON.stringify(olovaData).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026").replace(/'/g, "\\u0027")}</script>`;
856
- return { flightHydration, jsonLdScript, olovaDataScript };
857
- }
858
-
859
- // src/plugin/html/preload.ts
860
- function generatePreloadTags(manifest, routePath, scriptPath, cssLinks) {
861
- let preloadTags = "";
862
- if (manifest) {
863
- const frameworkChunks = [manifest.framework.react, manifest.framework.reactDom, manifest.framework.scheduler].filter(Boolean);
864
- for (const chunk of frameworkChunks) preloadTags += ` <link rel="modulepreload" href="/${chunk}" crossorigin />
865
- `;
866
- const routeChunk = manifest.routes[routePath];
867
- if (routeChunk) {
868
- preloadTags += ` <link rel="modulepreload" href="/${routeChunk.chunk}" crossorigin />
869
- `;
870
- for (const css of routeChunk.css) preloadTags += ` <link rel="preload" href="/${css}" as="style" />
871
- `;
872
- for (const dep of routeChunk.dependencies) {
873
- if (dep.priority === "critical" || dep.priority === "high") preloadTags += ` <link rel="modulepreload" href="/${dep.chunk}" crossorigin />
874
- `;
875
- }
876
- }
877
- } else {
878
- if (scriptPath) preloadTags += ` <link rel="modulepreload" href="${scriptPath}" />
879
- `;
880
- cssLinks.forEach((href) => {
881
- preloadTags += ` <link rel="preload" href="${href}" as="style" />
882
- `;
883
- });
884
- }
885
- return preloadTags;
886
- }
887
-
888
- // src/plugin/html/prefetch.ts
889
- function generatePrefetchScript(manifest) {
890
- if (!manifest) return "";
891
- const manifestData = JSON.stringify({
892
- routes: Object.fromEntries(Object.entries(manifest.routes).map(([path18, chunk]) => [path18, { chunk: chunk.chunk, css: chunk.css }])),
893
- framework: manifest.framework
894
- });
895
- return `
896
- <script type="module">
897
- (function(){
898
- const m=${manifestData};
899
- const p=new Set(),q=[],MAX=3;let a=0;
900
- function f(h){
901
- if(p.has(h)||a>=MAX){if(!p.has(h))q.push(h);return}
902
- p.add(h);a++;
903
- const l=document.createElement('link');
904
- l.rel='prefetch';l.href='/'+h;l.as=h.endsWith('.css')?'style':'script';
905
- l.onload=l.onerror=()=>{a--;if(q.length)f(q.shift())};
906
- document.head.appendChild(l);
907
- }
908
- function r(path){
909
- const c=m.routes[path]||m.routes[path.replace(/\\/$/,'')];
910
- if(c){f(c.chunk);c.css.forEach(f)}
911
- }
912
- const obs=new IntersectionObserver(e=>{
913
- e.forEach(en=>{
914
- if(en.isIntersecting){
915
- const h=en.target.getAttribute('href');
916
- if(h&&h.startsWith('/'))r(h);
917
- obs.unobserve(en.target);
918
- }
919
- });
920
- },{rootMargin:'50px'});
921
- function init(){
922
- document.querySelectorAll('a[href^="/"]').forEach(l=>{
923
- if(!l.dataset.noPrefetch){
924
- obs.observe(l);
925
- let t;
926
- l.addEventListener('mouseenter',()=>{t=setTimeout(()=>{
927
- const h=l.getAttribute('href');if(h)r(h);
928
- },100)});
929
- l.addEventListener('mouseleave',()=>clearTimeout(t));
930
- }
931
- });
932
- }
933
- if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init);
934
- else init();
935
- window.addEventListener('olova:navigate',init);
936
- })();
937
- </script>`;
938
- }
939
-
940
- // src/plugin/html/template.ts
941
- function generateHtmlTemplate(content, scriptPath, cssLinks = [], pageData, metadata, flightPayload, olovaConfig, preloadConfig) {
942
- const buildId = Date.now().toString(36);
943
- const siteUrl = olovaConfig?.siteUrl || "";
944
- const route = flightPayload?.route || "/";
945
- const metaTags = generateMetaTags(metadata, siteUrl, route, olovaConfig?.seo?.canonical !== false);
946
- const { flightHydration, jsonLdScript, olovaDataScript } = handleHtmlHydration(content, pageData, metadata, flightPayload, buildId);
947
- const preloadTags = generatePreloadTags(preloadConfig?.manifest, preloadConfig?.routePath || "/", scriptPath, cssLinks);
948
- const cssLinkTags = cssLinks.length > 0 ? cssLinks.map((href) => ` <link rel="stylesheet" href="${href}" />`).join("\n") : "";
949
- const prefetchScript = preloadConfig?.injectPrefetchScript ? generatePrefetchScript(preloadConfig.manifest) : "";
950
- return `<!DOCTYPE html>
951
- <html lang="en">
952
- <head>
953
- <meta charset="UTF-8" />
954
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
955
- <title>${metadata?.title || "Olova App"}</title>
956
- ${metaTags}${preloadTags}${cssLinkTags ? cssLinkTags + "\n" : ""} ${jsonLdScript}
957
- </head>
958
- <body>
959
- <div id="root">${content}</div>
960
- ${olovaDataScript}
961
- ${flightHydration}
962
- <script type="module" src="${scriptPath}"></script>${prefetchScript}
963
- </body>
964
- </html>`;
965
- }
966
-
967
- // src/plugin/hooks/server/middleware.ts
968
- function createSsrMiddleware(server, srcDir, pageRoutes) {
969
- return async (req, res, next) => {
970
- const url = req.url || "";
971
- const shouldSkip = url.includes(".") || url.startsWith("/@") || url.startsWith("/__") || url.startsWith("/node_modules") || url.includes("virtual:") || url.startsWith("/src") || req.method !== "GET";
972
- if (shouldSkip) return next();
973
- const urlPath = url.split("?")[0];
974
- const normalizedPath = urlPath === "/" ? "/" : urlPath.replace(/\/$/, "");
975
- const page = pageRoutes.get(normalizedPath);
976
- const React = await import("react");
977
- let content = "";
978
- let pageMetadata;
979
- if (page) {
980
- try {
981
- const pageModule = await server.ssrLoadModule(page.componentPath);
982
- pageMetadata = pageModule.metadata || pageModule.default.metadata;
983
- const layoutModules = await Promise.all(
984
- (page.layoutPaths || []).map((lp) => server.ssrLoadModule(lp))
985
- );
986
- const Layouts = layoutModules.map((m) => m.default);
987
- if (page.isStatic) {
988
- const { renderToString } = await import("react-dom/server");
989
- const Page = pageModule.default;
990
- let pageContent = React.createElement(Page, null);
991
- for (let i = Layouts.length - 1; i >= 0; i--) {
992
- pageContent = React.createElement(Layouts[i], { children: pageContent });
993
- }
994
- content = renderToString(pageContent);
995
- console.log(` \x1B[32m\u25CF SSG\x1B[0m ${normalizedPath}`);
996
- }
997
- } catch (err) {
998
- if (page.isStatic) console.error(` \x1B[31m\u2717 SSG failed\x1B[0m ${normalizedPath}: ${err.message}`);
999
- }
1000
- }
1001
- const html = generateHtmlTemplate(content, "/src/entry-client.tsx", [], void 0, pageMetadata);
1002
- res.setHeader("Content-Type", "text/html");
1003
- server.transformIndexHtml(url, html).then((transformedHtml) => res.end(transformedHtml)).catch(next);
1004
- };
1005
- }
1006
-
1007
- // src/plugin/hooks/server.ts
1008
- function handleConfigureServer(server) {
1009
- const baseDir = process.cwd();
1010
- const srcDir = path11.resolve(baseDir, "src");
1011
- const userConfig2 = getUserConfig();
1012
- const pages = findPages(srcDir, srcDir, userConfig2);
1013
- setupServerManifests(baseDir, srcDir, pages);
1014
- logServerRoutes(pages);
1015
- const pageRoutes = new Map(pages.map((p) => [p.path, p]));
1016
- server.middlewares.use(createSsrMiddleware(server, srcDir, pageRoutes));
1017
- }
1018
- function handleConfigurePreviewServer(server) {
1019
- server.middlewares.use((req, res, next) => {
1020
- const url = req.url?.split("?")[0];
1021
- if (!url || url === "/" || url.includes(".")) return next();
1022
- const config = getConfig();
1023
- const baseDir = process.cwd();
1024
- const outDir = path11.resolve(baseDir, config.outDir || ".olova/dist");
1025
- try {
1026
- const indexHtml = path11.join(outDir, url, "index.html");
1027
- if (fs8.existsSync(indexHtml)) {
1028
- req.url = url + "/index.html";
1029
- return next();
1030
- }
1031
- const fileHtml = path11.join(outDir, url + ".html");
1032
- if (fs8.existsSync(fileHtml)) {
1033
- req.url = url + ".html";
1034
- return next();
1035
- }
1036
- } catch (e) {
1037
- }
1038
- next();
1039
- });
1040
- }
1041
-
1042
- // src/plugin/hooks/transform.ts
1043
- import path12 from "path";
1044
-
1045
- // src/plugin/constants.ts
1046
- var HTML_MINIFY_OPTIONS = {
1047
- collapseWhitespace: true,
1048
- removeComments: true,
1049
- removeRedundantAttributes: true,
1050
- removeScriptTypeAttributes: true,
1051
- removeStyleLinkTypeAttributes: true,
1052
- useShortDoctype: true,
1053
- minifyCSS: true,
1054
- minifyJS: true,
1055
- sortAttributes: true,
1056
- sortClassName: true
1057
- };
1058
- var ENTRY_CLIENT_CODE = `
1059
- import React from 'react';
1060
- import { createRoot, hydrateRoot } from 'react-dom/client';
1061
- import { Router, HeadProvider } from 'olova/client';
1062
- import { routes } from 'virtual:olova-routes';
1063
- import Layout from '@/layout';
1064
-
1065
- // Global CSS imports (auto-detected from src directory)
1066
- import '@/index.css';
1067
-
1068
- // Chunk manifest for route-based code splitting
1069
- let chunkManifest = null;
1070
-
1071
- async function loadChunkManifest() {
1072
- try {
1073
- const response = await fetch('/_olova/chunks-manifest.json');
1074
- if (response.ok) {
1075
- chunkManifest = await response.json();
1076
- window.__OLOVA_CHUNK_MANIFEST__ = chunkManifest;
1077
- console.log('[Olova] Loaded chunk manifest:', Object.keys(chunkManifest.routes || {}).length, 'routes');
1078
- }
1079
- } catch (error) {
1080
- // Manifest may not exist in dev mode, that's fine
1081
- console.debug('[Olova] Chunk manifest not available (normal in dev mode)');
1082
- }
1083
- }
1084
-
1085
- function getOlovaData() {
1086
- if (typeof document === 'undefined') return null;
1087
- try {
1088
- const script = document.getElementById('__OLOVA_DATA__');
1089
- if (!script) return null;
1090
- return JSON.parse(script.textContent || '{}');
1091
- } catch (error) {
1092
- console.error('[Olova] Failed to parse __OLOVA_DATA__:', error);
1093
- return null;
1094
- }
1095
- }
1096
-
1097
- function getFlightPayload() {
1098
- try {
1099
- const olovaData = getOlovaData();
1100
- if (olovaData?.flight && olovaData.flight.v === 1) {
1101
- return olovaData.flight;
1102
- }
1103
- return null;
1104
- } catch (error) {
1105
- console.error('[Olova] Failed to parse Flight payload:', error);
1106
- return null;
1107
- }
1108
- }
1109
-
1110
- function progressiveHydrate(rootElement, app, payload) {
1111
- try {
1112
- hydrateRoot(rootElement, app, {
1113
- onRecoverableError(error) {
1114
- console.warn('[Olova] Hydration mismatch:', error);
1115
- },
1116
- });
1117
- requestAnimationFrame(() => {
1118
- document.documentElement.classList.add('olova-hydrated');
1119
- window.dispatchEvent(new CustomEvent('olova:ready'));
1120
- });
1121
- } catch (error) {
1122
- console.error('[Olova] Hydration failed:', error);
1123
- createRoot(rootElement).render(app);
1124
- }
1125
- }
1126
-
1127
- // Load chunk manifest early (non-blocking)
1128
- loadChunkManifest();
1129
-
1130
- window.__OLOVA_ROUTES__ = routes;
1131
-
1132
- const App = () => React.createElement(
1133
- HeadProvider,
1134
- null,
1135
- React.createElement(
1136
- Layout,
1137
- null,
1138
- React.createElement(Router, { routes: routes })
1139
- )
1140
- );
1141
-
1142
- const rootElement = document.getElementById('root');
1143
- const flightPayload = getFlightPayload();
1144
- const hasServerContent = rootElement.innerHTML.trim().length > 0;
1145
-
1146
- if (hasServerContent) {
1147
- console.log('[Olova] Hydrating');
1148
- progressiveHydrate(rootElement, React.createElement(App), flightPayload);
1149
- } else {
1150
- console.log('[Olova] Client-side rendering');
1151
- createRoot(rootElement).render(React.createElement(App));
1152
- requestAnimationFrame(() => {
1153
- document.documentElement.classList.add('olova-hydrated');
1154
- window.dispatchEvent(new CustomEvent('olova:ready'));
1155
- });
1156
- }
1157
-
1158
- if (import.meta.hot) {
1159
- import.meta.hot.accept();
1160
- }
1161
- `;
1162
-
1163
- // src/plugin/hooks/transform.ts
1164
- var virtualModuleId = "virtual:olova-routes";
1165
- var resolvedVirtualModuleId = "\0" + virtualModuleId;
1166
- var virtualEntryId = "virtual:olova-entry-client";
1167
- var resolvedVirtualEntryId = "\0" + virtualEntryId;
1168
- function handleResolveId(id) {
1169
- if (id === virtualModuleId) return resolvedVirtualModuleId;
1170
- if (id === virtualEntryId || id === "/src/entry-client.tsx") return resolvedVirtualEntryId;
1171
- return null;
1172
- }
1173
- function handleLoad(id) {
1174
- if (id === resolvedVirtualEntryId) return ENTRY_CLIENT_CODE;
1175
- if (id === resolvedVirtualModuleId) {
1176
- const srcDir = path12.resolve(process.cwd(), "src");
1177
- const userConfig2 = getUserConfig();
1178
- const pages = findPages(srcDir, srcDir, userConfig2);
1179
- const routesCode = pages.map((p) => {
1180
- const importPath = p.componentPath.replace(/\\/g, "/");
1181
- const layouts = p.layoutPaths.map((lp) => `() => import('${lp.replace(/\\/g, "/")}')`).join(", ");
1182
- let extra = "";
1183
- if (p.loadingPath) extra += `, loading: () => import('${p.loadingPath.replace(/\\/g, "/")}')`;
1184
- if (p.errorPath) extra += `, error: () => import('${p.errorPath.replace(/\\/g, "/")}')`;
1185
- if (p.notFoundPath) extra += `, notFound: () => import('${p.notFoundPath.replace(/\\/g, "/")}')`;
1186
- if (p.templatePath) extra += `, template: () => import('${p.templatePath.replace(/\\/g, "/")}')`;
1187
- return `{
1188
- path: '${p.path}',
1189
- component: () => import('${importPath}'),
1190
- layouts: [${layouts}],
1191
- static: ${p.isStatic},
1192
- dynamic: ${p.isDynamic || false}${extra}
1193
- }`;
1194
- }).join(",\n ");
1195
- return `export const routes = [
1196
- ${routesCode}
1197
- ];`;
1198
- }
1199
- return null;
1200
- }
1201
- function handleTransform(code) {
1202
- if (code.includes('"use static"') || code.includes("'use static'")) {
1203
- return code.replace(/['"]use static['"];?/, "");
1204
- }
1205
- return null;
1206
- }
1207
-
1208
- // src/plugin/hooks/bundle.ts
1209
- import path17 from "path";
1210
-
1211
- // src/plugin/ssg/config.ts
1212
- import fs9 from "fs";
1213
- import path13 from "path";
1214
- function discoverEntries(outDir) {
1215
- let jsEntry = "";
1216
- const cssEntries = getCSSForBuild(outDir);
1217
- const chunksDir = path13.join(outDir, "_olova", "static", "chunks");
1218
- if (fs9.existsSync(chunksDir)) {
1219
- const chunks = fs9.readdirSync(chunksDir);
1220
- for (const chunk of chunks) {
1221
- if (chunk.startsWith("main") && chunk.endsWith(".js")) {
1222
- jsEntry = "/_olova/static/chunks/" + chunk;
1223
- break;
1224
- }
1225
- }
1226
- }
1227
- return { jsEntry, cssEntries };
1228
- }
1229
-
1230
- // src/plugin/ssg/seo.ts
1231
- import fs10 from "fs";
1232
- import path14 from "path";
1233
- function generateSeoFiles(outDir, pages, siteUrl, seo) {
1234
- if (!siteUrl) return;
1235
- if (seo?.sitemap !== false) {
1236
- const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
1237
- <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
1238
- ${pages.map((page) => ` <url>
1239
- <loc>${siteUrl}${page.path === "/" ? "" : page.path}</loc>
1240
- <lastmod>${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}</lastmod>
1241
- <changefreq>daily</changefreq>
1242
- <priority>${page.path === "/" ? "1.0" : "0.8"}</priority>
1243
- </url>`).join("\n")}
1244
- </urlset>`;
1245
- fs10.writeFileSync(path14.join(outDir, "sitemap.xml"), sitemap);
1246
- }
1247
- if (seo?.robots !== false) {
1248
- let content = typeof seo?.robots === "object" && seo.robots.rules ? seo.robots.rules : `User-agent: *
1249
- Allow: /
1250
-
1251
- Sitemap: ${siteUrl}/sitemap.xml`;
1252
- if (typeof seo?.robots === "object" && seo.robots.sitemaps) {
1253
- seo.robots.sitemaps.forEach((s) => {
1254
- content += `
1255
- Sitemap: ${s}`;
1256
- });
1257
- }
1258
- fs10.writeFileSync(path14.join(outDir, "robots.txt"), content);
1259
- }
1260
- }
1261
-
1262
- // src/plugin/ssg/renderer.ts
1263
- import fs11 from "fs";
1264
- import path15 from "path";
1265
- import { pathToFileURL as pathToFileURL2 } from "url";
1266
- import { build as viteBuild } from "vite";
1267
- async function renderStaticPage(baseDir, srcDir, page) {
1268
- const tempSSRDir = path15.join(baseDir, ".olova/ssr");
1269
- if (!fs11.existsSync(tempSSRDir)) fs11.mkdirSync(tempSSRDir, { recursive: true });
1270
- const pkgPath = path15.join(tempSSRDir, "package.json");
1271
- if (!fs11.existsSync(pkgPath)) fs11.writeFileSync(pkgPath, JSON.stringify({ type: "module" }));
1272
- const layoutPath = fs11.existsSync(path15.join(srcDir, "layout.tsx")) ? path15.join(srcDir, "layout.tsx") : fs11.existsSync(path15.join(srcDir, "layout.jsx")) ? path15.join(srcDir, "layout.jsx") : null;
1273
- const layoutImport = layoutPath ? `import Layout from '${layoutPath.replace(/\\/g, "/")}';` : "";
1274
- const layoutUsage = layoutPath ? ["<Layout>", "</Layout>"] : ["<>", "</>"];
1275
- const tempEntry = path15.join(tempSSRDir, `entry-${Math.random().toString(36).substring(7)}.tsx`);
1276
- const content = `import React from 'react';
1277
- import { renderToString } from 'react-dom/server';
1278
- ${layoutImport}
1279
- import Page from '${page.componentPath.replace(/\\/g, "/")}';
1280
- export default function render() { return renderToString(${layoutUsage[0]}<Page />${layoutUsage[1]}); }`;
1281
- fs11.writeFileSync(tempEntry, content);
1282
- try {
1283
- await viteBuild({
1284
- configFile: false,
1285
- root: baseDir,
1286
- build: { ssr: true, write: true, outDir: tempSSRDir, emptyOutDir: false, rollupOptions: { input: tempEntry, output: { format: "esm", entryFileNames: "[name].js" }, onwarn: (w, h) => {
1287
- if (w.code !== "MODULE_LEVEL_DIRECTIVE") h(w);
1288
- } } },
1289
- plugins: [{ name: "olova-ssr-transforms", transform: (c) => c.replace(/['"]use static['"];?/, "") }],
1290
- logLevel: "silent"
1291
- });
1292
- const builtPath = tempEntry.replace(".tsx", ".js");
1293
- if (fs11.existsSync(builtPath)) {
1294
- const mod = await import(pathToFileURL2(builtPath).href);
1295
- return { content: mod.default(), metadata: mod.metadata };
1296
- }
1297
- throw new Error("Built artifact not found");
1298
- } finally {
1299
- if (fs11.existsSync(tempEntry)) fs11.unlinkSync(tempEntry);
1300
- const builtPath = tempEntry.replace(".tsx", ".js");
1301
- if (fs11.existsSync(builtPath)) fs11.unlinkSync(builtPath);
1302
- }
1303
- }
1304
-
1305
- // src/plugin/ssg/runner.ts
1306
- import fs12 from "fs";
1307
- import path16 from "path";
1308
- async function runSSG(baseDir, pages, olovaConfig) {
1309
- initCacheDir(baseDir);
1310
- console.log("\n\u{1F4E6} Generating pages...");
1311
- const outDir = path16.resolve(baseDir, olovaConfig.outDir || ".olova/dist");
1312
- const srcDir = path16.resolve(baseDir, "src");
1313
- const { jsEntry, cssEntries } = discoverEntries(outDir);
1314
- const { minify } = await import("html-minifier-terser");
1315
- const srcInDist = path16.join(outDir, "src");
1316
- if (fs12.existsSync(srcInDist)) fs12.rmSync(srcInDist, { recursive: true, force: true });
1317
- if (!fs12.existsSync(outDir)) fs12.mkdirSync(outDir, { recursive: true });
1318
- fs12.writeFileSync(path16.join(outDir, "prerender-manifest.json"), JSON.stringify(generatePrerenderManifest(baseDir, pages), null, 2));
1319
- for (const page of pages) {
1320
- const startTime = Date.now();
1321
- const htmlPath = page.path === "/" ? path16.join(outDir, "index.html") : path16.join(outDir, page.path, "index.html");
1322
- if (page.path !== "/" && !fs12.existsSync(path16.dirname(htmlPath))) fs12.mkdirSync(path16.dirname(htmlPath), { recursive: true });
1323
- let content = "", metadata = void 0;
1324
- if (page.isStatic) {
1325
- try {
1326
- const result = await renderStaticPage(baseDir, srcDir, page);
1327
- content = result.content;
1328
- metadata = result.metadata;
1329
- console.log(` \x1B[32m\u25CF SSG\x1B[0m ${page.path} \x1B[90m(${Date.now() - startTime}ms)\x1B[0m`);
1330
- } catch (err) {
1331
- console.error(` \x1B[31m\u2717 SSG failed\x1B[0m ${page.path}: ${err.message}`);
1332
- }
1333
- }
1334
- const fullHtml = generateHtmlTemplate(content, jsEntry, cssEntries, void 0, metadata, { route: page.path, params: {}, v: 1 }, olovaConfig);
1335
- fs12.writeFileSync(htmlPath, await minify(fullHtml, HTML_MINIFY_OPTIONS));
1336
- }
1337
- const buildManifest = {
1338
- version: Date.now().toString(36),
1339
- buildTime: (/* @__PURE__ */ new Date()).toISOString(),
1340
- pages: pages.map((p) => ({ path: p.path, isStatic: p.isStatic })),
1341
- assets: { main: jsEntry, css: cssEntries }
1342
- };
1343
- fs12.writeFileSync(path16.join(outDir, "build-manifest.json"), JSON.stringify(buildManifest, null, 2));
1344
- generateSeoFiles(outDir, pages, olovaConfig?.siteUrl, olovaConfig?.seo);
1345
- console.log(`
1346
- \u2705 Build complete!
1347
- `);
1348
- }
1349
-
1350
- // src/plugin/hooks/bundle/collection.ts
1351
- function collectAssetsAndChunks(bundle, chunkCollector) {
1352
- const cssFiles = /* @__PURE__ */ new Map();
1353
- for (const [fileName, asset] of Object.entries(bundle)) {
1354
- if (asset.type === "asset" && fileName.endsWith(".css")) {
1355
- const name = asset.name || fileName;
1356
- cssFiles.set(name, fileName);
1357
- }
1358
- if (asset.type === "chunk") {
1359
- const chunk = asset;
1360
- const name = chunk.name || "";
1361
- if (["framework-react", "framework-react-dom", "framework-scheduler"].includes(name)) {
1362
- trackFrameworkChunk(chunkCollector, name, fileName);
1363
- }
1364
- if (name.startsWith("framework-") || name.startsWith("vendor-")) {
1365
- addSharedChunk(chunkCollector, fileName);
1366
- addToChunkGroup(chunkCollector, name.startsWith("framework-") ? "framework" : "vendor", fileName);
1367
- }
1368
- const categories = ["layouts", "components", "shared"];
1369
- for (const cat of categories) {
1370
- if (name.startsWith(`${cat}/`)) addToChunkGroup(chunkCollector, cat, fileName);
1371
- }
1372
- }
1373
- }
1374
- return cssFiles;
1375
- }
1376
-
1377
- // src/plugin/hooks/bundle/mapping.ts
1378
- function mapRoutesToChunks(pages, bundle, chunkCollector, cssFiles) {
1379
- for (const page of pages) {
1380
- const chunkName = `pages/${routePathToChunkName(page.path)}`;
1381
- for (const [fileName, chunk] of Object.entries(bundle)) {
1382
- if (chunk.type === "chunk" && chunk.name === chunkName) {
1383
- const dependencies = [];
1384
- if (chunkCollector.framework.react) dependencies.push({ chunk: chunkCollector.framework.react, priority: "critical" });
1385
- if (chunkCollector.framework.reactDom) dependencies.push({ chunk: chunkCollector.framework.reactDom, priority: "critical" });
1386
- const layoutChunks = chunkCollector.chunkGroups.get("layouts");
1387
- if (layoutChunks) {
1388
- for (const layoutChunk of layoutChunks) dependencies.push({ chunk: layoutChunk, priority: "high" });
1389
- }
1390
- const routeCss = [];
1391
- for (const [_, cssPath] of cssFiles) {
1392
- if (cssPath.includes("app") || cssPath.includes("index") || cssPath.includes("main")) routeCss.push(cssPath);
1393
- }
1394
- addRouteChunk(
1395
- chunkCollector,
1396
- page.path,
1397
- fileName,
1398
- (chunk.code || "").length,
1399
- page.isStatic || false,
1400
- page.isDynamic || false,
1401
- routeCss,
1402
- dependencies,
1403
- page.path === "/" ? "high" : "normal"
1404
- );
1405
- addToChunkGroup(chunkCollector, "pages", fileName);
1406
- break;
1407
- }
1408
- }
1409
- }
1410
- }
1411
-
1412
- // src/plugin/hooks/bundle.ts
1413
- function handleGenerateBundle(bundle, isBuild) {
1414
- for (const fileName of Object.keys(bundle)) {
1415
- if (fileName.startsWith("src/")) delete bundle[fileName];
1416
- }
1417
- if (!isBuild) return createChunkCollector();
1418
- const baseDir = process.cwd();
1419
- const srcDir = path17.resolve(baseDir, "src");
1420
- const userConfig2 = getUserConfig();
1421
- const pages = findPages(srcDir, srcDir, userConfig2);
1422
- const chunkCollector = createChunkCollector();
1423
- const cssFiles = collectAssetsAndChunks(bundle, chunkCollector);
1424
- mapRoutesToChunks(pages, bundle, chunkCollector, cssFiles);
1425
- return chunkCollector;
1426
- }
1427
- async function handleCloseBundle(isBuild, chunkCollector) {
1428
- if (!isBuild) return;
1429
- const baseDir = process.cwd();
1430
- const srcDir = path17.resolve(baseDir, "src");
1431
- const userConfig2 = getUserConfig();
1432
- const pages = findPages(srcDir, srcDir, userConfig2);
1433
- const olovaConfig = getConfig();
1434
- const manifest = generateChunkManifest(chunkCollector);
1435
- const outDir = path17.resolve(baseDir, olovaConfig.outDir || ".olova/dist");
1436
- writeChunkManifest(outDir, manifest);
1437
- await runSSG(baseDir, pages, olovaConfig);
1438
- }
1439
-
1440
- // src/plugin/plugin.ts
1441
- function olova() {
1442
- let isBuild = false;
1443
- let chunkCollector = createChunkCollector();
1444
- return {
1445
- name: "vite-plugin-olova",
1446
- config: () => handleConfig(),
1447
- configResolved(config) {
1448
- isBuild = config.command === "build";
1449
- },
1450
- configureServer: (server) => handleConfigureServer(server),
1451
- resolveId: (id) => handleResolveId(id),
1452
- load: (id) => handleLoad(id),
1453
- transform: (code) => handleTransform(code),
1454
- generateBundle(_, bundle) {
1455
- chunkCollector = handleGenerateBundle(bundle, isBuild);
1456
- },
1457
- configurePreviewServer: (server) => handleConfigurePreviewServer(server),
1458
- closeBundle: () => handleCloseBundle(isBuild, chunkCollector)
1459
- };
1460
- }
1461
-
1462
- // src/plugin/index.ts
1463
- var plugin_default = olova;
1464
- export {
1465
- clearCache,
1466
- collectCSSFiles,
1467
- createDefaultPostCSSConfig,
1468
- createViteCSSConfig,
1469
- plugin_default as default,
1470
- detectPostCSSConfig,
1471
- detectTailwindConfig,
1472
- generateBuildId,
1473
- generateCSSImports,
1474
- generateCSSLinks,
1475
- generateFileHash,
1476
- generatePrerenderManifest,
1477
- getCSSForBuild,
1478
- getCacheAge,
1479
- getCachedData,
1480
- getCachedPage,
1481
- initCacheDir,
1482
- isCSSFile,
1483
- isCSSModule,
1484
- isCacheValid,
1485
- logCSSStatus,
1486
- olova,
1487
- setCachedData,
1488
- setCachedPage
1489
- };
1490
- //# sourceMappingURL=index.js.map