@coherent.js/runtime 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1119 -0
- package/dist/coherent-browser.cjs +304 -0
- package/dist/coherent-browser.cjs.map +7 -0
- package/dist/coherent-browser.js +279 -0
- package/dist/coherent-browser.js.map +7 -0
- package/dist/coherent-edge.cjs +458 -0
- package/dist/coherent-edge.cjs.map +7 -0
- package/dist/coherent-edge.js +430 -0
- package/dist/coherent-edge.js.map +7 -0
- package/dist/coherent-node.cjs +330 -0
- package/dist/coherent-node.cjs.map +7 -0
- package/dist/coherent-node.js +304 -0
- package/dist/coherent-node.js.map +7 -0
- package/dist/coherent-standalone.esm.js +279 -0
- package/dist/coherent-standalone.esm.js.map +7 -0
- package/dist/coherent-standalone.js +2 -0
- package/dist/coherent-standalone.js.map +7 -0
- package/dist/coherent-static.cjs +356 -0
- package/dist/coherent-static.cjs.map +7 -0
- package/dist/coherent-static.js +331 -0
- package/dist/coherent-static.js.map +7 -0
- package/dist/coherent-universal.cjs +3294 -0
- package/dist/coherent-universal.cjs.map +7 -0
- package/dist/coherent-universal.js +3254 -0
- package/dist/coherent-universal.js.map +7 -0
- package/dist/coherent-universal.min.js +2 -0
- package/dist/coherent-universal.min.js.map +7 -0
- package/package.json +92 -0
- package/types/browser.d.ts +2 -0
- package/types/edge.d.ts +2 -0
- package/types/index.d.ts +118 -0
- package/types/static.d.ts +2 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
// src/runtimes/static.js
|
|
2
|
+
import { render } from "@coherent.js/core";
|
|
3
|
+
var StaticRuntime = class _StaticRuntime {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
this.options = {
|
|
6
|
+
outputDir: "dist",
|
|
7
|
+
baseUrl: "",
|
|
8
|
+
generateSitemap: true,
|
|
9
|
+
generateManifest: true,
|
|
10
|
+
minifyHtml: true,
|
|
11
|
+
inlineCSS: false,
|
|
12
|
+
...options
|
|
13
|
+
};
|
|
14
|
+
this.componentRegistry = /* @__PURE__ */ new Map();
|
|
15
|
+
this.pageRegistry = /* @__PURE__ */ new Map();
|
|
16
|
+
this.staticAssets = /* @__PURE__ */ new Map();
|
|
17
|
+
this.generatedPages = /* @__PURE__ */ new Map();
|
|
18
|
+
this.buildStats = {
|
|
19
|
+
startTime: Date.now(),
|
|
20
|
+
pagesGenerated: 0,
|
|
21
|
+
assetsProcessed: 0,
|
|
22
|
+
totalSize: 0,
|
|
23
|
+
errors: []
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// Component management
|
|
27
|
+
registerComponent(name, component, options = {}) {
|
|
28
|
+
this.componentRegistry.set(name, {
|
|
29
|
+
component,
|
|
30
|
+
options
|
|
31
|
+
});
|
|
32
|
+
return component;
|
|
33
|
+
}
|
|
34
|
+
getComponent(name) {
|
|
35
|
+
const registration = this.componentRegistry.get(name);
|
|
36
|
+
return registration ? registration.component : null;
|
|
37
|
+
}
|
|
38
|
+
// Page registration
|
|
39
|
+
addPage(route, component, options = {}) {
|
|
40
|
+
this.pageRegistry.set(route, {
|
|
41
|
+
component: typeof component === "string" ? this.getComponent(component) : component,
|
|
42
|
+
options: {
|
|
43
|
+
title: options.title || "Page",
|
|
44
|
+
description: options.description || "",
|
|
45
|
+
keywords: options.keywords || "",
|
|
46
|
+
generatePath: options.generatePath || this.routeToPath(route),
|
|
47
|
+
props: options.props || {},
|
|
48
|
+
...options
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
routeToPath(route) {
|
|
53
|
+
if (route === "/") return "/index.html";
|
|
54
|
+
if (route.includes(":")) {
|
|
55
|
+
console.warn(`Dynamic route ${route} requires explicit generatePath`);
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return route.endsWith("/") ? `${route}index.html` : `${route}.html`;
|
|
59
|
+
}
|
|
60
|
+
// Static asset management
|
|
61
|
+
addAsset(path, content, options = {}) {
|
|
62
|
+
this.staticAssets.set(path, {
|
|
63
|
+
content,
|
|
64
|
+
type: options.type || this.inferContentType(path),
|
|
65
|
+
minify: options.minify !== false,
|
|
66
|
+
...options
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
inferContentType(path) {
|
|
70
|
+
const ext = path.split(".").pop().toLowerCase();
|
|
71
|
+
const contentTypes = {
|
|
72
|
+
"html": "text/html",
|
|
73
|
+
"css": "text/css",
|
|
74
|
+
"js": "application/javascript",
|
|
75
|
+
"json": "application/json",
|
|
76
|
+
"png": "image/png",
|
|
77
|
+
"jpg": "image/jpeg",
|
|
78
|
+
"jpeg": "image/jpeg",
|
|
79
|
+
"gif": "image/gif",
|
|
80
|
+
"svg": "image/svg+xml",
|
|
81
|
+
"ico": "image/x-icon"
|
|
82
|
+
};
|
|
83
|
+
return contentTypes[ext] || "text/plain";
|
|
84
|
+
}
|
|
85
|
+
// HTML template generation
|
|
86
|
+
generateHtmlDocument(content, options = {}) {
|
|
87
|
+
const {
|
|
88
|
+
title = "Coherent.js App",
|
|
89
|
+
description = "",
|
|
90
|
+
keywords = "",
|
|
91
|
+
lang = "en",
|
|
92
|
+
charset = "utf-8",
|
|
93
|
+
viewport = "width=device-width, initial-scale=1",
|
|
94
|
+
favicon = "/favicon.ico",
|
|
95
|
+
styles = [],
|
|
96
|
+
scripts = [],
|
|
97
|
+
meta = [],
|
|
98
|
+
bodyClass = "",
|
|
99
|
+
hydrate = false,
|
|
100
|
+
componentName = null,
|
|
101
|
+
componentProps = {}
|
|
102
|
+
} = options;
|
|
103
|
+
const metaTags = [
|
|
104
|
+
`<meta charset="${charset}">`,
|
|
105
|
+
`<meta name="viewport" content="${viewport}">`,
|
|
106
|
+
description && `<meta name="description" content="${description}">`,
|
|
107
|
+
keywords && `<meta name="keywords" content="${keywords}">`,
|
|
108
|
+
...meta.map((m) => typeof m === "string" ? m : `<meta ${Object.entries(m).map(([k, v]) => `${k}="${v}"`).join(" ")}>`)
|
|
109
|
+
].filter(Boolean).join("\n ");
|
|
110
|
+
const styleTags = styles.map(
|
|
111
|
+
(style) => typeof style === "string" ? style.startsWith("<") ? style : `<link rel="stylesheet" href="${style}">` : `<style>${style.content}</style>`
|
|
112
|
+
).join("\n ");
|
|
113
|
+
const scriptTags = [
|
|
114
|
+
...scripts.map(
|
|
115
|
+
(script) => typeof script === "string" ? script.startsWith("<") ? script : `<script src="${script}"></script>` : `<script>${script.content}</script>`
|
|
116
|
+
),
|
|
117
|
+
// Add hydration script if enabled
|
|
118
|
+
hydrate && this.generateHydrationScript(componentName, componentProps)
|
|
119
|
+
].filter(Boolean).join("\n ");
|
|
120
|
+
return `<!DOCTYPE html>
|
|
121
|
+
<html lang="${lang}">
|
|
122
|
+
<head>
|
|
123
|
+
${metaTags}
|
|
124
|
+
<title>${this.escapeHtml(title)}</title>
|
|
125
|
+
<link rel="icon" href="${favicon}">
|
|
126
|
+
${styleTags}
|
|
127
|
+
</head>
|
|
128
|
+
<body${bodyClass ? ` class="${bodyClass}"` : ""}>
|
|
129
|
+
${content}
|
|
130
|
+
${scriptTags}
|
|
131
|
+
</body>
|
|
132
|
+
</html>`;
|
|
133
|
+
}
|
|
134
|
+
generateHydrationScript(componentName) {
|
|
135
|
+
if (!componentName) return "";
|
|
136
|
+
return `
|
|
137
|
+
<script type="module">
|
|
138
|
+
import { autoHydrate } from '/coherent-client.js';
|
|
139
|
+
|
|
140
|
+
// Auto-hydrate on page load
|
|
141
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
142
|
+
autoHydrate({
|
|
143
|
+
'${componentName}': window.components?.['${componentName}']
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
</script>`;
|
|
147
|
+
}
|
|
148
|
+
escapeHtml(text) {
|
|
149
|
+
if (typeof text !== "string") return text;
|
|
150
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
151
|
+
}
|
|
152
|
+
// Build process
|
|
153
|
+
async build() {
|
|
154
|
+
this.buildStats.startTime = Date.now();
|
|
155
|
+
console.log("\u{1F3D7}\uFE0F Starting static site generation...");
|
|
156
|
+
try {
|
|
157
|
+
await this.generatePages();
|
|
158
|
+
await this.processAssets();
|
|
159
|
+
if (this.options.generateSitemap) {
|
|
160
|
+
await this.generateSitemap();
|
|
161
|
+
}
|
|
162
|
+
if (this.options.generateManifest) {
|
|
163
|
+
await this.generateManifest();
|
|
164
|
+
}
|
|
165
|
+
const buildTime = Date.now() - this.buildStats.startTime;
|
|
166
|
+
console.log(`\u2705 Build completed in ${buildTime}ms`);
|
|
167
|
+
console.log(`\u{1F4C4} Generated ${this.buildStats.pagesGenerated} pages`);
|
|
168
|
+
console.log(`\u{1F4E6} Processed ${this.buildStats.assetsProcessed} assets`);
|
|
169
|
+
return this.getBuildResult();
|
|
170
|
+
} catch (error) {
|
|
171
|
+
this.buildStats.errors.push(error);
|
|
172
|
+
console.error("\u274C Build failed:", error);
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async generatePages() {
|
|
177
|
+
for (const [route, pageConfig] of this.pageRegistry) {
|
|
178
|
+
try {
|
|
179
|
+
await this.generatePage(route, pageConfig);
|
|
180
|
+
this.buildStats.pagesGenerated++;
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.error(`Failed to generate page ${route}:`, error);
|
|
183
|
+
this.buildStats.errors.push({ route, error });
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async generatePage(route, pageConfig) {
|
|
188
|
+
const { component, options } = pageConfig;
|
|
189
|
+
if (!component) {
|
|
190
|
+
throw new Error(`No component found for route: ${route}`);
|
|
191
|
+
}
|
|
192
|
+
const vdom = component(options.props || {});
|
|
193
|
+
const content = render(vdom);
|
|
194
|
+
const html = this.generateHtmlDocument(content, {
|
|
195
|
+
title: options.title,
|
|
196
|
+
description: options.description,
|
|
197
|
+
keywords: options.keywords,
|
|
198
|
+
styles: options.styles || [],
|
|
199
|
+
scripts: options.scripts || [],
|
|
200
|
+
meta: options.meta || [],
|
|
201
|
+
hydrate: options.hydrate,
|
|
202
|
+
componentName: options.componentName,
|
|
203
|
+
componentProps: options.props || {},
|
|
204
|
+
...options.htmlOptions
|
|
205
|
+
});
|
|
206
|
+
const finalHtml = this.options.minifyHtml ? this.minifyHtml(html) : html;
|
|
207
|
+
const outputPath = options.generatePath || this.routeToPath(route);
|
|
208
|
+
if (outputPath) {
|
|
209
|
+
this.generatedPages.set(outputPath, {
|
|
210
|
+
html: finalHtml,
|
|
211
|
+
size: finalHtml.length,
|
|
212
|
+
route,
|
|
213
|
+
options
|
|
214
|
+
});
|
|
215
|
+
this.buildStats.totalSize += finalHtml.length;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
minifyHtml(html) {
|
|
219
|
+
return html.replace(/\s+/g, " ").replace(/>\s+</g, "><").replace(/\s+>/g, ">").replace(/<\s+/g, "<").trim();
|
|
220
|
+
}
|
|
221
|
+
async processAssets() {
|
|
222
|
+
for (const [path, asset] of this.staticAssets) {
|
|
223
|
+
try {
|
|
224
|
+
let content = asset.content;
|
|
225
|
+
if (asset.minify) {
|
|
226
|
+
content = this.minifyAsset(content, asset.type);
|
|
227
|
+
}
|
|
228
|
+
this.generatedPages.set(path, {
|
|
229
|
+
content,
|
|
230
|
+
type: asset.type,
|
|
231
|
+
size: content.length
|
|
232
|
+
});
|
|
233
|
+
this.buildStats.assetsProcessed++;
|
|
234
|
+
this.buildStats.totalSize += content.length;
|
|
235
|
+
} catch (error) {
|
|
236
|
+
console.error(`Failed to process asset ${path}:`, error);
|
|
237
|
+
this.buildStats.errors.push({ path, error });
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
minifyAsset(content, type) {
|
|
242
|
+
switch (type) {
|
|
243
|
+
case "text/css":
|
|
244
|
+
return content.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s+/g, " ").replace(/;\s*}/g, "}").replace(/\s*{\s*/g, "{").replace(/;\s*/g, ";").trim();
|
|
245
|
+
case "application/javascript":
|
|
246
|
+
return content.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "").replace(/\s+/g, " ").replace(/\s*([{}();,])\s*/g, "$1").trim();
|
|
247
|
+
default:
|
|
248
|
+
return content;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
async generateSitemap() {
|
|
252
|
+
const pages = Array.from(this.generatedPages.keys()).filter((path) => path.endsWith(".html"));
|
|
253
|
+
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
|
|
254
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
255
|
+
${pages.map((path) => ` <url>
|
|
256
|
+
<loc>${this.options.baseUrl}${path.replace("/index.html", "/")}</loc>
|
|
257
|
+
<lastmod>${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}</lastmod>
|
|
258
|
+
</url>`).join("\n")}
|
|
259
|
+
</urlset>`;
|
|
260
|
+
this.generatedPages.set("/sitemap.xml", {
|
|
261
|
+
content: sitemap,
|
|
262
|
+
type: "application/xml",
|
|
263
|
+
size: sitemap.length
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
async generateManifest() {
|
|
267
|
+
const manifest = {
|
|
268
|
+
name: this.options.name || "Coherent.js App",
|
|
269
|
+
short_name: this.options.shortName || "App",
|
|
270
|
+
description: this.options.description || "",
|
|
271
|
+
start_url: "/",
|
|
272
|
+
display: "standalone",
|
|
273
|
+
theme_color: this.options.themeColor || "#000000",
|
|
274
|
+
background_color: this.options.backgroundColor || "#ffffff",
|
|
275
|
+
icons: this.options.icons || []
|
|
276
|
+
};
|
|
277
|
+
const manifestJson = JSON.stringify(manifest, null, 2);
|
|
278
|
+
this.generatedPages.set("/manifest.json", {
|
|
279
|
+
content: manifestJson,
|
|
280
|
+
type: "application/json",
|
|
281
|
+
size: manifestJson.length
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
getBuildResult() {
|
|
285
|
+
return {
|
|
286
|
+
pages: this.generatedPages,
|
|
287
|
+
stats: {
|
|
288
|
+
...this.buildStats,
|
|
289
|
+
buildTime: Date.now() - this.buildStats.startTime
|
|
290
|
+
},
|
|
291
|
+
success: this.buildStats.errors.length === 0
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
// Create static app factory
|
|
295
|
+
createApp() {
|
|
296
|
+
return {
|
|
297
|
+
// Component registration
|
|
298
|
+
component: (name, component, opts) => this.registerComponent(name, component, opts),
|
|
299
|
+
// Page registration
|
|
300
|
+
page: (route, component, opts) => this.addPage(route, component, opts),
|
|
301
|
+
// Asset management
|
|
302
|
+
asset: (path, content, opts) => this.addAsset(path, content, opts),
|
|
303
|
+
// Build process
|
|
304
|
+
build: () => this.build(),
|
|
305
|
+
// Utilities
|
|
306
|
+
getRuntime: () => this,
|
|
307
|
+
getStats: () => this.buildStats,
|
|
308
|
+
getPages: () => Array.from(this.pageRegistry.keys()),
|
|
309
|
+
getAssets: () => Array.from(this.staticAssets.keys())
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
// Static factory methods
|
|
313
|
+
static createApp(options = {}) {
|
|
314
|
+
const runtime = new _StaticRuntime(options);
|
|
315
|
+
return runtime.createApp(options);
|
|
316
|
+
}
|
|
317
|
+
static async buildSite(pages = {}, components = {}, options = {}) {
|
|
318
|
+
const runtime = new _StaticRuntime(options);
|
|
319
|
+
Object.entries(components).forEach(([name, component]) => {
|
|
320
|
+
runtime.registerComponent(name, component);
|
|
321
|
+
});
|
|
322
|
+
Object.entries(pages).forEach(([route, config]) => {
|
|
323
|
+
runtime.addPage(route, config.component, config.options);
|
|
324
|
+
});
|
|
325
|
+
return await runtime.build();
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
export {
|
|
329
|
+
StaticRuntime
|
|
330
|
+
};
|
|
331
|
+
//# sourceMappingURL=coherent-static.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/runtimes/static.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * Static Runtime - For static site generation\n * Pre-renders components to static HTML files\n */\n\nimport { render } from '@coherent.js/core';\n\nexport class StaticRuntime {\n constructor(options = {}) {\n this.options = {\n outputDir: 'dist',\n baseUrl: '',\n generateSitemap: true,\n generateManifest: true,\n minifyHtml: true,\n inlineCSS: false,\n ...options\n };\n \n this.componentRegistry = new Map();\n this.pageRegistry = new Map();\n this.staticAssets = new Map();\n this.generatedPages = new Map();\n \n // Track build statistics\n this.buildStats = {\n startTime: Date.now(),\n pagesGenerated: 0,\n assetsProcessed: 0,\n totalSize: 0,\n errors: []\n };\n }\n\n // Component management\n registerComponent(name, component, options = {}) {\n this.componentRegistry.set(name, {\n component,\n options\n });\n return component;\n }\n\n getComponent(name) {\n const registration = this.componentRegistry.get(name);\n return registration ? registration.component : null;\n }\n\n // Page registration\n addPage(route, component, options = {}) {\n this.pageRegistry.set(route, {\n component: typeof component === 'string' ? this.getComponent(component) : component,\n options: {\n title: options.title || 'Page',\n description: options.description || '',\n keywords: options.keywords || '',\n generatePath: options.generatePath || this.routeToPath(route),\n props: options.props || {},\n ...options\n }\n });\n }\n\n routeToPath(route) {\n // Convert route pattern to static path\n // /users/:id -> /users/[id] (or similar static pattern)\n if (route === '/') return '/index.html';\n \n // Handle dynamic routes\n if (route.includes(':')) {\n // For static generation, dynamic routes need explicit paths\n console.warn(`Dynamic route ${route} requires explicit generatePath`);\n return null;\n }\n \n return route.endsWith('/') ? `${route}index.html` : `${route}.html`;\n }\n\n // Static asset management\n addAsset(path, content, options = {}) {\n this.staticAssets.set(path, {\n content,\n type: options.type || this.inferContentType(path),\n minify: options.minify !== false,\n ...options\n });\n }\n\n inferContentType(path) {\n const ext = path.split('.').pop().toLowerCase();\n const contentTypes = {\n 'html': 'text/html',\n 'css': 'text/css',\n 'js': 'application/javascript',\n 'json': 'application/json',\n 'png': 'image/png',\n 'jpg': 'image/jpeg',\n 'jpeg': 'image/jpeg',\n 'gif': 'image/gif',\n 'svg': 'image/svg+xml',\n 'ico': 'image/x-icon'\n };\n return contentTypes[ext] || 'text/plain';\n }\n\n // HTML template generation\n generateHtmlDocument(content, options = {}) {\n const {\n title = 'Coherent.js App',\n description = '',\n keywords = '',\n lang = 'en',\n charset = 'utf-8',\n viewport = 'width=device-width, initial-scale=1',\n favicon = '/favicon.ico',\n styles = [],\n scripts = [],\n meta = [],\n bodyClass = '',\n hydrate = false,\n componentName = null,\n componentProps = {}\n } = options;\n\n const metaTags = [\n `<meta charset=\"${charset}\">`,\n `<meta name=\"viewport\" content=\"${viewport}\">`,\n description && `<meta name=\"description\" content=\"${description}\">`,\n keywords && `<meta name=\"keywords\" content=\"${keywords}\">`,\n ...meta.map(m => typeof m === 'string' ? m : `<meta ${Object.entries(m).map(([k, v]) => `${k}=\"${v}\"`).join(' ')}>`)\n ].filter(Boolean).join('\\n ');\n\n const styleTags = styles.map(style => \n typeof style === 'string' \n ? style.startsWith('<') ? style : `<link rel=\"stylesheet\" href=\"${style}\">`\n : `<style>${style.content}</style>`\n ).join('\\n ');\n\n const scriptTags = [\n ...scripts.map(script => \n typeof script === 'string' \n ? script.startsWith('<') ? script : `<script src=\"${script}\"></script>`\n : `<script>${script.content}</script>`\n ),\n // Add hydration script if enabled\n hydrate && this.generateHydrationScript(componentName, componentProps)\n ].filter(Boolean).join('\\n ');\n\n return `<!DOCTYPE html>\n<html lang=\"${lang}\">\n<head>\n ${metaTags}\n <title>${this.escapeHtml(title)}</title>\n <link rel=\"icon\" href=\"${favicon}\">\n ${styleTags}\n</head>\n<body${bodyClass ? ` class=\"${bodyClass}\"` : ''}>\n ${content}\n ${scriptTags}\n</body>\n</html>`;\n }\n\n generateHydrationScript(componentName) {\n if (!componentName) return '';\n \n return `\n <script type=\"module\">\n import { autoHydrate } from '/coherent-client.js';\n \n // Auto-hydrate on page load\n document.addEventListener('DOMContentLoaded', () => {\n autoHydrate({\n '${componentName}': window.components?.['${componentName}']\n });\n });\n </script>`;\n }\n\n escapeHtml(text) {\n if (typeof text !== 'string') return text;\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n }\n\n // Build process\n async build() {\n this.buildStats.startTime = Date.now();\n console.log('\uD83C\uDFD7\uFE0F Starting static site generation...');\n\n try {\n // Generate all pages\n await this.generatePages();\n \n // Process static assets\n await this.processAssets();\n \n // Generate additional files\n if (this.options.generateSitemap) {\n await this.generateSitemap();\n }\n \n if (this.options.generateManifest) {\n await this.generateManifest();\n }\n \n // Generate build report\n const buildTime = Date.now() - this.buildStats.startTime;\n console.log(`\u2705 Build completed in ${buildTime}ms`);\n console.log(`\uD83D\uDCC4 Generated ${this.buildStats.pagesGenerated} pages`);\n console.log(`\uD83D\uDCE6 Processed ${this.buildStats.assetsProcessed} assets`);\n \n return this.getBuildResult();\n \n } catch (error) {\n this.buildStats.errors.push(error);\n console.error('\u274C Build failed:', error);\n throw error;\n }\n }\n\n async generatePages() {\n for (const [route, pageConfig] of this.pageRegistry) {\n try {\n await this.generatePage(route, pageConfig);\n this.buildStats.pagesGenerated++;\n } catch (error) {\n console.error(`Failed to generate page ${route}:`, error);\n this.buildStats.errors.push({ route, error });\n }\n }\n }\n\n async generatePage(route, pageConfig) {\n const { component, options } = pageConfig;\n \n if (!component) {\n throw new Error(`No component found for route: ${route}`);\n }\n\n // Render component to HTML\n const vdom = component(options.props || {});\n const content = render(vdom);\n \n // Wrap in HTML document\n const html = this.generateHtmlDocument(content, {\n title: options.title,\n description: options.description,\n keywords: options.keywords,\n styles: options.styles || [],\n scripts: options.scripts || [],\n meta: options.meta || [],\n hydrate: options.hydrate,\n componentName: options.componentName,\n componentProps: options.props || {},\n ...options.htmlOptions\n });\n\n // Minify if enabled\n const finalHtml = this.options.minifyHtml ? this.minifyHtml(html) : html;\n \n // Store generated page\n const outputPath = options.generatePath || this.routeToPath(route);\n if (outputPath) {\n this.generatedPages.set(outputPath, {\n html: finalHtml,\n size: finalHtml.length,\n route,\n options\n });\n \n this.buildStats.totalSize += finalHtml.length;\n }\n }\n\n minifyHtml(html) {\n // Basic HTML minification\n return html\n .replace(/\\s+/g, ' ')\n .replace(/>\\s+</g, '><')\n .replace(/\\s+>/g, '>')\n .replace(/<\\s+/g, '<')\n .trim();\n }\n\n async processAssets() {\n for (const [path, asset] of this.staticAssets) {\n try {\n let content = asset.content;\n \n // Process asset based on type\n if (asset.minify) {\n content = this.minifyAsset(content, asset.type);\n }\n \n // Store processed asset\n this.generatedPages.set(path, {\n content,\n type: asset.type,\n size: content.length\n });\n \n this.buildStats.assetsProcessed++;\n this.buildStats.totalSize += content.length;\n \n } catch (error) {\n console.error(`Failed to process asset ${path}:`, error);\n this.buildStats.errors.push({ path, error });\n }\n }\n }\n\n minifyAsset(content, type) {\n switch (type) {\n case 'text/css':\n return content\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n .replace(/\\s+/g, ' ')\n .replace(/;\\s*}/g, '}')\n .replace(/\\s*{\\s*/g, '{')\n .replace(/;\\s*/g, ';')\n .trim();\n \n case 'application/javascript':\n // Basic JS minification (in production, use a proper minifier)\n return content\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n .replace(/\\/\\/.*$/gm, '')\n .replace(/\\s+/g, ' ')\n .replace(/\\s*([{}();,])\\s*/g, '$1')\n .trim();\n \n default:\n return content;\n }\n }\n\n async generateSitemap() {\n const pages = Array.from(this.generatedPages.keys())\n .filter(path => path.endsWith('.html'));\n \n const sitemap = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n${pages.map(path => ` <url>\n <loc>${this.options.baseUrl}${path.replace('/index.html', '/')}</loc>\n <lastmod>${new Date().toISOString().split('T')[0]}</lastmod>\n </url>`).join('\\n')}\n</urlset>`;\n\n this.generatedPages.set('/sitemap.xml', {\n content: sitemap,\n type: 'application/xml',\n size: sitemap.length\n });\n }\n\n async generateManifest() {\n const manifest = {\n name: this.options.name || 'Coherent.js App',\n short_name: this.options.shortName || 'App',\n description: this.options.description || '',\n start_url: '/',\n display: 'standalone',\n theme_color: this.options.themeColor || '#000000',\n background_color: this.options.backgroundColor || '#ffffff',\n icons: this.options.icons || []\n };\n\n const manifestJson = JSON.stringify(manifest, null, 2);\n \n this.generatedPages.set('/manifest.json', {\n content: manifestJson,\n type: 'application/json',\n size: manifestJson.length\n });\n }\n\n getBuildResult() {\n return {\n pages: this.generatedPages,\n stats: {\n ...this.buildStats,\n buildTime: Date.now() - this.buildStats.startTime\n },\n success: this.buildStats.errors.length === 0\n };\n }\n\n // Create static app factory\n createApp() {\n return {\n // Component registration\n component: (name, component, opts) => this.registerComponent(name, component, opts),\n \n // Page registration\n page: (route, component, opts) => this.addPage(route, component, opts),\n \n // Asset management\n asset: (path, content, opts) => this.addAsset(path, content, opts),\n \n // Build process\n build: () => this.build(),\n \n // Utilities\n getRuntime: () => this,\n getStats: () => this.buildStats,\n getPages: () => Array.from(this.pageRegistry.keys()),\n getAssets: () => Array.from(this.staticAssets.keys())\n };\n }\n\n // Static factory methods\n static createApp(options = {}) {\n const runtime = new StaticRuntime(options);\n return runtime.createApp(options);\n }\n\n static async buildSite(pages = {}, components = {}, options = {}) {\n const runtime = new StaticRuntime(options);\n \n // Register components\n Object.entries(components).forEach(([name, component]) => {\n runtime.registerComponent(name, component);\n });\n \n // Register pages\n Object.entries(pages).forEach(([route, config]) => {\n runtime.addPage(route, config.component, config.options);\n });\n \n return await runtime.build();\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|