@absolutejs/absolute 0.19.0-beta.316 → 0.19.0-beta.318
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/dist/{Island-p1b3nrte.svelte → Island-c38gqq3d.svelte} +3 -3
- package/dist/angular/browser.js.map +2 -2
- package/dist/angular/index.js.map +2 -2
- package/dist/build.js +20 -17
- package/dist/build.js.map +5 -5
- package/dist/index.js +1789 -1784
- package/dist/index.js.map +21 -21
- package/dist/react/index.js.map +1 -1
- package/dist/src/angular/Island.browser.d.ts +4 -4
- package/dist/src/angular/Island.d.ts +4 -4
- package/dist/src/build/staticIslandPages.d.ts +3 -0
- package/dist/src/react/Island.d.ts +2 -2
- package/dist/svelte/components/Island.svelte +3 -3
- package/dist/svelte/components/Island.svelte.d.ts +2 -2
- package/dist/svelte/index.js +1 -1
- package/dist/types/globals.d.ts +20 -0
- package/dist/types/island.d.ts +0 -7
- package/dist/vue/browser.js.map +2 -2
- package/dist/vue/index.js.map +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -203,1389 +203,9 @@ var defineIslandRegistry = (registry) => registry, defineIslandComponent = (comp
|
|
|
203
203
|
};
|
|
204
204
|
var init_islands = () => {};
|
|
205
205
|
|
|
206
|
-
// src/core/islandPageContext.ts
|
|
207
|
-
var BOOTSTRAP_MANIFEST_KEY = "BootstrapClient", ISLAND_MARKER = 'data-island="true"', MANIFEST_MARKER = "__ABSOLUTE_MANIFEST__", ISLAND_STATE_MARKER = "__ABS_ISLAND_STATE__", buildIslandsHeadMarkup = (manifest) => {
|
|
208
|
-
const manifestScript = `<script>window.__ABSOLUTE_MANIFEST__ = ${JSON.stringify(manifest)}</script>`;
|
|
209
|
-
const islandStateScript = "<script>window.__ABS_ISLAND_STATE__ = window.__ABS_ISLAND_STATE__ ?? {}</script>";
|
|
210
|
-
const bootstrapPath = manifest[BOOTSTRAP_MANIFEST_KEY];
|
|
211
|
-
const bootstrapScript = bootstrapPath ? `<script type="module" src="${bootstrapPath}"></script>` : "";
|
|
212
|
-
return `${manifestScript}${islandStateScript}${bootstrapScript}`;
|
|
213
|
-
}, injectHeadMarkup = (html, markup) => {
|
|
214
|
-
const closingHeadIndex = html.indexOf("</head>");
|
|
215
|
-
if (closingHeadIndex >= 0) {
|
|
216
|
-
return `${html.slice(0, closingHeadIndex)}${markup}${html.slice(closingHeadIndex)}`;
|
|
217
|
-
}
|
|
218
|
-
const openingBodyIndex = html.indexOf("<body");
|
|
219
|
-
if (openingBodyIndex >= 0) {
|
|
220
|
-
const bodyStart = html.indexOf(">", openingBodyIndex);
|
|
221
|
-
if (bodyStart >= 0) {
|
|
222
|
-
return `${html.slice(0, openingBodyIndex)}<head>${markup}</head>${html.slice(openingBodyIndex)}`;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
return `<!DOCTYPE html><html><head>${markup}</head><body>${html}</body></html>`;
|
|
226
|
-
}, setCurrentIslandManifest = (manifest) => {
|
|
227
|
-
globalThis.__absoluteManifest = manifest;
|
|
228
|
-
}, htmlContainsIslands = (html) => html.includes(ISLAND_MARKER), injectIslandPageContext = (html, options) => {
|
|
229
|
-
const manifest = globalThis.__absoluteManifest;
|
|
230
|
-
const hasIslands = options?.hasIslands ?? htmlContainsIslands(html);
|
|
231
|
-
if (!manifest || !hasIslands) {
|
|
232
|
-
return html;
|
|
233
|
-
}
|
|
234
|
-
if (html.includes(MANIFEST_MARKER) || html.includes(ISLAND_STATE_MARKER)) {
|
|
235
|
-
return html;
|
|
236
|
-
}
|
|
237
|
-
return injectHeadMarkup(html, buildIslandsHeadMarkup(manifest));
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
// src/utils/ssrErrorPage.ts
|
|
241
|
-
var ssrErrorPage = (framework, error) => {
|
|
242
|
-
const frameworkColors = {
|
|
243
|
-
angular: "#dd0031",
|
|
244
|
-
html: "#e34c26",
|
|
245
|
-
htmx: "#1a365d",
|
|
246
|
-
react: "#61dafb",
|
|
247
|
-
svelte: "#ff3e00",
|
|
248
|
-
vue: "#42b883"
|
|
249
|
-
};
|
|
250
|
-
const accent = frameworkColors[framework] ?? "#94a3b8";
|
|
251
|
-
const label = framework.charAt(0).toUpperCase() + framework.slice(1);
|
|
252
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
253
|
-
return `<!DOCTYPE html>
|
|
254
|
-
<html>
|
|
255
|
-
<head>
|
|
256
|
-
<meta charset="utf-8">
|
|
257
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
258
|
-
<title>SSR Error - AbsoluteJS</title>
|
|
259
|
-
<style>
|
|
260
|
-
*{margin:0;padding:0;box-sizing:border-box}
|
|
261
|
-
body{min-height:100vh;background:linear-gradient(135deg,rgba(15,23,42,0.98) 0%,rgba(30,41,59,0.98) 100%);color:#e2e8f0;font-family:"JetBrains Mono","Fira Code",ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:14px;line-height:1.6;display:flex;align-items:flex-start;justify-content:center;padding:32px}
|
|
262
|
-
.card{max-width:720px;width:100%;background:rgba(30,41,59,0.6);border:1px solid rgba(71,85,105,0.5);border-radius:16px;box-shadow:0 25px 50px -12px rgba(0,0,0,0.5),0 0 0 1px rgba(255,255,255,0.05);overflow:hidden}
|
|
263
|
-
.header{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:20px 24px;background:rgba(15,23,42,0.5);border-bottom:1px solid rgba(71,85,105,0.4)}
|
|
264
|
-
.brand{font-weight:700;font-size:20px;color:#fff;letter-spacing:-0.02em}
|
|
265
|
-
.badge{padding:5px 10px;border-radius:8px;font-size:12px;font-weight:600;background:${accent};color:#fff;opacity:0.95;box-shadow:0 2px 4px rgba(0,0,0,0.2)}
|
|
266
|
-
.kind{color:#94a3b8;font-size:13px;font-weight:500}
|
|
267
|
-
.content{padding:24px}
|
|
268
|
-
.label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.08em;color:#94a3b8;margin-bottom:8px}
|
|
269
|
-
.message{margin:0;padding:16px 20px;background:rgba(239,68,68,0.12);border:1px solid rgba(239,68,68,0.25);border-radius:10px;overflow-x:auto;white-space:pre-wrap;word-break:break-word;color:#fca5a5;font-size:13px;line-height:1.5}
|
|
270
|
-
.hint{margin-top:20px;padding:12px 20px;background:rgba(71,85,105,0.3);border-radius:10px;border:1px solid rgba(71,85,105,0.4);color:#cbd5e1;font-size:13px}
|
|
271
|
-
</style>
|
|
272
|
-
</head>
|
|
273
|
-
<body>
|
|
274
|
-
<div class="card">
|
|
275
|
-
<div class="header">
|
|
276
|
-
<div style="display:flex;align-items:center;gap:12px">
|
|
277
|
-
<span class="brand">AbsoluteJS</span>
|
|
278
|
-
<span class="badge">${label}</span>
|
|
279
|
-
</div>
|
|
280
|
-
<span class="kind">Server Render Error</span>
|
|
281
|
-
</div>
|
|
282
|
-
<div class="content">
|
|
283
|
-
<div class="label">What went wrong</div>
|
|
284
|
-
<pre class="message">${message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")}</pre>
|
|
285
|
-
<div class="hint">A component threw during server-side rendering. Check the terminal for the full stack trace.</div>
|
|
286
|
-
</div>
|
|
287
|
-
</div>
|
|
288
|
-
</body>
|
|
289
|
-
</html>`;
|
|
290
|
-
};
|
|
291
|
-
|
|
292
|
-
// src/utils/stringModifiers.ts
|
|
293
|
-
var normalizeSlug = (str) => str.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-9\-_]+/g, "").replace(/[-_]{2,}/g, "-"), toKebab = (str) => normalizeSlug(str).replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), toPascal = (str) => {
|
|
294
|
-
if (!str.includes("-") && !str.includes("_")) {
|
|
295
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
296
|
-
}
|
|
297
|
-
return normalizeSlug(str).split(/[-_]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase()).join("");
|
|
298
|
-
}, toScreamingSnake = (str) => str.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toUpperCase();
|
|
299
|
-
|
|
300
|
-
// src/utils/resolveConvention.ts
|
|
301
|
-
import { basename } from "path";
|
|
302
|
-
var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boolean(value) && typeof value === "object", getMap = () => {
|
|
303
|
-
const value = Reflect.get(globalThis, CONVENTIONS_KEY);
|
|
304
|
-
if (isConventionsMap(value))
|
|
305
|
-
return value;
|
|
306
|
-
const empty = {};
|
|
307
|
-
return empty;
|
|
308
|
-
}, derivePageName = (pagePath) => {
|
|
309
|
-
const base = basename(pagePath);
|
|
310
|
-
const dotIndex = base.indexOf(".");
|
|
311
|
-
const name = dotIndex > 0 ? base.slice(0, dotIndex) : base;
|
|
312
|
-
return toPascal(name);
|
|
313
|
-
}, resolveErrorConventionPath = (framework, pageName) => {
|
|
314
|
-
const conventions2 = getMap()[framework];
|
|
315
|
-
if (!conventions2)
|
|
316
|
-
return;
|
|
317
|
-
return conventions2.pages?.[pageName]?.error ?? conventions2.defaults?.error;
|
|
318
|
-
}, resolveNotFoundConventionPath = (framework) => getMap()[framework]?.defaults?.notFound, setConventions = (map) => {
|
|
319
|
-
Reflect.set(globalThis, CONVENTIONS_KEY, map);
|
|
320
|
-
}, isDev = () => true, buildErrorProps = (error) => {
|
|
321
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
322
|
-
const stack = isDev() && error instanceof Error ? error.stack : undefined;
|
|
323
|
-
return { error: { message, stack } };
|
|
324
|
-
}, renderReactError = async (conventionPath, errorProps) => {
|
|
325
|
-
const { createElement } = await import("react");
|
|
326
|
-
const { renderToReadableStream } = await import("react-dom/server");
|
|
327
|
-
const mod = await import(conventionPath);
|
|
328
|
-
const [firstKey] = Object.keys(mod);
|
|
329
|
-
const ErrorComponent = mod.default ?? (firstKey ? mod[firstKey] : undefined);
|
|
330
|
-
const element = createElement(ErrorComponent, errorProps);
|
|
331
|
-
const stream = await renderToReadableStream(element);
|
|
332
|
-
return new Response(stream, {
|
|
333
|
-
headers: { "Content-Type": "text/html" },
|
|
334
|
-
status: 500
|
|
335
|
-
});
|
|
336
|
-
}, renderSvelteError = async (conventionPath, errorProps) => {
|
|
337
|
-
const { render } = await import("svelte/server");
|
|
338
|
-
const mod = await import(conventionPath);
|
|
339
|
-
const ErrorComponent = mod.default;
|
|
340
|
-
const { head, body } = render(ErrorComponent, {
|
|
341
|
-
props: errorProps
|
|
342
|
-
});
|
|
343
|
-
const html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;
|
|
344
|
-
return new Response(html, {
|
|
345
|
-
headers: { "Content-Type": "text/html" },
|
|
346
|
-
status: 500
|
|
347
|
-
});
|
|
348
|
-
}, unescapeVueStyles = (ssrBody) => {
|
|
349
|
-
let styles = "";
|
|
350
|
-
const body = ssrBody.replace(/<style>([\s\S]*?)<\/style>/g, (_, css) => {
|
|
351
|
-
styles += `<style>${css.replace(/"/g, '"').replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")}</style>`;
|
|
352
|
-
return "";
|
|
353
|
-
});
|
|
354
|
-
return { body, styles };
|
|
355
|
-
}, renderVueError = async (conventionPath, errorProps) => {
|
|
356
|
-
const { createSSRApp, h } = await import("vue");
|
|
357
|
-
const { renderToString } = await import("vue/server-renderer");
|
|
358
|
-
const mod = await import(conventionPath);
|
|
359
|
-
const ErrorComponent = mod.default;
|
|
360
|
-
const app = createSSRApp({
|
|
361
|
-
render: () => h(ErrorComponent, errorProps)
|
|
362
|
-
});
|
|
363
|
-
const rawBody = await renderToString(app);
|
|
364
|
-
const { styles, body } = unescapeVueStyles(rawBody);
|
|
365
|
-
const html = `<!DOCTYPE html><html><head>${styles}</head><body><div id="root">${body}</div></body></html>`;
|
|
366
|
-
return new Response(html, {
|
|
367
|
-
headers: { "Content-Type": "text/html" },
|
|
368
|
-
status: 500
|
|
369
|
-
});
|
|
370
|
-
}, renderAngularError = async (conventionPath, errorProps) => {
|
|
371
|
-
const mod = await import(conventionPath);
|
|
372
|
-
const renderError = mod.default ?? mod.renderError;
|
|
373
|
-
if (typeof renderError !== "function")
|
|
374
|
-
return null;
|
|
375
|
-
const html = renderError(errorProps);
|
|
376
|
-
return new Response(html, {
|
|
377
|
-
headers: { "Content-Type": "text/html" },
|
|
378
|
-
status: 500
|
|
379
|
-
});
|
|
380
|
-
}, logConventionRenderError = (framework, label, renderError) => {
|
|
381
|
-
const message = renderError instanceof Error ? renderError.message : "";
|
|
382
|
-
if (message.includes("Cannot find module") || message.includes("Cannot find package") || message.includes("not found in module")) {
|
|
383
|
-
console.error(`[SSR] Convention ${label} page for ${framework} failed: missing framework package. Ensure the ${framework} runtime is installed (e.g. bun add ${framework === "react" ? "react react-dom" : framework}).`);
|
|
384
|
-
return;
|
|
385
|
-
}
|
|
386
|
-
console.error(`[SSR] Failed to render ${framework} convention ${label} page:`, renderError);
|
|
387
|
-
}, ERROR_RENDERERS, renderConventionError = async (framework, pageName, error) => {
|
|
388
|
-
const conventionPath = resolveErrorConventionPath(framework, pageName);
|
|
389
|
-
if (!conventionPath)
|
|
390
|
-
return null;
|
|
391
|
-
const errorProps = buildErrorProps(error);
|
|
392
|
-
const renderer = ERROR_RENDERERS[framework];
|
|
393
|
-
if (!renderer)
|
|
394
|
-
return null;
|
|
395
|
-
try {
|
|
396
|
-
return await renderer(conventionPath, errorProps);
|
|
397
|
-
} catch (renderError) {
|
|
398
|
-
logConventionRenderError(framework, "error", renderError);
|
|
399
|
-
}
|
|
400
|
-
return null;
|
|
401
|
-
}, renderReactNotFound = async (conventionPath) => {
|
|
402
|
-
const { createElement } = await import("react");
|
|
403
|
-
const { renderToReadableStream } = await import("react-dom/server");
|
|
404
|
-
const mod = await import(conventionPath);
|
|
405
|
-
const [nfKey] = Object.keys(mod);
|
|
406
|
-
const NotFoundComponent = mod.default ?? (nfKey ? mod[nfKey] : undefined);
|
|
407
|
-
const element = createElement(NotFoundComponent);
|
|
408
|
-
const stream = await renderToReadableStream(element);
|
|
409
|
-
return new Response(stream, {
|
|
410
|
-
headers: { "Content-Type": "text/html" },
|
|
411
|
-
status: 404
|
|
412
|
-
});
|
|
413
|
-
}, renderSvelteNotFound = async (conventionPath) => {
|
|
414
|
-
const { render } = await import("svelte/server");
|
|
415
|
-
const mod = await import(conventionPath);
|
|
416
|
-
const NotFoundComponent = mod.default;
|
|
417
|
-
const { head, body } = render(NotFoundComponent);
|
|
418
|
-
const html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;
|
|
419
|
-
return new Response(html, {
|
|
420
|
-
headers: { "Content-Type": "text/html" },
|
|
421
|
-
status: 404
|
|
422
|
-
});
|
|
423
|
-
}, renderVueNotFound = async (conventionPath) => {
|
|
424
|
-
const { createSSRApp, h } = await import("vue");
|
|
425
|
-
const { renderToString } = await import("vue/server-renderer");
|
|
426
|
-
const mod = await import(conventionPath);
|
|
427
|
-
const NotFoundComponent = mod.default;
|
|
428
|
-
const app = createSSRApp({
|
|
429
|
-
render: () => h(NotFoundComponent)
|
|
430
|
-
});
|
|
431
|
-
const rawBody = await renderToString(app);
|
|
432
|
-
const { styles, body } = unescapeVueStyles(rawBody);
|
|
433
|
-
const html = `<!DOCTYPE html><html><head>${styles}</head><body><div id="root">${body}</div></body></html>`;
|
|
434
|
-
return new Response(html, {
|
|
435
|
-
headers: { "Content-Type": "text/html" },
|
|
436
|
-
status: 404
|
|
437
|
-
});
|
|
438
|
-
}, renderAngularNotFound = async (conventionPath) => {
|
|
439
|
-
const mod = await import(conventionPath);
|
|
440
|
-
const renderNotFound = mod.default ?? mod.renderNotFound;
|
|
441
|
-
if (typeof renderNotFound !== "function")
|
|
442
|
-
return null;
|
|
443
|
-
const html = renderNotFound();
|
|
444
|
-
return new Response(html, {
|
|
445
|
-
headers: { "Content-Type": "text/html" },
|
|
446
|
-
status: 404
|
|
447
|
-
});
|
|
448
|
-
}, NOT_FOUND_RENDERERS, renderConventionNotFound = async (framework) => {
|
|
449
|
-
const conventionPath = resolveNotFoundConventionPath(framework);
|
|
450
|
-
if (!conventionPath)
|
|
451
|
-
return null;
|
|
452
|
-
const renderer = NOT_FOUND_RENDERERS[framework];
|
|
453
|
-
if (!renderer)
|
|
454
|
-
return null;
|
|
455
|
-
try {
|
|
456
|
-
return await renderer(conventionPath);
|
|
457
|
-
} catch (renderError) {
|
|
458
|
-
logConventionRenderError(framework, "not-found", renderError);
|
|
459
|
-
}
|
|
460
|
-
return null;
|
|
461
|
-
}, NOT_FOUND_PRIORITY, renderFirstNotFound = async () => {
|
|
462
|
-
for (const framework of NOT_FOUND_PRIORITY) {
|
|
463
|
-
if (!getMap()[framework]?.defaults?.notFound)
|
|
464
|
-
continue;
|
|
465
|
-
const response = await renderConventionNotFound(framework);
|
|
466
|
-
if (response)
|
|
467
|
-
return response;
|
|
468
|
-
}
|
|
469
|
-
return null;
|
|
470
|
-
};
|
|
471
|
-
var init_resolveConvention = __esm(() => {
|
|
472
|
-
ERROR_RENDERERS = {
|
|
473
|
-
angular: renderAngularError,
|
|
474
|
-
react: renderReactError,
|
|
475
|
-
svelte: renderSvelteError,
|
|
476
|
-
vue: renderVueError
|
|
477
|
-
};
|
|
478
|
-
NOT_FOUND_RENDERERS = {
|
|
479
|
-
angular: renderAngularNotFound,
|
|
480
|
-
react: renderReactNotFound,
|
|
481
|
-
svelte: renderSvelteNotFound,
|
|
482
|
-
vue: renderVueNotFound
|
|
483
|
-
};
|
|
484
|
-
NOT_FOUND_PRIORITY = [
|
|
485
|
-
"react",
|
|
486
|
-
"svelte",
|
|
487
|
-
"vue",
|
|
488
|
-
"angular"
|
|
489
|
-
];
|
|
490
|
-
});
|
|
491
|
-
|
|
492
|
-
// src/react/pageHandler.ts
|
|
493
|
-
var ssrDirty = false, buildDirtyResponse = (index, maybeProps) => {
|
|
494
|
-
const propsScript = maybeProps ? `window.__INITIAL_PROPS__=${JSON.stringify(maybeProps)};` : "";
|
|
495
|
-
const dirtyFlag = "window.__SSR_DIRTY__=true;";
|
|
496
|
-
const refreshSetup = "window.__REFRESH_BUFFER__=[];" + "window.$RefreshReg$=function(t,i){window.__REFRESH_BUFFER__.push([t,i])};" + "window.$RefreshSig$=function(){return function(t){return t}};";
|
|
497
|
-
const inlineScript = `${propsScript}${dirtyFlag}${refreshSetup}`;
|
|
498
|
-
const html = `<!DOCTYPE html><html><head></head><body>` + `<script>${inlineScript}</script>` + `<script type="module" src="${index}"></script>` + `</body></html>`;
|
|
499
|
-
return new Response(html, {
|
|
500
|
-
headers: { "Content-Type": "text/html" }
|
|
501
|
-
});
|
|
502
|
-
}, handleReactPageRequest = async (PageComponent, index, ...props) => {
|
|
503
|
-
const [maybeProps] = props;
|
|
504
|
-
if (ssrDirty) {
|
|
505
|
-
return buildDirtyResponse(index, maybeProps);
|
|
506
|
-
}
|
|
507
|
-
try {
|
|
508
|
-
const { createElement } = await import("react");
|
|
509
|
-
const { renderToReadableStream } = await import("react-dom/server");
|
|
510
|
-
const element = maybeProps !== undefined ? createElement(PageComponent, maybeProps) : createElement(PageComponent);
|
|
511
|
-
const propsScript = maybeProps ? `window.__INITIAL_PROPS__=${JSON.stringify(maybeProps)};` : "";
|
|
512
|
-
const refreshSetup = "window.__REFRESH_BUFFER__=[];window.$RefreshReg$=function(t,i){window.__REFRESH_BUFFER__.push([t,i])};window.$RefreshSig$=function(){return function(t){return t}};";
|
|
513
|
-
const stream = await renderToReadableStream(element, {
|
|
514
|
-
bootstrapModules: [index],
|
|
515
|
-
bootstrapScriptContent: propsScript + refreshSetup || undefined,
|
|
516
|
-
onError(error) {
|
|
517
|
-
console.error("[SSR] React streaming error:", error);
|
|
518
|
-
}
|
|
519
|
-
});
|
|
520
|
-
const html = injectIslandPageContext(await new Response(stream).text());
|
|
521
|
-
return new Response(html, {
|
|
522
|
-
headers: { "Content-Type": "text/html" }
|
|
523
|
-
});
|
|
524
|
-
} catch (error) {
|
|
525
|
-
console.error("[SSR] React render error:", error);
|
|
526
|
-
const pageName = PageComponent.name || PageComponent.displayName || "";
|
|
527
|
-
const conventionResponse = await renderConventionError("react", pageName, error);
|
|
528
|
-
if (conventionResponse)
|
|
529
|
-
return conventionResponse;
|
|
530
|
-
return new Response(ssrErrorPage("react", error), {
|
|
531
|
-
headers: { "Content-Type": "text/html" },
|
|
532
|
-
status: 500
|
|
533
|
-
});
|
|
534
|
-
}
|
|
535
|
-
}, invalidateReactSsrCache = () => {
|
|
536
|
-
ssrDirty = true;
|
|
537
|
-
};
|
|
538
|
-
var init_pageHandler = __esm(() => {
|
|
539
|
-
init_resolveConvention();
|
|
540
|
-
});
|
|
541
|
-
|
|
542
|
-
// src/core/currentIslandRegistry.ts
|
|
543
|
-
var setCurrentIslandRegistry = (registry) => {
|
|
544
|
-
globalThis.__absoluteIslandRegistry = registry;
|
|
545
|
-
}, requireCurrentIslandRegistry = () => {
|
|
546
|
-
const registry = globalThis.__absoluteIslandRegistry;
|
|
547
|
-
if (!registry) {
|
|
548
|
-
throw new Error("No island registry is active. Configure `islands.registry` in absolute.config.ts before rendering <Island />.");
|
|
549
|
-
}
|
|
550
|
-
return registry;
|
|
551
|
-
};
|
|
552
|
-
|
|
553
|
-
// src/build/islandEntries.ts
|
|
554
|
-
import {
|
|
555
|
-
mkdirSync,
|
|
556
|
-
rmSync,
|
|
557
|
-
writeFileSync
|
|
558
|
-
} from "fs";
|
|
559
|
-
import { dirname, extname, join, relative, resolve as resolve3 } from "path";
|
|
560
|
-
var frameworks, isRecord3 = (value) => typeof value === "object" && value !== null, resolveRegistryExport2 = (mod) => {
|
|
561
|
-
if (isRecord3(mod.islandRegistry))
|
|
562
|
-
return mod.islandRegistry;
|
|
563
|
-
if (isRecord3(mod.default))
|
|
564
|
-
return mod.default;
|
|
565
|
-
throw new Error("Island registry module must export `islandRegistry` or a default registry object.");
|
|
566
|
-
}, normalizeImportPath = (wrapperPath, targetPath) => {
|
|
567
|
-
const importPath = relative(dirname(wrapperPath), targetPath).replace(/\\/g, "/");
|
|
568
|
-
return importPath.startsWith(".") ? importPath : `./${importPath}`;
|
|
569
|
-
}, isIdentifier = (value) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value), resolveIslandSourcePath = (registryPath, sourcePath) => {
|
|
570
|
-
if (sourcePath.startsWith("file://")) {
|
|
571
|
-
return new URL(sourcePath).pathname;
|
|
572
|
-
}
|
|
573
|
-
return resolve3(dirname(registryPath), sourcePath);
|
|
574
|
-
}, createRegistryImportCode = (wrapperPath, registryPath, hasNamedExport) => {
|
|
575
|
-
const normalizedPath = normalizeImportPath(wrapperPath, registryPath);
|
|
576
|
-
if (hasNamedExport) {
|
|
577
|
-
return {
|
|
578
|
-
importStatement: `import { islandRegistry as __absoluteIslandRegistry } from ${JSON.stringify(normalizedPath)};`,
|
|
579
|
-
registryReference: "__absoluteIslandRegistry"
|
|
580
|
-
};
|
|
581
|
-
}
|
|
582
|
-
return {
|
|
583
|
-
importStatement: `import __absoluteIslandRegistry from ${JSON.stringify(normalizedPath)};`,
|
|
584
|
-
registryReference: "__absoluteIslandRegistry"
|
|
585
|
-
};
|
|
586
|
-
}, createDirectEntrySource = (wrapperPath, importPath, exportName) => {
|
|
587
|
-
const normalizedImportPath = normalizeImportPath(wrapperPath, importPath);
|
|
588
|
-
if (!exportName || exportName === "default") {
|
|
589
|
-
return `export { default } from ${JSON.stringify(normalizedImportPath)};
|
|
590
|
-
`;
|
|
591
|
-
}
|
|
592
|
-
return `export { ${exportName} as default } from ${JSON.stringify(normalizedImportPath)};
|
|
593
|
-
`;
|
|
594
|
-
}, createRegistryEntrySource = (wrapperPath, registryPath, hasNamedExport, framework, component) => {
|
|
595
|
-
const { importStatement, registryReference } = createRegistryImportCode(wrapperPath, registryPath, hasNamedExport);
|
|
596
|
-
const frameworkAccess = isIdentifier(framework) ? `${registryReference}.${framework}` : `${registryReference}[${JSON.stringify(framework)}]`;
|
|
597
|
-
const componentAccess = isIdentifier(component) ? `${frameworkAccess}.${component}` : `${frameworkAccess}[${JSON.stringify(component)}]`;
|
|
598
|
-
return `${importStatement}
|
|
599
|
-
|
|
600
|
-
const component = ${componentAccess};
|
|
601
|
-
|
|
602
|
-
export default component;
|
|
603
|
-
`;
|
|
604
|
-
}, shouldUseCompiledClientPath = (framework, sourcePath) => {
|
|
605
|
-
if (framework === "svelte") {
|
|
606
|
-
return /\.svelte(?:\.(?:ts|js))?$/.test(sourcePath);
|
|
607
|
-
}
|
|
608
|
-
if (framework === "vue") {
|
|
609
|
-
return extname(sourcePath) === ".vue";
|
|
610
|
-
}
|
|
611
|
-
return false;
|
|
612
|
-
}, loadIslandRegistryBuildInfo = async (registryPath) => {
|
|
613
|
-
const resolvedRegistryPath = resolve3(registryPath);
|
|
614
|
-
const registryModule = await import(resolvedRegistryPath);
|
|
615
|
-
const registry = resolveRegistryExport2(registryModule);
|
|
616
|
-
const definitions = [];
|
|
617
|
-
for (const framework of frameworks) {
|
|
618
|
-
const frameworkRegistry = registry[framework];
|
|
619
|
-
if (!isRecord3(frameworkRegistry))
|
|
620
|
-
continue;
|
|
621
|
-
for (const [component, value] of Object.entries(frameworkRegistry)) {
|
|
622
|
-
definitions.push({
|
|
623
|
-
buildReference: getIslandBuildReference(value),
|
|
624
|
-
component,
|
|
625
|
-
framework
|
|
626
|
-
});
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
return {
|
|
630
|
-
definitions,
|
|
631
|
-
hasNamedExport: isRecord3(registryModule.islandRegistry),
|
|
632
|
-
registry,
|
|
633
|
-
resolvedRegistryPath
|
|
634
|
-
};
|
|
635
|
-
}, collectIslandFrameworkSources = (buildInfo) => {
|
|
636
|
-
const sources = {};
|
|
637
|
-
for (const definition of buildInfo.definitions) {
|
|
638
|
-
const buildReference = definition.buildReference;
|
|
639
|
-
if (!buildReference)
|
|
640
|
-
continue;
|
|
641
|
-
const resolvedSourcePath = resolveIslandSourcePath(buildInfo.resolvedRegistryPath, buildReference.source);
|
|
642
|
-
if (!shouldUseCompiledClientPath(definition.framework, resolvedSourcePath)) {
|
|
643
|
-
continue;
|
|
644
|
-
}
|
|
645
|
-
const frameworkSources = sources[definition.framework] ?? [];
|
|
646
|
-
if (!frameworkSources.includes(resolvedSourcePath)) {
|
|
647
|
-
frameworkSources.push(resolvedSourcePath);
|
|
648
|
-
}
|
|
649
|
-
sources[definition.framework] = frameworkSources;
|
|
650
|
-
}
|
|
651
|
-
return sources;
|
|
652
|
-
}, generateIslandEntryPoints = async ({
|
|
653
|
-
buildInfo,
|
|
654
|
-
buildPath,
|
|
655
|
-
clientPathMaps = {}
|
|
656
|
-
}) => {
|
|
657
|
-
const generatedRoot = join(buildPath, "_island_entries");
|
|
658
|
-
rmSync(generatedRoot, { force: true, recursive: true });
|
|
659
|
-
const entries = [];
|
|
660
|
-
for (const definition of buildInfo.definitions) {
|
|
661
|
-
const entryPath = join(generatedRoot, "islands", definition.framework, `${definition.component}.ts`);
|
|
662
|
-
const buildReference = definition.buildReference;
|
|
663
|
-
const source = buildReference ? resolveIslandSourcePath(buildInfo.resolvedRegistryPath, buildReference.source) : null;
|
|
664
|
-
const compiledSourcePath = source && shouldUseCompiledClientPath(definition.framework, source) ? clientPathMaps[definition.framework]?.get(source) : undefined;
|
|
665
|
-
const entrySource = source && (compiledSourcePath || !shouldUseCompiledClientPath(definition.framework, source)) ? createDirectEntrySource(entryPath, compiledSourcePath ?? source, compiledSourcePath ? undefined : buildReference?.export) : createRegistryEntrySource(entryPath, buildInfo.resolvedRegistryPath, buildInfo.hasNamedExport, definition.framework, definition.component);
|
|
666
|
-
mkdirSync(dirname(entryPath), { recursive: true });
|
|
667
|
-
writeFileSync(entryPath, entrySource);
|
|
668
|
-
entries.push({
|
|
669
|
-
component: definition.component,
|
|
670
|
-
entryPath,
|
|
671
|
-
framework: definition.framework
|
|
672
|
-
});
|
|
673
|
-
}
|
|
674
|
-
return {
|
|
675
|
-
entries,
|
|
676
|
-
generatedRoot
|
|
677
|
-
};
|
|
678
|
-
};
|
|
679
|
-
var init_islandEntries = __esm(() => {
|
|
680
|
-
init_islands();
|
|
681
|
-
frameworks = [
|
|
682
|
-
"react",
|
|
683
|
-
"svelte",
|
|
684
|
-
"vue",
|
|
685
|
-
"angular"
|
|
686
|
-
];
|
|
687
|
-
});
|
|
688
|
-
|
|
689
|
-
// src/build/scanEntryPoints.ts
|
|
690
|
-
import { existsSync } from "fs";
|
|
691
|
-
var {Glob } = globalThis.Bun;
|
|
692
|
-
var scanEntryPoints = async (dir, pattern) => {
|
|
693
|
-
if (!existsSync(dir))
|
|
694
|
-
return [];
|
|
695
|
-
const entryPaths = [];
|
|
696
|
-
const glob = new Glob(pattern);
|
|
697
|
-
for await (const file2 of glob.scan({ absolute: true, cwd: dir })) {
|
|
698
|
-
entryPaths.push(file2);
|
|
699
|
-
}
|
|
700
|
-
return entryPaths;
|
|
701
|
-
};
|
|
702
|
-
var init_scanEntryPoints = () => {};
|
|
703
|
-
|
|
704
|
-
// src/islands/sourceMetadata.ts
|
|
705
|
-
var islandFrameworks, islandHydrationModes, isIslandFramework = (value) => islandFrameworks.some((framework) => framework === value), isIslandHydrate = (value) => islandHydrationModes.some((hydrate) => hydrate === value), parseIslandTagAttributes = (attributeString) => {
|
|
706
|
-
const frameworkMatch = attributeString.match(/\bframework\s*=\s*["']([^"']+)["']/);
|
|
707
|
-
const componentMatch = attributeString.match(/\bcomponent\s*=\s*["']([^"']+)["']/);
|
|
708
|
-
const hydrateMatch = attributeString.match(/\bhydrate\s*=\s*["']([^"']+)["']/);
|
|
709
|
-
const framework = frameworkMatch?.[1];
|
|
710
|
-
const component = componentMatch?.[1];
|
|
711
|
-
if (!framework || !component) {
|
|
712
|
-
return null;
|
|
713
|
-
}
|
|
714
|
-
if (!isIslandFramework(framework)) {
|
|
715
|
-
return null;
|
|
716
|
-
}
|
|
717
|
-
const hydrateCandidate = hydrateMatch?.[1];
|
|
718
|
-
return {
|
|
719
|
-
component,
|
|
720
|
-
framework,
|
|
721
|
-
hydrate: hydrateCandidate && isIslandHydrate(hydrateCandidate) ? hydrateCandidate : undefined
|
|
722
|
-
};
|
|
723
|
-
}, normalizeUsage = (usage) => `${usage.framework}:${usage.component}:${usage.hydrate ?? ""}`, addUsage = (usageMap, usage) => {
|
|
724
|
-
if (!usage)
|
|
725
|
-
return;
|
|
726
|
-
usageMap.set(normalizeUsage(usage), usage);
|
|
727
|
-
}, extractIslandUsagesFromSource = (source) => {
|
|
728
|
-
const usageMap = new Map;
|
|
729
|
-
const islandTagRegex = /<Island\b([\s\S]*?)(?:\/>|>(?:[\s\S]*?)<\/Island>)/g;
|
|
730
|
-
let islandTagMatch = islandTagRegex.exec(source);
|
|
731
|
-
while (islandTagMatch) {
|
|
732
|
-
addUsage(usageMap, parseIslandTagAttributes(islandTagMatch[1] ?? ""));
|
|
733
|
-
islandTagMatch = islandTagRegex.exec(source);
|
|
734
|
-
}
|
|
735
|
-
const staticRenderCallRegex = /renderIsland\s*\(\s*\{[\s\S]*?\bframework\s*:\s*['"]([^'"]+)['"][\s\S]*?\bcomponent\s*:\s*['"]([^'"]+)['"](?:[\s\S]*?\bhydrate\s*:\s*['"]([^'"]+)['"])?[\s\S]*?\}\s*\)/g;
|
|
736
|
-
let renderMatch = staticRenderCallRegex.exec(source);
|
|
737
|
-
while (renderMatch) {
|
|
738
|
-
const framework = renderMatch[1];
|
|
739
|
-
const component = renderMatch[2];
|
|
740
|
-
const hydrate = renderMatch[3];
|
|
741
|
-
if (!framework || !component || !isIslandFramework(framework)) {
|
|
742
|
-
renderMatch = staticRenderCallRegex.exec(source);
|
|
743
|
-
continue;
|
|
744
|
-
}
|
|
745
|
-
addUsage(usageMap, {
|
|
746
|
-
component,
|
|
747
|
-
framework,
|
|
748
|
-
hydrate: hydrate && isIslandHydrate(hydrate) ? hydrate : undefined
|
|
749
|
-
});
|
|
750
|
-
renderMatch = staticRenderCallRegex.exec(source);
|
|
751
|
-
}
|
|
752
|
-
return [...usageMap.values()];
|
|
753
|
-
}, buildIslandMetadataExports = (source) => {
|
|
754
|
-
const usages = extractIslandUsagesFromSource(source);
|
|
755
|
-
const serialized = JSON.stringify(usages);
|
|
756
|
-
return `
|
|
757
|
-
export const __ABSOLUTE_PAGE_ISLANDS__ = ${serialized};
|
|
758
|
-
export const __ABSOLUTE_PAGE_HAS_ISLANDS__ = ${usages.length > 0};
|
|
759
|
-
`;
|
|
760
|
-
};
|
|
761
|
-
var init_sourceMetadata = __esm(() => {
|
|
762
|
-
islandFrameworks = [
|
|
763
|
-
"react",
|
|
764
|
-
"svelte",
|
|
765
|
-
"vue",
|
|
766
|
-
"angular"
|
|
767
|
-
];
|
|
768
|
-
islandHydrationModes = [
|
|
769
|
-
"load",
|
|
770
|
-
"idle",
|
|
771
|
-
"visible",
|
|
772
|
-
"none"
|
|
773
|
-
];
|
|
774
|
-
});
|
|
775
|
-
|
|
776
|
-
// src/islands/pageMetadata.ts
|
|
777
|
-
import { readFileSync } from "fs";
|
|
778
|
-
import { dirname as dirname2, resolve as resolve4 } from "path";
|
|
779
|
-
var pagePatterns, getPageDirs = (config) => [
|
|
780
|
-
{ dir: config.angularDirectory, framework: "angular" },
|
|
781
|
-
{ dir: config.reactDirectory, framework: "react" },
|
|
782
|
-
{ dir: config.svelteDirectory, framework: "svelte" },
|
|
783
|
-
{ dir: config.vueDirectory, framework: "vue" },
|
|
784
|
-
{ dir: config.htmlDirectory, framework: "html" },
|
|
785
|
-
{ dir: config.htmxDirectory, framework: "htmx" }
|
|
786
|
-
].filter((entry) => typeof entry.dir === "string" && entry.dir.length > 0), buildIslandSourceLookup = async (config) => {
|
|
787
|
-
const registryPath = config.islands?.registry;
|
|
788
|
-
if (!registryPath) {
|
|
789
|
-
return new Map;
|
|
790
|
-
}
|
|
791
|
-
const buildInfo = await loadIslandRegistryBuildInfo(registryPath);
|
|
792
|
-
const lookup = new Map;
|
|
793
|
-
for (const definition of buildInfo.definitions) {
|
|
794
|
-
const source = definition.buildReference?.source;
|
|
795
|
-
if (!source)
|
|
796
|
-
continue;
|
|
797
|
-
const resolvedSource = source.startsWith("file://") ? new URL(source).pathname : resolve4(dirname2(buildInfo.resolvedRegistryPath), source);
|
|
798
|
-
lookup.set(`${definition.framework}:${definition.component}`, resolve4(resolvedSource));
|
|
799
|
-
}
|
|
800
|
-
return lookup;
|
|
801
|
-
}, loadPageIslandMetadata = async (config) => {
|
|
802
|
-
const pageMetadata = new Map;
|
|
803
|
-
const islandSourceLookup = await buildIslandSourceLookup(config);
|
|
804
|
-
for (const entry of getPageDirs(config)) {
|
|
805
|
-
const pattern = pagePatterns[entry.framework];
|
|
806
|
-
if (!pattern)
|
|
807
|
-
continue;
|
|
808
|
-
const files = await scanEntryPoints(resolve4(entry.dir), pattern);
|
|
809
|
-
for (const filePath of files) {
|
|
810
|
-
const source = readFileSync(filePath, "utf-8");
|
|
811
|
-
const islands = extractIslandUsagesFromSource(source);
|
|
812
|
-
pageMetadata.set(resolve4(filePath), {
|
|
813
|
-
islands: islands.map((usage) => {
|
|
814
|
-
const sourcePath = islandSourceLookup.get(`${usage.framework}:${usage.component}`);
|
|
815
|
-
return sourcePath ? {
|
|
816
|
-
...usage,
|
|
817
|
-
source: sourcePath
|
|
818
|
-
} : usage;
|
|
819
|
-
}),
|
|
820
|
-
pagePath: resolve4(filePath)
|
|
821
|
-
});
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
return pageMetadata;
|
|
825
|
-
}, setCurrentPageIslandMetadata = (metadata2) => {
|
|
826
|
-
globalThis.__absolutePageIslandMetadata = metadata2;
|
|
827
|
-
}, getCurrentPageIslandMetadata = () => globalThis.__absolutePageIslandMetadata ?? new Map, getPagesUsingIslandSource = (sourcePath) => {
|
|
828
|
-
const target = resolve4(sourcePath);
|
|
829
|
-
const matches = [];
|
|
830
|
-
for (const metadata2 of getCurrentPageIslandMetadata().values()) {
|
|
831
|
-
const usesTarget = metadata2.islands.some((usage) => {
|
|
832
|
-
const candidate = usage.source;
|
|
833
|
-
return candidate ? resolve4(candidate) === target : false;
|
|
834
|
-
});
|
|
835
|
-
if (usesTarget) {
|
|
836
|
-
matches.push(metadata2.pagePath);
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
return matches;
|
|
840
|
-
};
|
|
841
|
-
var init_pageMetadata = __esm(() => {
|
|
842
|
-
init_islandEntries();
|
|
843
|
-
init_scanEntryPoints();
|
|
844
|
-
init_sourceMetadata();
|
|
845
|
-
pagePatterns = {
|
|
846
|
-
angular: "pages/**/*.{ts,js}",
|
|
847
|
-
html: "pages/**/*.html",
|
|
848
|
-
htmx: "pages/**/*.html",
|
|
849
|
-
react: "pages/**/*.{ts,tsx,js,jsx}",
|
|
850
|
-
svelte: "pages/**/*.svelte",
|
|
851
|
-
vue: "pages/**/*.vue"
|
|
852
|
-
};
|
|
853
|
-
});
|
|
854
|
-
|
|
855
|
-
// src/build/generateIslandBindings.ts
|
|
856
|
-
var exports_generateIslandBindings = {};
|
|
857
|
-
__export(exports_generateIslandBindings, {
|
|
858
|
-
generateIslandBindings: () => generateIslandBindings
|
|
859
|
-
});
|
|
860
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
861
|
-
import { dirname as dirname3, resolve as resolve5 } from "path";
|
|
862
|
-
var ensureDir = (filePath) => {
|
|
863
|
-
mkdirSync2(dirname3(filePath), { recursive: true });
|
|
864
|
-
}, writeIfChanged = (filePath, content) => {
|
|
865
|
-
ensureDir(filePath);
|
|
866
|
-
writeFileSync2(filePath, content);
|
|
867
|
-
}, removeIfExists = (filePath) => {
|
|
868
|
-
if (existsSync2(filePath)) {
|
|
869
|
-
rmSync2(filePath, { force: true });
|
|
870
|
-
}
|
|
871
|
-
}, generateIslandBindings = (projectRoot, config) => {
|
|
872
|
-
const registryPath = config.islands?.registry;
|
|
873
|
-
if (!registryPath) {
|
|
874
|
-
return;
|
|
875
|
-
}
|
|
876
|
-
const resolvedRegistryPath = resolve5(projectRoot, registryPath);
|
|
877
|
-
removeIfExists(resolve5(dirname3(resolvedRegistryPath), "absolute-islands.d.ts"));
|
|
878
|
-
if (config.reactDirectory) {
|
|
879
|
-
const compatTarget = resolve5(config.reactDirectory, "generated", "absolute-react.ts");
|
|
880
|
-
removeIfExists(resolve5(config.reactDirectory, "generated", "Island.tsx"));
|
|
881
|
-
removeIfExists(resolve5(config.reactDirectory, "generated", "absolute-react.d.ts"));
|
|
882
|
-
writeIfChanged(compatTarget, `export * from "@absolutejs/absolute/react";
|
|
883
|
-
`);
|
|
884
|
-
}
|
|
885
|
-
if (config.vueDirectory) {
|
|
886
|
-
const compatTarget = resolve5(config.vueDirectory, "generated", "absolute-vue.ts");
|
|
887
|
-
removeIfExists(resolve5(config.vueDirectory, "generated", "Island.ts"));
|
|
888
|
-
removeIfExists(resolve5(config.vueDirectory, "generated", "absolute-vue.d.ts"));
|
|
889
|
-
writeIfChanged(compatTarget, `export * from "@absolutejs/absolute/vue";
|
|
890
|
-
`);
|
|
891
|
-
}
|
|
892
|
-
if (config.svelteDirectory) {
|
|
893
|
-
const compatTarget = resolve5(config.svelteDirectory, "generated", "absolute-svelte.ts");
|
|
894
|
-
removeIfExists(resolve5(config.svelteDirectory, "generated", "islands.ts"));
|
|
895
|
-
removeIfExists(resolve5(config.svelteDirectory, "generated", "absolute-svelte.d.ts"));
|
|
896
|
-
writeIfChanged(compatTarget, `export * from "@absolutejs/absolute/svelte";
|
|
897
|
-
`);
|
|
898
|
-
}
|
|
899
|
-
if (config.angularDirectory) {
|
|
900
|
-
const compatTarget = resolve5(config.angularDirectory, "generated", "absolute-angular.ts");
|
|
901
|
-
removeIfExists(resolve5(config.angularDirectory, "generated", "islands.ts"));
|
|
902
|
-
removeIfExists(resolve5(config.angularDirectory, "generated", "absolute-angular.d.ts"));
|
|
903
|
-
writeIfChanged(compatTarget, `export * from "@absolutejs/absolute/angular";
|
|
904
|
-
`);
|
|
905
|
-
}
|
|
906
|
-
};
|
|
907
|
-
var init_generateIslandBindings = () => {};
|
|
908
|
-
|
|
909
|
-
// src/utils/getDurationString.ts
|
|
910
|
-
var getDurationString = (duration) => {
|
|
911
|
-
let durationString;
|
|
912
|
-
if (duration < MILLISECONDS_IN_A_SECOND) {
|
|
913
|
-
durationString = `${duration.toFixed(TIME_PRECISION)}ms`;
|
|
914
|
-
} else if (duration < MILLISECONDS_IN_A_MINUTE) {
|
|
915
|
-
durationString = `${(duration / MILLISECONDS_IN_A_SECOND).toFixed(TIME_PRECISION)}s`;
|
|
916
|
-
} else {
|
|
917
|
-
durationString = `${(duration / MILLISECONDS_IN_A_MINUTE).toFixed(TIME_PRECISION)}m`;
|
|
918
|
-
}
|
|
919
|
-
return durationString;
|
|
920
|
-
};
|
|
921
|
-
var init_getDurationString = __esm(() => {
|
|
922
|
-
init_constants();
|
|
923
|
-
});
|
|
924
|
-
|
|
925
|
-
// src/utils/startupBanner.ts
|
|
926
|
-
var colors, MONTHS, formatTimestamp = () => {
|
|
927
|
-
const now = new Date;
|
|
928
|
-
const month = MONTHS[now.getMonth()];
|
|
929
|
-
const day = now.getDate().toString().padStart(2, "0");
|
|
930
|
-
let hours = now.getHours();
|
|
931
|
-
const minutes = now.getMinutes().toString().padStart(2, "0");
|
|
932
|
-
const seconds = now.getSeconds().toString().padStart(2, "0");
|
|
933
|
-
const ampm = hours >= HOURS_IN_HALF_DAY ? "PM" : "AM";
|
|
934
|
-
hours = hours % HOURS_IN_HALF_DAY || HOURS_IN_HALF_DAY;
|
|
935
|
-
return `${month} ${day} ${hours}:${minutes}:${seconds} ${ampm}`;
|
|
936
|
-
}, startupBanner = (options) => {
|
|
937
|
-
const {
|
|
938
|
-
version,
|
|
939
|
-
duration,
|
|
940
|
-
port,
|
|
941
|
-
host,
|
|
942
|
-
networkUrl,
|
|
943
|
-
protocol = "http"
|
|
944
|
-
} = options;
|
|
945
|
-
const name = `${colors.cyan}${colors.bold}ABSOLUTEJS${colors.reset}`;
|
|
946
|
-
const ver = `${colors.dim}v${version}${colors.reset}`;
|
|
947
|
-
const time = `${colors.dim}ready in${colors.reset} ${colors.bold}${getDurationString(duration)}${colors.reset}`;
|
|
948
|
-
console.log("");
|
|
949
|
-
console.log(` ${name} ${ver} ${time}`);
|
|
950
|
-
console.log("");
|
|
951
|
-
console.log(` ${colors.green}\u279C${colors.reset} ${colors.bold}Local:${colors.reset} ${protocol}://${host === "0.0.0.0" ? "localhost" : host}:${port}/`);
|
|
952
|
-
if (networkUrl) {
|
|
953
|
-
console.log(` ${colors.green}\u279C${colors.reset} ${colors.bold}Network:${colors.reset} ${networkUrl}`);
|
|
954
|
-
}
|
|
955
|
-
console.log("");
|
|
956
|
-
};
|
|
957
|
-
var init_startupBanner = __esm(() => {
|
|
958
|
-
init_constants();
|
|
959
|
-
init_getDurationString();
|
|
960
|
-
colors = {
|
|
961
|
-
bold: "\x1B[1m",
|
|
962
|
-
cyan: "\x1B[36m",
|
|
963
|
-
dim: "\x1B[2m",
|
|
964
|
-
green: "\x1B[32m",
|
|
965
|
-
reset: "\x1B[0m"
|
|
966
|
-
};
|
|
967
|
-
MONTHS = [
|
|
968
|
-
"Jan",
|
|
969
|
-
"Feb",
|
|
970
|
-
"Mar",
|
|
971
|
-
"Apr",
|
|
972
|
-
"May",
|
|
973
|
-
"Jun",
|
|
974
|
-
"Jul",
|
|
975
|
-
"Aug",
|
|
976
|
-
"Sep",
|
|
977
|
-
"Oct",
|
|
978
|
-
"Nov",
|
|
979
|
-
"Dec"
|
|
980
|
-
];
|
|
981
|
-
});
|
|
982
|
-
|
|
983
|
-
// src/utils/logger.ts
|
|
984
|
-
var colors2, frameworkColors, formatPath = (filePath) => {
|
|
985
|
-
const cwd = process.cwd();
|
|
986
|
-
let relative2 = filePath.startsWith(cwd) ? filePath.slice(cwd.length + 1) : filePath;
|
|
987
|
-
relative2 = relative2.replace(/\\/g, "/");
|
|
988
|
-
if (!relative2.startsWith("/")) {
|
|
989
|
-
relative2 = `/${relative2}`;
|
|
990
|
-
}
|
|
991
|
-
return relative2;
|
|
992
|
-
}, getFrameworkColor = (framework) => frameworkColors[framework] || colors2.white, log = (action, options) => {
|
|
993
|
-
const timestamp = `${colors2.dim}${formatTimestamp()}${colors2.reset}`;
|
|
994
|
-
const tag = `${colors2.cyan}[hmr]${colors2.reset}`;
|
|
995
|
-
let message = action;
|
|
996
|
-
if (options?.path) {
|
|
997
|
-
const pathColor = options.framework ? getFrameworkColor(options.framework) : colors2.white;
|
|
998
|
-
message += ` ${pathColor}${formatPath(options.path)}${colors2.reset}`;
|
|
999
|
-
}
|
|
1000
|
-
if (options?.duration !== undefined) {
|
|
1001
|
-
message += ` ${colors2.dim}(${options.duration}ms)${colors2.reset}`;
|
|
1002
|
-
}
|
|
1003
|
-
console.log(`${timestamp} ${tag} ${message}`);
|
|
1004
|
-
}, logCssUpdate = (path, framework, duration) => {
|
|
1005
|
-
log("css update", { duration, framework: framework ?? "css", path });
|
|
1006
|
-
}, logError = (message, error) => {
|
|
1007
|
-
const timestamp = `${colors2.dim}${formatTimestamp()}${colors2.reset}`;
|
|
1008
|
-
const tag = `${colors2.red}[hmr]${colors2.reset}`;
|
|
1009
|
-
const errorMsg = error instanceof Error ? error.message : error;
|
|
1010
|
-
const fullMessage = `${colors2.red}error${colors2.reset} ${message}${errorMsg ? `: ${errorMsg}` : ""}`;
|
|
1011
|
-
console.error(`${timestamp} ${tag} ${fullMessage}`);
|
|
1012
|
-
}, logHmrUpdate = (path, framework, duration) => {
|
|
1013
|
-
log("hmr update", { duration, framework, path });
|
|
1014
|
-
}, logScriptUpdate = (path, framework, duration) => {
|
|
1015
|
-
log("script update", { duration, framework, path });
|
|
1016
|
-
}, logServerReload = () => {
|
|
1017
|
-
log(`${colors2.cyan}server module reloaded${colors2.reset}`);
|
|
1018
|
-
}, logWarn = (message) => {
|
|
1019
|
-
const timestamp = `${colors2.dim}${formatTimestamp()}${colors2.reset}`;
|
|
1020
|
-
const tag = `${colors2.yellow}[hmr]${colors2.reset}`;
|
|
1021
|
-
console.warn(`${timestamp} ${tag} ${colors2.yellow}warning${colors2.reset} ${message}`);
|
|
1022
|
-
};
|
|
1023
|
-
var init_logger = __esm(() => {
|
|
1024
|
-
init_startupBanner();
|
|
1025
|
-
colors2 = {
|
|
1026
|
-
blue: "\x1B[34m",
|
|
1027
|
-
bold: "\x1B[1m",
|
|
1028
|
-
cyan: "\x1B[36m",
|
|
1029
|
-
dim: "\x1B[2m",
|
|
1030
|
-
green: "\x1B[32m",
|
|
1031
|
-
magenta: "\x1B[35m",
|
|
1032
|
-
red: "\x1B[31m",
|
|
1033
|
-
reset: "\x1B[0m",
|
|
1034
|
-
white: "\x1B[37m",
|
|
1035
|
-
yellow: "\x1B[33m"
|
|
1036
|
-
};
|
|
1037
|
-
frameworkColors = {
|
|
1038
|
-
angular: colors2.magenta,
|
|
1039
|
-
assets: colors2.dim,
|
|
1040
|
-
css: colors2.cyan,
|
|
1041
|
-
html: colors2.white,
|
|
1042
|
-
htmx: colors2.white,
|
|
1043
|
-
react: colors2.blue,
|
|
1044
|
-
svelte: colors2.yellow,
|
|
1045
|
-
vue: colors2.green
|
|
1046
|
-
};
|
|
1047
|
-
});
|
|
1048
|
-
|
|
1049
|
-
// src/utils/normalizePath.ts
|
|
1050
|
-
var normalizePath = (path) => path.replace(/\\/g, "/");
|
|
1051
|
-
|
|
1052
|
-
// src/build/generateManifest.ts
|
|
1053
|
-
var exports_generateManifest = {};
|
|
1054
|
-
__export(exports_generateManifest, {
|
|
1055
|
-
generateManifest: () => generateManifest
|
|
1056
|
-
});
|
|
1057
|
-
import { extname as extname2 } from "path";
|
|
1058
|
-
var getManifestKey = (folder, pascalName, isClientComponent, isReact, isVue, isSvelte, isAngular) => {
|
|
1059
|
-
if (folder === "indexes")
|
|
1060
|
-
return `${pascalName}Index`;
|
|
1061
|
-
if (isClientComponent)
|
|
1062
|
-
return `${pascalName}Client`;
|
|
1063
|
-
if (folder !== "pages")
|
|
1064
|
-
return pascalName;
|
|
1065
|
-
if (isReact)
|
|
1066
|
-
return `${pascalName}Page`;
|
|
1067
|
-
if (isVue || isSvelte || isAngular)
|
|
1068
|
-
return pascalName;
|
|
1069
|
-
return `${pascalName}Page`;
|
|
1070
|
-
}, getCssKey = (pascalName, segments) => {
|
|
1071
|
-
const isFromVue = segments.some((seg) => seg === "vue");
|
|
1072
|
-
if (isFromVue && segments.includes("css"))
|
|
1073
|
-
return `${pascalName}CompiledCSS`;
|
|
1074
|
-
const isFromReact = segments.some((seg) => seg === "react");
|
|
1075
|
-
const isFromSvelte = segments.some((seg) => seg === "svelte");
|
|
1076
|
-
const isFromAngular = segments.some((seg) => seg === "angular");
|
|
1077
|
-
if (isFromReact || isFromVue || isFromSvelte || isFromAngular)
|
|
1078
|
-
return `${pascalName}BundledCSS`;
|
|
1079
|
-
return `${pascalName}CSS`;
|
|
1080
|
-
}, generateManifest = (outputs, buildPath) => outputs.reduce((manifest, artifact) => {
|
|
1081
|
-
const normalizedArtifactPath = normalizePath(artifact.path);
|
|
1082
|
-
const normalizedBuildPath = normalizePath(buildPath);
|
|
1083
|
-
let relative2 = normalizedArtifactPath.startsWith(normalizedBuildPath) ? normalizedArtifactPath.slice(normalizedBuildPath.length) : normalizedArtifactPath;
|
|
1084
|
-
relative2 = relative2.replace(/^\/+/, "");
|
|
1085
|
-
const segments = relative2.split("/");
|
|
1086
|
-
const fileWithHash = segments.pop();
|
|
1087
|
-
if (!fileWithHash)
|
|
1088
|
-
return manifest;
|
|
1089
|
-
const [baseName] = fileWithHash.split(`.${artifact.hash}.`);
|
|
1090
|
-
if (!baseName)
|
|
1091
|
-
return manifest;
|
|
1092
|
-
const pascalName = toPascal(baseName);
|
|
1093
|
-
const ext = extname2(fileWithHash);
|
|
1094
|
-
const islandIndex = segments.findIndex((seg) => seg === "islands");
|
|
1095
|
-
if (ext === ".css") {
|
|
1096
|
-
const cssKey = getCssKey(pascalName, segments);
|
|
1097
|
-
if (manifest[cssKey] && manifest[cssKey] !== `/${relative2}`)
|
|
1098
|
-
logWarn(`Duplicate manifest key "${cssKey}" \u2014 "${manifest[cssKey]}" will be overwritten by "/${relative2}". Use unique page names across frameworks.`);
|
|
1099
|
-
manifest[cssKey] = `/${relative2}`;
|
|
1100
|
-
return manifest;
|
|
1101
|
-
}
|
|
1102
|
-
if (islandIndex > UNFOUND_INDEX) {
|
|
1103
|
-
const frameworkSegment = segments[islandIndex + 1];
|
|
1104
|
-
if (frameworkSegment === "react" || frameworkSegment === "svelte" || frameworkSegment === "vue" || frameworkSegment === "angular") {
|
|
1105
|
-
const manifestKey2 = getIslandManifestKey(frameworkSegment, pascalName);
|
|
1106
|
-
manifest[manifestKey2] = `/${relative2}`;
|
|
1107
|
-
return manifest;
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
const idx = segments.findIndex((seg) => seg === "indexes" || seg === "pages" || seg === "client");
|
|
1111
|
-
const folder = idx > UNFOUND_INDEX ? segments[idx] : segments[0];
|
|
1112
|
-
const isReact = segments.some((seg) => seg === "react");
|
|
1113
|
-
const isVue = segments.some((seg) => seg === "vue");
|
|
1114
|
-
const isSvelte = segments.some((seg) => seg === "svelte");
|
|
1115
|
-
const isAngular = segments.some((seg) => seg === "angular");
|
|
1116
|
-
const isClientComponent = segments.includes("client");
|
|
1117
|
-
const manifestKey = getManifestKey(folder, pascalName, isClientComponent, isReact, isVue, isSvelte, isAngular);
|
|
1118
|
-
if (manifest[manifestKey] && manifest[manifestKey] !== `/${relative2}`) {
|
|
1119
|
-
logWarn(`Duplicate manifest key "${manifestKey}" \u2014 "${manifest[manifestKey]}" will be overwritten by "/${relative2}". Use unique page names across frameworks.`);
|
|
1120
|
-
}
|
|
1121
|
-
manifest[manifestKey] = `/${relative2}`;
|
|
1122
|
-
return manifest;
|
|
1123
|
-
}, {});
|
|
1124
|
-
var init_generateManifest = __esm(() => {
|
|
1125
|
-
init_constants();
|
|
1126
|
-
init_logger();
|
|
1127
|
-
});
|
|
1128
|
-
|
|
1129
|
-
// src/build/generateReactIndexes.ts
|
|
1130
|
-
var exports_generateReactIndexes = {};
|
|
1131
|
-
__export(exports_generateReactIndexes, {
|
|
1132
|
-
generateReactIndexFiles: () => generateReactIndexFiles
|
|
1133
|
-
});
|
|
1134
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
1135
|
-
import { readdir, rm, writeFile } from "fs/promises";
|
|
1136
|
-
import { basename as basename2, join as join2, relative as relative2, resolve as resolve6, sep } from "path";
|
|
1137
|
-
var {Glob: Glob2 } = globalThis.Bun;
|
|
1138
|
-
var indexContentCache, resolveDevClientDir = () => {
|
|
1139
|
-
const projectRoot = process.cwd();
|
|
1140
|
-
const fromSource = resolve6(import.meta.dir, "../dev/client");
|
|
1141
|
-
if (existsSync3(fromSource) && fromSource.startsWith(projectRoot)) {
|
|
1142
|
-
return fromSource;
|
|
1143
|
-
}
|
|
1144
|
-
const fromNodeModules = resolve6(projectRoot, "node_modules/@absolutejs/absolute/dist/dev/client");
|
|
1145
|
-
if (existsSync3(fromNodeModules))
|
|
1146
|
-
return fromNodeModules;
|
|
1147
|
-
return resolve6(import.meta.dir, "./dev/client");
|
|
1148
|
-
}, devClientDir, errorOverlayPath, hmrClientPath, refreshSetupPath, generateReactIndexFiles = async (reactPagesDirectory, reactIndexesDirectory, isDev2 = false) => {
|
|
1149
|
-
if (!existsSync3(reactIndexesDirectory)) {
|
|
1150
|
-
mkdirSync3(reactIndexesDirectory, { recursive: true });
|
|
1151
|
-
}
|
|
1152
|
-
const CONVENTION_RE = /^(?:(.+)\.)?(error|loading|not-found)\.[^.]+$/;
|
|
1153
|
-
const pagesGlob = new Glob2("*.*");
|
|
1154
|
-
const files = [];
|
|
1155
|
-
for await (const file2 of pagesGlob.scan({ cwd: reactPagesDirectory })) {
|
|
1156
|
-
if (CONVENTION_RE.test(file2))
|
|
1157
|
-
continue;
|
|
1158
|
-
files.push(file2);
|
|
1159
|
-
}
|
|
1160
|
-
const currentPageNames = new Set(files.map((file2) => basename2(file2).split(".")[0]));
|
|
1161
|
-
const emptyStringArray = [];
|
|
1162
|
-
const existingIndexes = await readdir(reactIndexesDirectory).catch(() => emptyStringArray);
|
|
1163
|
-
const staleIndexes = existingIndexes.filter((indexFile) => {
|
|
1164
|
-
const indexName = indexFile.replace(/\.tsx$/, "");
|
|
1165
|
-
return indexName !== "_refresh" && !currentPageNames.has(indexName);
|
|
1166
|
-
});
|
|
1167
|
-
if (staleIndexes.length > 0) {
|
|
1168
|
-
await Promise.all(staleIndexes.map((indexFile) => {
|
|
1169
|
-
indexContentCache.delete(join2(reactIndexesDirectory, indexFile));
|
|
1170
|
-
return rm(join2(reactIndexesDirectory, indexFile), {
|
|
1171
|
-
force: true
|
|
1172
|
-
});
|
|
1173
|
-
}));
|
|
1174
|
-
}
|
|
1175
|
-
const pagesRelPath = relative2(resolve6(reactIndexesDirectory), resolve6(reactPagesDirectory)).split(sep).join("/");
|
|
1176
|
-
const promises = files.map(async (file2) => {
|
|
1177
|
-
const fileName = basename2(file2);
|
|
1178
|
-
const [componentName] = fileName.split(".");
|
|
1179
|
-
const hmrPreamble = isDev2 ? [
|
|
1180
|
-
`window.__HMR_FRAMEWORK__ = "react";`,
|
|
1181
|
-
`window.__REACT_COMPONENT_KEY__ = "${componentName}Index";`,
|
|
1182
|
-
`import '${refreshSetupPath}';`,
|
|
1183
|
-
`import '${hmrClientPath}';`,
|
|
1184
|
-
`import { showErrorOverlay, hideErrorOverlay } from '${errorOverlayPath}';
|
|
1185
|
-
`
|
|
1186
|
-
] : [];
|
|
1187
|
-
const reactImports = isDev2 ? [
|
|
1188
|
-
`import { hydrateRoot, createRoot } from 'react-dom/client';`,
|
|
1189
|
-
`import { createElement, Component } from 'react';`
|
|
1190
|
-
] : [
|
|
1191
|
-
`import { hydrateRoot, createRoot } from 'react-dom/client';`,
|
|
1192
|
-
`import { createElement } from 'react';`
|
|
1193
|
-
];
|
|
1194
|
-
const errorBoundaryDef = isDev2 ? [
|
|
1195
|
-
`
|
|
1196
|
-
// Dev-only Error Boundary to catch React render errors`,
|
|
1197
|
-
`class ErrorBoundary extends Component {`,
|
|
1198
|
-
` constructor(props) {`,
|
|
1199
|
-
` super(props);`,
|
|
1200
|
-
` this.state = { hasError: false };`,
|
|
1201
|
-
` window.__ERROR_BOUNDARY__ = this;`,
|
|
1202
|
-
` }`,
|
|
1203
|
-
` static getDerivedStateFromError() {`,
|
|
1204
|
-
` return { hasError: true };`,
|
|
1205
|
-
` }`,
|
|
1206
|
-
` componentDidCatch(error) {`,
|
|
1207
|
-
` showErrorOverlay({`,
|
|
1208
|
-
` framework: 'react',`,
|
|
1209
|
-
` kind: 'runtime',`,
|
|
1210
|
-
` message: error && error.stack ? error.stack : String(error)`,
|
|
1211
|
-
` });`,
|
|
1212
|
-
` }`,
|
|
1213
|
-
` componentDidUpdate(prevProps, prevState) {`,
|
|
1214
|
-
` if (prevState.hasError && !this.state.hasError) {`,
|
|
1215
|
-
` hideErrorOverlay();`,
|
|
1216
|
-
` }`,
|
|
1217
|
-
` }`,
|
|
1218
|
-
` reset() {`,
|
|
1219
|
-
` this.setState({ hasError: false });`,
|
|
1220
|
-
` }`,
|
|
1221
|
-
` render() {`,
|
|
1222
|
-
` if (this.state.hasError) return null;`,
|
|
1223
|
-
``,
|
|
1224
|
-
` return this.props.children;`,
|
|
1225
|
-
` }`,
|
|
1226
|
-
`}
|
|
1227
|
-
`
|
|
1228
|
-
] : [];
|
|
1229
|
-
const content = [
|
|
1230
|
-
...hmrPreamble,
|
|
1231
|
-
...reactImports,
|
|
1232
|
-
`import type { ComponentType } from 'react'`,
|
|
1233
|
-
`import { ${componentName} } from '${pagesRelPath}/${componentName}';
|
|
1234
|
-
`,
|
|
1235
|
-
`type PropsOf<C> = C extends ComponentType<infer P> ? P : never;
|
|
1236
|
-
`,
|
|
1237
|
-
`declare global {`,
|
|
1238
|
-
` interface Window {`,
|
|
1239
|
-
` __INITIAL_PROPS__?: PropsOf<typeof ${componentName}>`,
|
|
1240
|
-
` __REACT_ROOT__?: ReturnType<typeof hydrateRoot | typeof createRoot>`,
|
|
1241
|
-
` __HMR_CLIENT_ONLY_MODE__?: boolean`,
|
|
1242
|
-
` }`,
|
|
1243
|
-
`}
|
|
1244
|
-
`,
|
|
1245
|
-
...errorBoundaryDef,
|
|
1246
|
-
`// Hydration with error handling and fallback`,
|
|
1247
|
-
`const isDev = ${isDev2};`,
|
|
1248
|
-
`const componentPath = '${pagesRelPath}/${componentName}';
|
|
1249
|
-
`,
|
|
1250
|
-
`function isHydrationError(error) {`,
|
|
1251
|
-
` if (!error) return false;`,
|
|
1252
|
-
` const errorMessage = error instanceof Error ? error.message : String(error);`,
|
|
1253
|
-
` const errorString = String(error);`,
|
|
1254
|
-
` const fullMessage = errorMessage + ' ' + errorString;`,
|
|
1255
|
-
` const hydrationKeywords = ['hydration', 'Hydration', 'mismatch', 'Mismatch', 'did not match', 'server rendered HTML', 'server HTML', 'client HTML', 'Hydration failed'];`,
|
|
1256
|
-
` const isHydration = hydrationKeywords.some(keyword => fullMessage.includes(keyword));`,
|
|
1257
|
-
` `,
|
|
1258
|
-
` // Ignore whitespace-only mismatches in <head> - these are harmless formatting differences`,
|
|
1259
|
-
` // The error often shows: + <link...> vs - {"\\n "} which is just formatting`,
|
|
1260
|
-
` if (isHydration) {`,
|
|
1261
|
-
` // Check if this is a head/link/stylesheet related mismatch`,
|
|
1262
|
-
` const isHeadRelated = fullMessage.includes('<head') || fullMessage.includes('</head>') || fullMessage.includes('head>') || fullMessage.includes('<link') || fullMessage.includes('link>') || fullMessage.includes('stylesheet') || fullMessage.includes('fonts.googleapis') || fullMessage.includes('rel="stylesheet"');`,
|
|
1263
|
-
` `,
|
|
1264
|
-
` // Check if the mismatch involves only whitespace/newlines`,
|
|
1265
|
-
` // Pattern: looks for {"\\n"} or {"\\n "} or similar whitespace-only content`,
|
|
1266
|
-
` // Also check for patterns like: - {"\\n "} or + <link...>`,
|
|
1267
|
-
` const hasWhitespacePattern = /\\{\\s*["']\\\\n[^"']*["']\\s*\\}/.test(fullMessage) || /\\{\\s*["'][\\\\n\\\\r\\\\s]+["']\\s*\\}/.test(fullMessage) || /-\\s*\\{\\s*["'][\\\\n\\\\r\\\\s]+["']\\s*\\}/.test(fullMessage);`,
|
|
1268
|
-
` const isWhitespaceOnly = /^[\\s\\n\\r]*$/.test(errorString) || /^[\\s\\n\\r]*$/.test(errorMessage);`,
|
|
1269
|
-
` const hasNewlinePattern = fullMessage.includes('\\\\n') || fullMessage.includes('\\\\r') || fullMessage.includes('\\n') || fullMessage.includes('\\r');`,
|
|
1270
|
-
` `,
|
|
1271
|
-
` // If it's head-related and involves whitespace/newlines, ignore it`,
|
|
1272
|
-
` if (isHeadRelated && (hasWhitespacePattern || isWhitespaceOnly || hasNewlinePattern)) {`,
|
|
1273
|
-
` return false; // Don't treat whitespace-only head mismatches as errors`,
|
|
1274
|
-
` }`,
|
|
1275
|
-
` }`,
|
|
1276
|
-
` return isHydration;`,
|
|
1277
|
-
`}
|
|
1278
|
-
`,
|
|
1279
|
-
`function logHydrationError(error, componentName) {`,
|
|
1280
|
-
` if (!isDev) return;`,
|
|
1281
|
-
` if (window.__HMR_WS__ && window.__HMR_WS__.readyState === WebSocket.OPEN) {`,
|
|
1282
|
-
` try {`,
|
|
1283
|
-
` window.__HMR_WS__.send(JSON.stringify({`,
|
|
1284
|
-
` type: 'hydration-error',`,
|
|
1285
|
-
` data: {`,
|
|
1286
|
-
` componentName: '${componentName}',`,
|
|
1287
|
-
` componentPath: componentPath,`,
|
|
1288
|
-
` error: error instanceof Error ? error.message : String(error),`,
|
|
1289
|
-
` timestamp: Date.now()`,
|
|
1290
|
-
` }`,
|
|
1291
|
-
` }));`,
|
|
1292
|
-
` } catch (err) {}`,
|
|
1293
|
-
` }`,
|
|
1294
|
-
`}
|
|
1295
|
-
`,
|
|
1296
|
-
`// Track if we've already switched to client-only mode`,
|
|
1297
|
-
`let hasSwitchedToClientOnly = false;`,
|
|
1298
|
-
`let hydrationErrorDetected = false;
|
|
1299
|
-
`,
|
|
1300
|
-
`function handleHydrationFallback(error) {`,
|
|
1301
|
-
` if (hasSwitchedToClientOnly) return; // Already handled`,
|
|
1302
|
-
` hasSwitchedToClientOnly = true;`,
|
|
1303
|
-
` hydrationErrorDetected = true;
|
|
1304
|
-
`,
|
|
1305
|
-
` logHydrationError(error, '${componentName}');
|
|
1306
|
-
`,
|
|
1307
|
-
` // Fallback: client-only render (no hydration)`,
|
|
1308
|
-
` try {`,
|
|
1309
|
-
` // Unmount existing root if it exists`,
|
|
1310
|
-
` if (window.__REACT_ROOT__ && typeof window.__REACT_ROOT__.unmount === 'function') {`,
|
|
1311
|
-
` try {`,
|
|
1312
|
-
` window.__REACT_ROOT__.unmount();`,
|
|
1313
|
-
` } catch (e) {`,
|
|
1314
|
-
` // Ignore unmount errors`,
|
|
1315
|
-
` }`,
|
|
1316
|
-
` }
|
|
1317
|
-
`,
|
|
1318
|
-
` // Render into the same root container when falling back to client-only`,
|
|
1319
|
-
` const root = createRoot(container);`,
|
|
1320
|
-
` root.render(${isDev2 ? `createElement(ErrorBoundary, null, createElement(${componentName}, mergedProps))` : `createElement(${componentName}, mergedProps)`});`,
|
|
1321
|
-
` window.__REACT_ROOT__ = root;`,
|
|
1322
|
-
` window.__HMR_CLIENT_ONLY_MODE__ = true;`,
|
|
1323
|
-
` } catch (fallbackError) {`,
|
|
1324
|
-
` window.location.reload();`,
|
|
1325
|
-
` }`,
|
|
1326
|
-
`}
|
|
1327
|
-
`,
|
|
1328
|
-
`// HMR State Preservation: Check for preserved state and merge with initial props`,
|
|
1329
|
-
`// This allows state to be preserved across HMR updates without modifying component files`,
|
|
1330
|
-
`let preservedState = (typeof window !== 'undefined' && window.__HMR_PRESERVED_STATE__) ? window.__HMR_PRESERVED_STATE__ : {};
|
|
1331
|
-
`,
|
|
1332
|
-
`// Also check sessionStorage for state that survived a page reload (for React HMR)`,
|
|
1333
|
-
`if (typeof window !== 'undefined' && typeof sessionStorage !== 'undefined') {`,
|
|
1334
|
-
` const hmrStateJson = sessionStorage.getItem('__REACT_HMR_STATE__');`,
|
|
1335
|
-
` if (hmrStateJson) {`,
|
|
1336
|
-
` try {`,
|
|
1337
|
-
` const hmrState = JSON.parse(hmrStateJson);`,
|
|
1338
|
-
` preservedState = { ...preservedState, ...hmrState };`,
|
|
1339
|
-
` sessionStorage.removeItem('__REACT_HMR_STATE__');`,
|
|
1340
|
-
` } catch (e) {}`,
|
|
1341
|
-
` }`,
|
|
1342
|
-
`}
|
|
1343
|
-
`,
|
|
1344
|
-
`const mergedProps = { ...(window.__INITIAL_PROPS__ || {}), ...preservedState };`,
|
|
1345
|
-
`// Clear preserved state after using it (so it doesn't persist across multiple updates)`,
|
|
1346
|
-
`if (typeof window !== 'undefined') {`,
|
|
1347
|
-
` window.__HMR_PRESERVED_STATE__ = undefined;`,
|
|
1348
|
-
`}
|
|
1349
|
-
`,
|
|
1350
|
-
`// Attempt hydration with error handling`,
|
|
1351
|
-
`// Use document (not document.body) when the page renders <html><head><body>`,
|
|
1352
|
-
`// to avoid "In HTML, <html> cannot be a child of <body>" hydration error`,
|
|
1353
|
-
`const container = typeof document !== 'undefined' ? document : null;`,
|
|
1354
|
-
`if (!container) {`,
|
|
1355
|
-
` throw new Error('React root container not found: document is null');`,
|
|
1356
|
-
`}
|
|
1357
|
-
`,
|
|
1358
|
-
`// Guard: only hydrate on first load. During HMR re-imports, skip hydration`,
|
|
1359
|
-
`// so React Fast Refresh can swap components in-place and preserve state.`,
|
|
1360
|
-
`if (!window.__REACT_ROOT__) {`,
|
|
1361
|
-
` let root;`,
|
|
1362
|
-
` // After HMR, SSR is skipped to avoid stale content flash \u2014 render client-only`,
|
|
1363
|
-
` if (window.__SSR_DIRTY__) {`,
|
|
1364
|
-
` root = createRoot(container);`,
|
|
1365
|
-
` root.render(${isDev2 ? `createElement(ErrorBoundary, null, createElement(${componentName}, mergedProps))` : `createElement(${componentName}, mergedProps)`});`,
|
|
1366
|
-
` window.__REACT_ROOT__ = root;`,
|
|
1367
|
-
` } else {`,
|
|
1368
|
-
` try {`,
|
|
1369
|
-
` // Use onRecoverableError to catch hydration errors (React 19)`,
|
|
1370
|
-
` root = hydrateRoot(`,
|
|
1371
|
-
` container,`,
|
|
1372
|
-
` ${isDev2 ? `createElement(ErrorBoundary, null, createElement(${componentName}, mergedProps))` : `createElement(${componentName}, mergedProps)`},`,
|
|
1373
|
-
` {`,
|
|
1374
|
-
` onRecoverableError: (error) => {`,
|
|
1375
|
-
` // Check if this is a hydration error (isHydrationError filters out whitespace-only head mismatches)`,
|
|
1376
|
-
` if (isDev && isHydrationError(error)) {`,
|
|
1377
|
-
` // Real hydration error - handle it`,
|
|
1378
|
-
` handleHydrationFallback(error);`,
|
|
1379
|
-
` } else {`,
|
|
1380
|
-
` // Not a hydration error, or it's a whitespace-only mismatch that was filtered out`,
|
|
1381
|
-
` // Check if it's a whitespace-only head mismatch using the same logic as isHydrationError`,
|
|
1382
|
-
` const errorMessage = error instanceof Error ? error.message : String(error);`,
|
|
1383
|
-
` const errorString = String(error);`,
|
|
1384
|
-
` const fullMessage = errorMessage + ' ' + errorString;`,
|
|
1385
|
-
` const hydrationKeywords = ['hydration', 'Hydration', 'mismatch', 'Mismatch', 'did not match', 'server rendered HTML', 'server HTML', 'client HTML', 'Hydration failed'];`,
|
|
1386
|
-
` const isHydration = hydrationKeywords.some(keyword => fullMessage.includes(keyword));`,
|
|
1387
|
-
` if (isHydration) {`,
|
|
1388
|
-
` // Check if this is a head/link/stylesheet related mismatch`,
|
|
1389
|
-
` const isHeadRelated = fullMessage.includes('<head') || fullMessage.includes('</head>') || fullMessage.includes('head>') || fullMessage.includes('<link') || fullMessage.includes('link>') || fullMessage.includes('stylesheet') || fullMessage.includes('fonts.googleapis') || fullMessage.includes('rel="stylesheet"');`,
|
|
1390
|
-
` // Check if the mismatch involves only whitespace/newlines`,
|
|
1391
|
-
` const hasWhitespacePattern = /\\{\\s*["']\\\\n[^"']*["']\\s*\\}/.test(fullMessage) || /\\{\\s*["'][\\\\n\\\\r\\\\s]+["']\\s*\\}/.test(fullMessage) || /-\\s*\\{\\s*["'][\\\\n\\\\r\\\\s]+["']\\s*\\}/.test(fullMessage);`,
|
|
1392
|
-
` const isWhitespaceOnly = /^[\\s\\n\\r]*$/.test(errorString) || /^[\\s\\n\\r]*$/.test(errorMessage);`,
|
|
1393
|
-
` const hasNewlinePattern = fullMessage.includes('\\\\n') || fullMessage.includes('\\\\r') || fullMessage.includes('\\n') || fullMessage.includes('\\r');`,
|
|
1394
|
-
` // If it's head-related and involves whitespace/newlines, silently ignore it`,
|
|
1395
|
-
` if (isHeadRelated && (hasWhitespacePattern || isWhitespaceOnly || hasNewlinePattern)) {`,
|
|
1396
|
-
` // Already logged by isHydrationError, just return silently`,
|
|
1397
|
-
` return;`,
|
|
1398
|
-
` }`,
|
|
1399
|
-
` }`,
|
|
1400
|
-
` // Log other recoverable errors`,
|
|
1401
|
-
` console.error('React recoverable error:', error);`,
|
|
1402
|
-
` }`,
|
|
1403
|
-
` }`,
|
|
1404
|
-
` }`,
|
|
1405
|
-
` );`,
|
|
1406
|
-
` window.__REACT_ROOT__ = root;`,
|
|
1407
|
-
` } catch (error) {`,
|
|
1408
|
-
` // Catch synchronous errors (shouldn't happen with hydrateRoot, but safety net)`,
|
|
1409
|
-
` if (isDev && isHydrationError(error)) {`,
|
|
1410
|
-
` handleHydrationFallback(error);`,
|
|
1411
|
-
` } else {`,
|
|
1412
|
-
` throw error;`,
|
|
1413
|
-
` }`,
|
|
1414
|
-
` }`,
|
|
1415
|
-
` } // end else (normal hydration path)
|
|
1416
|
-
`,
|
|
1417
|
-
` // Also listen for hydration errors via console.error (React logs them there)`,
|
|
1418
|
-
` if (isDev) {`,
|
|
1419
|
-
` const originalError = console.error;`,
|
|
1420
|
-
` console.error = function(...args) {`,
|
|
1421
|
-
` const errorMessage = args.map(arg => {`,
|
|
1422
|
-
` if (arg instanceof Error) return arg.message;`,
|
|
1423
|
-
` return String(arg);`,
|
|
1424
|
-
` }).join(' ');`,
|
|
1425
|
-
` `,
|
|
1426
|
-
` // Check if this is a hydration error`,
|
|
1427
|
-
` if (isHydrationError({ message: errorMessage }) && !hydrationErrorDetected) {`,
|
|
1428
|
-
` hydrationErrorDetected = true;`,
|
|
1429
|
-
` // Create a synthetic error for fallback`,
|
|
1430
|
-
` const syntheticError = new Error(errorMessage);`,
|
|
1431
|
-
` // Use setTimeout to ensure this happens after React's error handling`,
|
|
1432
|
-
` setTimeout(() => {`,
|
|
1433
|
-
` handleHydrationFallback(syntheticError);`,
|
|
1434
|
-
` }, 0);`,
|
|
1435
|
-
` }`,
|
|
1436
|
-
` `,
|
|
1437
|
-
` // Call original console.error`,
|
|
1438
|
-
` originalError.apply(console, args);`,
|
|
1439
|
-
` };`,
|
|
1440
|
-
` }`,
|
|
1441
|
-
`}`,
|
|
1442
|
-
...isDev2 ? [
|
|
1443
|
-
`
|
|
1444
|
-
// Pre-warm: import the page module from the module server`,
|
|
1445
|
-
`// immediately so the browser caches all /@src/ URLs.`,
|
|
1446
|
-
`import('/@src/${relative2(process.cwd(), resolve6(reactPagesDirectory, `${componentName}.tsx`)).replace(/\\/g, "/")}').catch(() => {});`
|
|
1447
|
-
] : []
|
|
1448
|
-
].join(`
|
|
1449
|
-
`);
|
|
1450
|
-
const indexPath = join2(reactIndexesDirectory, `${componentName}.tsx`);
|
|
1451
|
-
const hasher = new Bun.CryptoHasher("md5");
|
|
1452
|
-
hasher.update(content);
|
|
1453
|
-
const contentHash = hasher.digest("hex");
|
|
1454
|
-
if (indexContentCache.get(indexPath) === contentHash && existsSync3(indexPath)) {
|
|
1455
|
-
return;
|
|
1456
|
-
}
|
|
1457
|
-
indexContentCache.set(indexPath, contentHash);
|
|
1458
|
-
await writeFile(indexPath, content);
|
|
1459
|
-
});
|
|
1460
|
-
await Promise.all(promises);
|
|
1461
|
-
if (!isDev2) {
|
|
1462
|
-
return;
|
|
1463
|
-
}
|
|
1464
|
-
const refreshPath = join2(reactIndexesDirectory, "_refresh.tsx");
|
|
1465
|
-
if (!existsSync3(refreshPath)) {
|
|
1466
|
-
await writeFile(refreshPath, `import '${refreshSetupPath}';
|
|
1467
|
-
import 'react';
|
|
1468
|
-
import 'react-dom/client';
|
|
1469
|
-
`);
|
|
1470
|
-
}
|
|
1471
|
-
};
|
|
1472
|
-
var init_generateReactIndexes = __esm(() => {
|
|
1473
|
-
indexContentCache = new Map;
|
|
1474
|
-
devClientDir = resolveDevClientDir();
|
|
1475
|
-
errorOverlayPath = join2(devClientDir, "errorOverlay.ts").replace(/\\/g, "/");
|
|
1476
|
-
hmrClientPath = join2(devClientDir, "hmrClient.ts").replace(/\\/g, "/");
|
|
1477
|
-
refreshSetupPath = join2(devClientDir, "reactRefreshSetup.ts").replace(/\\/g, "/");
|
|
1478
|
-
});
|
|
1479
|
-
|
|
1480
|
-
// src/build/islandBindingCompat.ts
|
|
1481
|
-
import { resolve as resolve7 } from "path";
|
|
1482
|
-
var packageToFramework, compatFileNames, normalize = (value) => value.replace(/\\/g, "/"), isFrameworkPackage = (value) => (value in packageToFramework), resolveIslandCompatModule = (specifier, importer, frameworkDirs) => {
|
|
1483
|
-
if (!isFrameworkPackage(specifier)) {
|
|
1484
|
-
return null;
|
|
1485
|
-
}
|
|
1486
|
-
const framework = packageToFramework[specifier];
|
|
1487
|
-
const frameworkDir = frameworkDirs[framework];
|
|
1488
|
-
if (!frameworkDir) {
|
|
1489
|
-
return null;
|
|
1490
|
-
}
|
|
1491
|
-
const normalizedImporter = normalize(importer);
|
|
1492
|
-
const normalizedFrameworkDir = normalize(resolve7(frameworkDir));
|
|
1493
|
-
if (!normalizedImporter.startsWith(normalizedFrameworkDir)) {
|
|
1494
|
-
return null;
|
|
1495
|
-
}
|
|
1496
|
-
if (normalizedImporter.includes("/generated/absolute-") || normalizedImporter.includes("/generated/Island.") || normalizedImporter.includes("/generated/islands.")) {
|
|
1497
|
-
return null;
|
|
1498
|
-
}
|
|
1499
|
-
return resolve7(frameworkDir, "generated", compatFileNames[framework]);
|
|
1500
|
-
};
|
|
1501
|
-
var init_islandBindingCompat = __esm(() => {
|
|
1502
|
-
packageToFramework = {
|
|
1503
|
-
"@absolutejs/absolute/angular": "angular",
|
|
1504
|
-
"@absolutejs/absolute/react": "react",
|
|
1505
|
-
"@absolutejs/absolute/svelte": "svelte",
|
|
1506
|
-
"@absolutejs/absolute/vue": "vue"
|
|
1507
|
-
};
|
|
1508
|
-
compatFileNames = {
|
|
1509
|
-
angular: "absolute-angular.ts",
|
|
1510
|
-
react: "absolute-react.ts",
|
|
1511
|
-
svelte: "absolute-svelte.ts",
|
|
1512
|
-
vue: "absolute-vue.ts"
|
|
1513
|
-
};
|
|
1514
|
-
});
|
|
1515
|
-
|
|
1516
|
-
// src/build/islandBindingPlugin.ts
|
|
1517
|
-
var exports_islandBindingPlugin = {};
|
|
1518
|
-
__export(exports_islandBindingPlugin, {
|
|
1519
|
-
createIslandBindingPlugin: () => createIslandBindingPlugin
|
|
1520
|
-
});
|
|
1521
|
-
var createIslandBindingPlugin = (frameworkDirs) => ({
|
|
1522
|
-
name: "absolute-island-binding-plugin",
|
|
1523
|
-
setup(build2) {
|
|
1524
|
-
build2.onResolve({
|
|
1525
|
-
filter: /^@absolutejs\/absolute\/(react|vue|svelte|angular)$/
|
|
1526
|
-
}, (args) => {
|
|
1527
|
-
const redirected = resolveIslandCompatModule(args.path, args.importer, frameworkDirs);
|
|
1528
|
-
if (!redirected) {
|
|
1529
|
-
return;
|
|
1530
|
-
}
|
|
1531
|
-
return {
|
|
1532
|
-
path: redirected
|
|
1533
|
-
};
|
|
1534
|
-
});
|
|
1535
|
-
}
|
|
1536
|
-
});
|
|
1537
|
-
var init_islandBindingPlugin = __esm(() => {
|
|
1538
|
-
init_islandBindingCompat();
|
|
1539
|
-
});
|
|
1540
|
-
|
|
1541
|
-
// src/build/wrapHTMLScript.ts
|
|
1542
|
-
var wrapHTMLScriptWithHMR = (code, scriptId) => {
|
|
1543
|
-
const escapedId = JSON.stringify(scriptId);
|
|
1544
|
-
return `${code}
|
|
1545
|
-
|
|
1546
|
-
// HMR acceptance - allows this script to be hot-reloaded
|
|
1547
|
-
if (typeof import.meta !== "undefined" && import.meta.hot) {
|
|
1548
|
-
import.meta.hot.accept();
|
|
1549
|
-
console.log('[HMR] Script ready:', ${escapedId});
|
|
1550
|
-
}
|
|
1551
|
-
`;
|
|
1552
|
-
};
|
|
1553
|
-
|
|
1554
|
-
// src/build/htmlScriptHMRPlugin.ts
|
|
1555
|
-
var scriptLoaders, toLoader = (ext) => {
|
|
1556
|
-
for (const loader of scriptLoaders) {
|
|
1557
|
-
if (loader === ext)
|
|
1558
|
-
return loader;
|
|
1559
|
-
}
|
|
1560
|
-
return "ts";
|
|
1561
|
-
}, createHTMLScriptHMRPlugin = (htmlDir, htmxDir) => ({
|
|
1562
|
-
name: "html-script-hmr",
|
|
1563
|
-
setup(build2) {
|
|
1564
|
-
build2.onLoad({ filter: /\.(ts|js|tsx|jsx)$/ }, async (args) => {
|
|
1565
|
-
const normalizedPath = args.path.replace(/\\/g, "/");
|
|
1566
|
-
const isHtmlScript = htmlDir && normalizedPath.includes(htmlDir.replace(/\\/g, "/")) && normalizedPath.includes("/scripts/");
|
|
1567
|
-
const isHtmxScript = htmxDir && normalizedPath.includes(htmxDir.replace(/\\/g, "/")) && normalizedPath.includes("/scripts/");
|
|
1568
|
-
if (!isHtmlScript && !isHtmxScript) {
|
|
1569
|
-
return;
|
|
1570
|
-
}
|
|
1571
|
-
const text = await Bun.file(args.path).text();
|
|
1572
|
-
const wrapped = wrapHTMLScriptWithHMR(text, normalizedPath);
|
|
1573
|
-
const ext = args.path.split(".").pop() ?? "ts";
|
|
1574
|
-
const loader = toLoader(ext);
|
|
1575
|
-
return {
|
|
1576
|
-
contents: wrapped,
|
|
1577
|
-
loader
|
|
1578
|
-
};
|
|
1579
|
-
});
|
|
1580
|
-
}
|
|
1581
|
-
});
|
|
1582
|
-
var init_htmlScriptHMRPlugin = __esm(() => {
|
|
1583
|
-
scriptLoaders = new Set(["ts", "js", "tsx", "jsx"]);
|
|
1584
|
-
});
|
|
1585
|
-
|
|
1586
206
|
// src/angular/injectorPatch.ts
|
|
1587
|
-
import { existsSync
|
|
1588
|
-
import { dirname
|
|
207
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
208
|
+
import { dirname, join, resolve } from "path";
|
|
1589
209
|
var applyInjectorPatch = (chunkPath, content) => {
|
|
1590
210
|
if (content.includes('Symbol.for("angular.currentInjector")')) {
|
|
1591
211
|
return;
|
|
@@ -1619,18 +239,18 @@ var applyInjectorPatch = (chunkPath, content) => {
|
|
|
1619
239
|
if (patched === content) {
|
|
1620
240
|
return;
|
|
1621
241
|
}
|
|
1622
|
-
|
|
242
|
+
writeFileSync(chunkPath, patched, "utf-8");
|
|
1623
243
|
}, resolveAngularCoreDir = () => {
|
|
1624
|
-
const fromProject =
|
|
1625
|
-
if (
|
|
244
|
+
const fromProject = resolve(process.cwd(), "node_modules/@angular/core");
|
|
245
|
+
if (existsSync(join(fromProject, "package.json"))) {
|
|
1626
246
|
return fromProject;
|
|
1627
247
|
}
|
|
1628
|
-
return
|
|
248
|
+
return dirname(__require.resolve("@angular/core/package.json"));
|
|
1629
249
|
}, patchAngularInjectorSingleton = () => {
|
|
1630
250
|
try {
|
|
1631
251
|
const coreDir = resolveAngularCoreDir();
|
|
1632
|
-
const chunkPath =
|
|
1633
|
-
const content =
|
|
252
|
+
const chunkPath = join(coreDir, "fesm2022", "_not_found-chunk.mjs");
|
|
253
|
+
const content = readFileSync(chunkPath, "utf-8");
|
|
1634
254
|
applyInjectorPatch(chunkPath, content);
|
|
1635
255
|
} catch {}
|
|
1636
256
|
};
|
|
@@ -1639,11 +259,11 @@ var init_injectorPatch = __esm(() => {
|
|
|
1639
259
|
});
|
|
1640
260
|
|
|
1641
261
|
// src/angular/resolveAngularPackage.ts
|
|
1642
|
-
import { existsSync as
|
|
1643
|
-
import { resolve as
|
|
262
|
+
import { existsSync as existsSync2 } from "fs";
|
|
263
|
+
import { resolve as resolve2 } from "path";
|
|
1644
264
|
var resolveAngularPackage = (specifier) => {
|
|
1645
|
-
const fromProject =
|
|
1646
|
-
if (
|
|
265
|
+
const fromProject = resolve2(process.cwd(), "node_modules", specifier);
|
|
266
|
+
if (existsSync2(fromProject)) {
|
|
1647
267
|
return fromProject;
|
|
1648
268
|
}
|
|
1649
269
|
return specifier;
|
|
@@ -1737,6 +357,14 @@ var init_angularDeps = __esm(() => {
|
|
|
1737
357
|
init_resolveAngularPackage();
|
|
1738
358
|
});
|
|
1739
359
|
|
|
360
|
+
// src/utils/stringModifiers.ts
|
|
361
|
+
var normalizeSlug = (str) => str.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-9\-_]+/g, "").replace(/[-_]{2,}/g, "-"), toKebab = (str) => normalizeSlug(str).replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), toPascal = (str) => {
|
|
362
|
+
if (!str.includes("-") && !str.includes("_")) {
|
|
363
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
364
|
+
}
|
|
365
|
+
return normalizeSlug(str).split(/[-_]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase()).join("");
|
|
366
|
+
}, toScreamingSnake = (str) => str.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toUpperCase();
|
|
367
|
+
|
|
1740
368
|
// src/utils/registerClientScript.ts
|
|
1741
369
|
var scriptRegistry, requestCounter = 0, getRequestId = () => `req_${Date.now()}_${++requestCounter}`, ssrContextGetter = null, getSsrContextId = () => ssrContextGetter?.() || Object.getOwnPropertyDescriptor(globalThis, "__absolutejs_requestId")?.value, registerClientScript = (script, requestId) => {
|
|
1742
370
|
const id = requestId || getSsrContextId() || getRequestId();
|
|
@@ -3278,8 +1906,8 @@ class SourceMapGenerator {
|
|
|
3278
1906
|
lines = [];
|
|
3279
1907
|
lastCol0 = 0;
|
|
3280
1908
|
hasMappings = false;
|
|
3281
|
-
constructor(
|
|
3282
|
-
this.file =
|
|
1909
|
+
constructor(file = null) {
|
|
1910
|
+
this.file = file;
|
|
3283
1911
|
}
|
|
3284
1912
|
addSource(url, content = null) {
|
|
3285
1913
|
if (!this.sourcesContent.has(url)) {
|
|
@@ -5172,8 +3800,8 @@ class ParseLocation {
|
|
|
5172
3800
|
offset;
|
|
5173
3801
|
line;
|
|
5174
3802
|
col;
|
|
5175
|
-
constructor(
|
|
5176
|
-
this.file =
|
|
3803
|
+
constructor(file, offset, line, col) {
|
|
3804
|
+
this.file = file;
|
|
5177
3805
|
this.offset = offset;
|
|
5178
3806
|
this.line = line;
|
|
5179
3807
|
this.col = col;
|
|
@@ -5906,12 +4534,12 @@ class ShadowCss {
|
|
|
5906
4534
|
let scopedSelector = "";
|
|
5907
4535
|
let startIndex = 0;
|
|
5908
4536
|
let res;
|
|
5909
|
-
const
|
|
4537
|
+
const sep = /( |>|\+|~(?!=))(?!([^)(]*(?:\([^)(]*(?:\([^)(]*(?:\([^)(]*\)[^)(]*)*\)[^)(]*)*\)[^)(]*)*\)))\s*/g;
|
|
5910
4538
|
const hasHost = selector.includes(_polyfillHostNoCombinator);
|
|
5911
4539
|
if (isParentSelector || this._shouldScopeIndicator) {
|
|
5912
4540
|
this._shouldScopeIndicator = !hasHost;
|
|
5913
4541
|
}
|
|
5914
|
-
while ((res =
|
|
4542
|
+
while ((res = sep.exec(selector)) !== null) {
|
|
5915
4543
|
const separator = res[1];
|
|
5916
4544
|
const part2 = selector.slice(startIndex, res.index);
|
|
5917
4545
|
if (part2.match(/__esc-ph-(\d+)__/) && selector[res.index + 1]?.match(/[a-fA-F\d]/)) {
|
|
@@ -5919,7 +4547,7 @@ class ShadowCss {
|
|
|
5919
4547
|
}
|
|
5920
4548
|
const scopedPart = _pseudoFunctionAwareScopeSelectorPart(part2);
|
|
5921
4549
|
scopedSelector += `${scopedPart} ${separator} `;
|
|
5922
|
-
startIndex =
|
|
4550
|
+
startIndex = sep.lastIndex;
|
|
5923
4551
|
}
|
|
5924
4552
|
const part = selector.substring(startIndex);
|
|
5925
4553
|
scopedSelector += _pseudoFunctionAwareScopeSelectorPart(part);
|
|
@@ -22376,13 +21004,13 @@ function getTemplateExpression(template2, templateInfo) {
|
|
|
22376
21004
|
return literal(templateInfo.content, null, null);
|
|
22377
21005
|
}
|
|
22378
21006
|
const contents = templateInfo.content;
|
|
22379
|
-
const
|
|
22380
|
-
const start = new ParseLocation(
|
|
22381
|
-
const end = computeEndLocation(
|
|
21007
|
+
const file = new ParseSourceFile(contents, templateInfo.sourceUrl);
|
|
21008
|
+
const start = new ParseLocation(file, 0, 0, 0);
|
|
21009
|
+
const end = computeEndLocation(file, contents);
|
|
22382
21010
|
const span = new ParseSourceSpan(start, end);
|
|
22383
21011
|
return literal(contents, null, span);
|
|
22384
21012
|
}
|
|
22385
|
-
function computeEndLocation(
|
|
21013
|
+
function computeEndLocation(file, contents) {
|
|
22386
21014
|
const length = contents.length;
|
|
22387
21015
|
let lineStart = 0;
|
|
22388
21016
|
let lastLineStart = 0;
|
|
@@ -22395,7 +21023,7 @@ function computeEndLocation(file2, contents) {
|
|
|
22395
21023
|
line++;
|
|
22396
21024
|
}
|
|
22397
21025
|
} while (lineStart !== -1);
|
|
22398
|
-
return new ParseLocation(
|
|
21026
|
+
return new ParseLocation(file, length, line, length - lastLineStart);
|
|
22399
21027
|
}
|
|
22400
21028
|
function compileUsedDependenciesMetadata(meta) {
|
|
22401
21029
|
const wrapType = meta.declarationListEmitMode !== 0 ? generateForwardRef : (expr) => expr;
|
|
@@ -30916,7 +29544,7 @@ If '${name}' is a directive input, make sure the directive is imported by the` +
|
|
|
30916
29544
|
transUnits.push(new CR(6), transUnit);
|
|
30917
29545
|
});
|
|
30918
29546
|
const body = new Tag("body", {}, [...transUnits, new CR(4)]);
|
|
30919
|
-
const
|
|
29547
|
+
const file = new Tag("file", {
|
|
30920
29548
|
"source-language": locale || _DEFAULT_SOURCE_LANG$1,
|
|
30921
29549
|
datatype: "plaintext",
|
|
30922
29550
|
original: "ng2.template"
|
|
@@ -30924,7 +29552,7 @@ If '${name}' is a directive input, make sure the directive is imported by the` +
|
|
|
30924
29552
|
const xliff = new Tag("xliff", {
|
|
30925
29553
|
version: _VERSION$1,
|
|
30926
29554
|
xmlns: _XMLNS$1
|
|
30927
|
-
}, [new CR(2),
|
|
29555
|
+
}, [new CR(2), file, new CR]);
|
|
30928
29556
|
return serialize$1([new Declaration({
|
|
30929
29557
|
version: "1.0",
|
|
30930
29558
|
encoding: "UTF-8"
|
|
@@ -30994,7 +29622,7 @@ ${errors.join(`
|
|
|
30994
29622
|
unit.children.push(new CR(6), segment, new CR(4));
|
|
30995
29623
|
units.push(new CR(4), unit);
|
|
30996
29624
|
});
|
|
30997
|
-
const
|
|
29625
|
+
const file = new Tag("file", {
|
|
30998
29626
|
original: "ng.template",
|
|
30999
29627
|
id: "ngi18n"
|
|
31000
29628
|
}, [...units, new CR(2)]);
|
|
@@ -31002,7 +29630,7 @@ ${errors.join(`
|
|
|
31002
29630
|
version: _VERSION,
|
|
31003
29631
|
xmlns: _XMLNS,
|
|
31004
29632
|
srcLang: locale || _DEFAULT_SOURCE_LANG
|
|
31005
|
-
}, [new CR(2),
|
|
29633
|
+
}, [new CR(2), file, new CR]);
|
|
31006
29634
|
return serialize$1([new Declaration({
|
|
31007
29635
|
version: "1.0",
|
|
31008
29636
|
encoding: "UTF-8"
|
|
@@ -31338,414 +29966,1789 @@ var ISLAND_TAG_RE, extractIslandAttribute = (attributeString, name) => {
|
|
|
31338
29966
|
if (quotedMatch?.[1]) {
|
|
31339
29967
|
return { expression: JSON.stringify(quotedMatch[1]), found: true };
|
|
31340
29968
|
}
|
|
31341
|
-
const attributeIndex = attributeString.search(new RegExp(`\\b${name}\\s*=\\s*\\{`));
|
|
31342
|
-
if (attributeIndex >= 0) {
|
|
31343
|
-
const braceStart = attributeString.indexOf("{", attributeIndex);
|
|
31344
|
-
if (braceStart >= 0) {
|
|
31345
|
-
let depth = 0;
|
|
31346
|
-
for (let index = braceStart;index < attributeString.length; index += 1) {
|
|
31347
|
-
const char = attributeString[index];
|
|
31348
|
-
if (char === "{") {
|
|
31349
|
-
depth += 1;
|
|
31350
|
-
}
|
|
31351
|
-
if (char === "}") {
|
|
31352
|
-
depth -= 1;
|
|
31353
|
-
if (depth === 0) {
|
|
31354
|
-
return {
|
|
31355
|
-
expression: attributeString.slice(braceStart + 1, index).trim(),
|
|
31356
|
-
found: true
|
|
31357
|
-
};
|
|
31358
|
-
}
|
|
31359
|
-
}
|
|
31360
|
-
}
|
|
31361
|
-
}
|
|
29969
|
+
const attributeIndex = attributeString.search(new RegExp(`\\b${name}\\s*=\\s*\\{`));
|
|
29970
|
+
if (attributeIndex >= 0) {
|
|
29971
|
+
const braceStart = attributeString.indexOf("{", attributeIndex);
|
|
29972
|
+
if (braceStart >= 0) {
|
|
29973
|
+
let depth = 0;
|
|
29974
|
+
for (let index = braceStart;index < attributeString.length; index += 1) {
|
|
29975
|
+
const char = attributeString[index];
|
|
29976
|
+
if (char === "{") {
|
|
29977
|
+
depth += 1;
|
|
29978
|
+
}
|
|
29979
|
+
if (char === "}") {
|
|
29980
|
+
depth -= 1;
|
|
29981
|
+
if (depth === 0) {
|
|
29982
|
+
return {
|
|
29983
|
+
expression: attributeString.slice(braceStart + 1, index).trim(),
|
|
29984
|
+
found: true
|
|
29985
|
+
};
|
|
29986
|
+
}
|
|
29987
|
+
}
|
|
29988
|
+
}
|
|
29989
|
+
}
|
|
29990
|
+
}
|
|
29991
|
+
return { expression: "", found: false };
|
|
29992
|
+
}, lowerSvelteIslandSyntax = (source, mode = "server") => {
|
|
29993
|
+
if (!source.includes("<Island")) {
|
|
29994
|
+
return { code: source, transformed: false };
|
|
29995
|
+
}
|
|
29996
|
+
let islandIndex = 0;
|
|
29997
|
+
const transformedMarkup = source.replace(ISLAND_TAG_RE, (fullMatch, attributeString) => {
|
|
29998
|
+
const framework = extractIslandAttribute(attributeString, "framework");
|
|
29999
|
+
const component = extractIslandAttribute(attributeString, "component");
|
|
30000
|
+
if (!framework.found || !component.found) {
|
|
30001
|
+
return fullMatch;
|
|
30002
|
+
}
|
|
30003
|
+
const hydrate = extractIslandAttribute(attributeString, "hydrate");
|
|
30004
|
+
const props = extractIslandAttribute(attributeString, "props");
|
|
30005
|
+
const slotId = `absolute-svelte-island-${islandIndex.toString(BASE_36_RADIX)}`;
|
|
30006
|
+
islandIndex += 1;
|
|
30007
|
+
const resolveExpression = `await __absoluteResolveIslandHtml(${JSON.stringify(slotId)}, { component: ${component.expression}, framework: ${framework.expression}, hydrate: ${hydrate.found ? hydrate.expression : JSON.stringify("load")}, props: ${props.found ? props.expression : "{}"} })`;
|
|
30008
|
+
return `<div data-absolute-island-slot="${slotId}" style="display: contents">{@html ${resolveExpression}}</div>`;
|
|
30009
|
+
});
|
|
30010
|
+
const importLine = 'import { resolveIslandHtml as __absoluteResolveIslandHtml } from "@absolutejs/absolute/svelte";';
|
|
30011
|
+
if (transformedMarkup.includes("<script")) {
|
|
30012
|
+
return {
|
|
30013
|
+
code: transformedMarkup.replace(/<script(\s[^>]*)?>/, (match) => `${match}
|
|
30014
|
+
${importLine}
|
|
30015
|
+
`),
|
|
30016
|
+
transformed: true
|
|
30017
|
+
};
|
|
30018
|
+
}
|
|
30019
|
+
return {
|
|
30020
|
+
code: `<script lang="ts">
|
|
30021
|
+
${importLine}
|
|
30022
|
+
</script>
|
|
30023
|
+
${transformedMarkup}`,
|
|
30024
|
+
transformed: true
|
|
30025
|
+
};
|
|
30026
|
+
};
|
|
30027
|
+
var init_lowerIslandSyntax = __esm(() => {
|
|
30028
|
+
init_constants();
|
|
30029
|
+
ISLAND_TAG_RE = /<Island\b([\s\S]*?)\/>/g;
|
|
30030
|
+
});
|
|
30031
|
+
|
|
30032
|
+
// src/core/svelteServerModule.ts
|
|
30033
|
+
import { mkdir } from "fs/promises";
|
|
30034
|
+
import { dirname as dirname2, extname, join as join2, relative, resolve as resolve3 } from "path";
|
|
30035
|
+
var serverCacheRoot, compiledModuleCache, transpiler, ensureRelativeImportPath = (from, to) => {
|
|
30036
|
+
const importPath = relative(dirname2(from), to).replace(/\\/g, "/");
|
|
30037
|
+
return importPath.startsWith(".") ? importPath : `./${importPath}`;
|
|
30038
|
+
}, resolveRelativeModule = async (spec, from) => {
|
|
30039
|
+
if (!spec.startsWith(".")) {
|
|
30040
|
+
return null;
|
|
30041
|
+
}
|
|
30042
|
+
const basePath = resolve3(dirname2(from), spec);
|
|
30043
|
+
const candidates = [
|
|
30044
|
+
basePath,
|
|
30045
|
+
`${basePath}.ts`,
|
|
30046
|
+
`${basePath}.js`,
|
|
30047
|
+
`${basePath}.mjs`,
|
|
30048
|
+
`${basePath}.cjs`,
|
|
30049
|
+
`${basePath}.json`,
|
|
30050
|
+
join2(basePath, "index.ts"),
|
|
30051
|
+
join2(basePath, "index.js"),
|
|
30052
|
+
join2(basePath, "index.mjs"),
|
|
30053
|
+
join2(basePath, "index.cjs"),
|
|
30054
|
+
join2(basePath, "index.json")
|
|
30055
|
+
];
|
|
30056
|
+
for (const candidate of candidates) {
|
|
30057
|
+
if (await Bun.file(candidate).exists() === true) {
|
|
30058
|
+
return candidate;
|
|
30059
|
+
}
|
|
30060
|
+
}
|
|
30061
|
+
return null;
|
|
30062
|
+
}, getCachedModulePath = (sourcePath) => {
|
|
30063
|
+
const relativeSourcePath = relative(process.cwd(), sourcePath).replace(/\\/g, "/");
|
|
30064
|
+
const normalizedSourcePath = relativeSourcePath.startsWith("..") ? sourcePath.replace(/[:\\/]/g, "_") : relativeSourcePath;
|
|
30065
|
+
return join2(serverCacheRoot, `${normalizedSourcePath}.server.js`);
|
|
30066
|
+
}, resolveSvelteImport = async (spec, from) => {
|
|
30067
|
+
if (spec.startsWith("/")) {
|
|
30068
|
+
return spec;
|
|
30069
|
+
}
|
|
30070
|
+
if (!spec.startsWith(".")) {
|
|
30071
|
+
return null;
|
|
30072
|
+
}
|
|
30073
|
+
const explicitPath = resolve3(dirname2(from), spec);
|
|
30074
|
+
if (extname(explicitPath) === ".svelte") {
|
|
30075
|
+
return explicitPath;
|
|
30076
|
+
}
|
|
30077
|
+
const candidate = `${explicitPath}.svelte`;
|
|
30078
|
+
if (await Bun.file(candidate).exists() === true) {
|
|
30079
|
+
return candidate;
|
|
30080
|
+
}
|
|
30081
|
+
return null;
|
|
30082
|
+
}, writeIfChanged = async (path, content) => {
|
|
30083
|
+
const targetFile = Bun.file(path);
|
|
30084
|
+
const exists = await targetFile.exists();
|
|
30085
|
+
if (exists) {
|
|
30086
|
+
const currentContent = await targetFile.text();
|
|
30087
|
+
if (currentContent === content) {
|
|
30088
|
+
return;
|
|
30089
|
+
}
|
|
30090
|
+
}
|
|
30091
|
+
await Bun.write(path, content);
|
|
30092
|
+
}, compileSvelteServerModule = async (sourcePath) => {
|
|
30093
|
+
const cachedModulePath = compiledModuleCache.get(sourcePath);
|
|
30094
|
+
if (cachedModulePath) {
|
|
30095
|
+
return cachedModulePath;
|
|
30096
|
+
}
|
|
30097
|
+
const source = await Bun.file(sourcePath).text();
|
|
30098
|
+
const { compile, preprocess } = await import("svelte/compiler");
|
|
30099
|
+
const loweredSource = lowerSvelteIslandSyntax(source, "server");
|
|
30100
|
+
const preprocessed = await preprocess(loweredSource.code, {});
|
|
30101
|
+
const transpiled = sourcePath.endsWith(".ts") || sourcePath.endsWith(".svelte.ts") ? transpiler.transformSync(preprocessed.code) : preprocessed.code;
|
|
30102
|
+
const childImportSpecs = Array.from(transpiled.matchAll(/from\s+['"]([^'"]+)['"]/g)).map((match) => match[1]).filter((value) => value !== undefined);
|
|
30103
|
+
const resolvedChildModules = await Promise.all(childImportSpecs.map((spec) => resolveSvelteImport(spec, sourcePath)));
|
|
30104
|
+
const resolvedModuleImports = await Promise.all(childImportSpecs.map((spec) => resolveRelativeModule(spec, sourcePath)));
|
|
30105
|
+
const childModulePaths = new Map;
|
|
30106
|
+
const rewrittenModulePaths = new Map;
|
|
30107
|
+
for (let index = 0;index < childImportSpecs.length; index += 1) {
|
|
30108
|
+
const spec = childImportSpecs[index];
|
|
30109
|
+
const resolvedChild = resolvedChildModules[index];
|
|
30110
|
+
if (!spec || !resolvedChild)
|
|
30111
|
+
continue;
|
|
30112
|
+
const compiledChildPath = await compileSvelteServerModule(resolvedChild);
|
|
30113
|
+
childModulePaths.set(spec, compiledChildPath);
|
|
30114
|
+
}
|
|
30115
|
+
for (let index = 0;index < childImportSpecs.length; index += 1) {
|
|
30116
|
+
const spec = childImportSpecs[index];
|
|
30117
|
+
const resolvedModuleImport = resolvedModuleImports[index];
|
|
30118
|
+
if (!spec || !resolvedModuleImport)
|
|
30119
|
+
continue;
|
|
30120
|
+
if (resolvedChildModules[index])
|
|
30121
|
+
continue;
|
|
30122
|
+
rewrittenModulePaths.set(spec, ensureRelativeImportPath(getCachedModulePath(sourcePath), resolvedModuleImport));
|
|
30123
|
+
}
|
|
30124
|
+
let compiledCode = compile(transpiled, {
|
|
30125
|
+
css: "injected",
|
|
30126
|
+
experimental: {
|
|
30127
|
+
async: loweredSource.transformed
|
|
30128
|
+
},
|
|
30129
|
+
filename: sourcePath,
|
|
30130
|
+
generate: "server"
|
|
30131
|
+
}).js.code;
|
|
30132
|
+
for (const [spec, compiledChildPath] of childModulePaths) {
|
|
30133
|
+
compiledCode = compiledCode.replaceAll(spec, ensureRelativeImportPath(getCachedModulePath(sourcePath), compiledChildPath));
|
|
30134
|
+
}
|
|
30135
|
+
for (const [spec, resolvedModuleImport] of rewrittenModulePaths) {
|
|
30136
|
+
compiledCode = compiledCode.replaceAll(spec, resolvedModuleImport);
|
|
30137
|
+
}
|
|
30138
|
+
const compiledModulePath = getCachedModulePath(sourcePath);
|
|
30139
|
+
await mkdir(dirname2(compiledModulePath), { recursive: true });
|
|
30140
|
+
await writeIfChanged(compiledModulePath, compiledCode);
|
|
30141
|
+
compiledModuleCache.set(sourcePath, compiledModulePath);
|
|
30142
|
+
return compiledModulePath;
|
|
30143
|
+
};
|
|
30144
|
+
var init_svelteServerModule = __esm(() => {
|
|
30145
|
+
init_lowerIslandSyntax();
|
|
30146
|
+
serverCacheRoot = join2(process.cwd(), ".absolutejs", "islands", "svelte");
|
|
30147
|
+
compiledModuleCache = new Map;
|
|
30148
|
+
transpiler = new Bun.Transpiler({
|
|
30149
|
+
loader: "ts",
|
|
30150
|
+
target: "browser"
|
|
30151
|
+
});
|
|
30152
|
+
});
|
|
30153
|
+
|
|
30154
|
+
// src/core/islandMarkupAttributes.ts
|
|
30155
|
+
var getIslandMarkerAttributes = (props, islandId) => ({
|
|
30156
|
+
"data-component": props.component,
|
|
30157
|
+
"data-framework": props.framework,
|
|
30158
|
+
"data-hydrate": props.hydrate ?? "load",
|
|
30159
|
+
"data-island": "true",
|
|
30160
|
+
...islandId ? { "data-island-id": islandId } : {},
|
|
30161
|
+
"data-props": serializeIslandProps(props.props)
|
|
30162
|
+
}), escapeHtmlAttribute = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<").replaceAll(">", ">"), serializeIslandAttributes = (attributes) => Object.entries(attributes).map(([key, value]) => `${key}="${escapeHtmlAttribute(value)}"`).join(" ");
|
|
30163
|
+
var init_islandMarkupAttributes = __esm(() => {
|
|
30164
|
+
init_islands();
|
|
30165
|
+
});
|
|
30166
|
+
|
|
30167
|
+
// src/core/renderIslandMarkup.ts
|
|
30168
|
+
var islandSequence = 0, resolvedServerComponentCache, resolvedServerBuildComponentCache, nextIslandId = () => {
|
|
30169
|
+
islandSequence += 1;
|
|
30170
|
+
return `island-${islandSequence}`;
|
|
30171
|
+
}, isRecord2 = (value) => typeof value === "object" && value !== null, isReactServerIslandComponent = (value) => typeof value === "function", isSvelteServerIslandComponent = (value) => typeof value === "function", isVueServerIslandComponent = (value) => typeof value === "function" || isRecord2(value), isAngularServerIslandComponent = (value) => typeof value === "function", resolveBuildReferencePath = (source, registryPath) => source.startsWith("file://") ? new URL(source).pathname : source.startsWith(".") ? new URL(source, registryPath).pathname : source, loadServerBuildComponent = async (buildReferencePath) => {
|
|
30172
|
+
const cachedBuildComponent = resolvedServerBuildComponentCache.get(buildReferencePath);
|
|
30173
|
+
if (cachedBuildComponent) {
|
|
30174
|
+
return cachedBuildComponent;
|
|
30175
|
+
}
|
|
30176
|
+
const loadPromise = (async () => {
|
|
30177
|
+
const compiledModulePath = await compileSvelteServerModule(buildReferencePath);
|
|
30178
|
+
const loadedModule = await import(compiledModulePath);
|
|
30179
|
+
return "default" in loadedModule ? loadedModule.default : loadedModule;
|
|
30180
|
+
})();
|
|
30181
|
+
resolvedServerBuildComponentCache.set(buildReferencePath, loadPromise);
|
|
30182
|
+
return loadPromise;
|
|
30183
|
+
}, loadServerImportComponent = async (resolvedComponent) => {
|
|
30184
|
+
const resolvedModulePath = resolvedComponent.startsWith(".") ? new URL(resolvedComponent, import.meta.url).pathname : resolvedComponent;
|
|
30185
|
+
const importTarget = resolvedModulePath.endsWith(".svelte") ? await compileSvelteServerModule(resolvedModulePath) : resolvedModulePath;
|
|
30186
|
+
const loadedModule = await import(importTarget);
|
|
30187
|
+
return "default" in loadedModule ? loadedModule.default : loadedModule;
|
|
30188
|
+
}, resolveServerIslandComponent = async (component) => {
|
|
30189
|
+
const cachedResolvedComponent = resolvedServerComponentCache.get(component);
|
|
30190
|
+
if (cachedResolvedComponent) {
|
|
30191
|
+
return cachedResolvedComponent;
|
|
30192
|
+
}
|
|
30193
|
+
const resolutionPromise = (async () => {
|
|
30194
|
+
const buildReference = getIslandBuildReference(component);
|
|
30195
|
+
const buildReferencePath = buildReference?.source ? resolveBuildReferencePath(buildReference.source, import.meta.url) : null;
|
|
30196
|
+
if (buildReferencePath?.endsWith(".svelte")) {
|
|
30197
|
+
return loadServerBuildComponent(buildReferencePath);
|
|
30198
|
+
}
|
|
30199
|
+
const resolvedComponent = getIslandComponent(component);
|
|
30200
|
+
if (typeof resolvedComponent !== "string") {
|
|
30201
|
+
return resolvedComponent;
|
|
30202
|
+
}
|
|
30203
|
+
return loadServerImportComponent(resolvedComponent);
|
|
30204
|
+
})();
|
|
30205
|
+
resolvedServerComponentCache.set(component, resolutionPromise);
|
|
30206
|
+
return resolutionPromise;
|
|
30207
|
+
}, resolveReactServerIslandComponent = async (component) => {
|
|
30208
|
+
const resolvedComponent = await resolveServerIslandComponent(component);
|
|
30209
|
+
if (!isReactServerIslandComponent(resolvedComponent)) {
|
|
30210
|
+
throw new Error("Resolved React island is not a valid React component.");
|
|
30211
|
+
}
|
|
30212
|
+
return resolvedComponent;
|
|
30213
|
+
}, resolveSvelteServerIslandComponent = async (component) => {
|
|
30214
|
+
const resolvedComponent = await resolveServerIslandComponent(component);
|
|
30215
|
+
if (!isSvelteServerIslandComponent(resolvedComponent)) {
|
|
30216
|
+
throw new Error("Resolved Svelte island is not a valid Svelte component.");
|
|
30217
|
+
}
|
|
30218
|
+
return resolvedComponent;
|
|
30219
|
+
}, resolveVueServerIslandComponent = async (component) => {
|
|
30220
|
+
const resolvedComponent = await resolveServerIslandComponent(component);
|
|
30221
|
+
if (!isVueServerIslandComponent(resolvedComponent)) {
|
|
30222
|
+
throw new Error("Resolved Vue island is not a valid Vue component.");
|
|
30223
|
+
}
|
|
30224
|
+
return resolvedComponent;
|
|
30225
|
+
}, resolveAngularServerIslandComponent = async (component) => {
|
|
30226
|
+
const resolvedComponent = await resolveServerIslandComponent(component);
|
|
30227
|
+
if (!isAngularServerIslandComponent(resolvedComponent)) {
|
|
30228
|
+
throw new Error("Resolved Angular island is not a valid Angular component.");
|
|
30229
|
+
}
|
|
30230
|
+
return resolvedComponent;
|
|
30231
|
+
}, renderIslandResult = async (registry, props) => {
|
|
30232
|
+
const islandId = nextIslandId();
|
|
30233
|
+
const attributes = getIslandMarkerAttributes(props);
|
|
30234
|
+
if (props.framework === "react") {
|
|
30235
|
+
const entry = registry.react?.[props.component];
|
|
30236
|
+
if (!entry) {
|
|
30237
|
+
throw new Error(`Island component "${props.component}" is not registered for framework "react".`);
|
|
30238
|
+
}
|
|
30239
|
+
const component = await resolveReactServerIslandComponent(entry);
|
|
30240
|
+
const html = renderReactIslandToHtml(component, props.props);
|
|
30241
|
+
return { attributes, html };
|
|
30242
|
+
}
|
|
30243
|
+
if (props.framework === "svelte") {
|
|
30244
|
+
const entry = registry.svelte?.[props.component];
|
|
30245
|
+
if (!entry) {
|
|
30246
|
+
throw new Error(`Island component "${props.component}" is not registered for framework "svelte".`);
|
|
30247
|
+
}
|
|
30248
|
+
const component = await resolveSvelteServerIslandComponent(entry);
|
|
30249
|
+
const html = renderSvelteIslandToHtml(component, props.props);
|
|
30250
|
+
return { attributes, html };
|
|
30251
|
+
}
|
|
30252
|
+
if (props.framework === "vue") {
|
|
30253
|
+
const entry = registry.vue?.[props.component];
|
|
30254
|
+
if (!entry) {
|
|
30255
|
+
throw new Error(`Island component "${props.component}" is not registered for framework "vue".`);
|
|
30256
|
+
}
|
|
30257
|
+
const component = await resolveVueServerIslandComponent(entry);
|
|
30258
|
+
const html = await renderVueIslandToHtml(component, props.props);
|
|
30259
|
+
return { attributes, html };
|
|
30260
|
+
}
|
|
30261
|
+
if (props.framework === "angular") {
|
|
30262
|
+
const entry = registry.angular?.[props.component];
|
|
30263
|
+
if (!entry) {
|
|
30264
|
+
throw new Error(`Island component "${props.component}" is not registered for framework "angular".`);
|
|
30265
|
+
}
|
|
30266
|
+
const component = await resolveAngularServerIslandComponent(entry);
|
|
30267
|
+
const html = await renderAngularIslandToHtml(component, props.props, islandId);
|
|
30268
|
+
return {
|
|
30269
|
+
attributes: {
|
|
30270
|
+
...getIslandMarkerAttributes(props, islandId)
|
|
30271
|
+
},
|
|
30272
|
+
html
|
|
30273
|
+
};
|
|
30274
|
+
}
|
|
30275
|
+
throw new Error(`Framework "${props.framework}" is not implemented in this prototype.`);
|
|
30276
|
+
}, renderIslandMarkup = async (registry, props) => {
|
|
30277
|
+
const result = await renderIslandResult(registry, props);
|
|
30278
|
+
return `<div ${serializeIslandAttributes(result.attributes)}>${result.html}</div>`;
|
|
30279
|
+
};
|
|
30280
|
+
var init_renderIslandMarkup = __esm(() => {
|
|
30281
|
+
init_islandSsr();
|
|
30282
|
+
init_svelteServerModule();
|
|
30283
|
+
init_islandMarkupAttributes();
|
|
30284
|
+
init_islands();
|
|
30285
|
+
resolvedServerComponentCache = new Map;
|
|
30286
|
+
resolvedServerBuildComponentCache = new Map;
|
|
30287
|
+
});
|
|
30288
|
+
|
|
30289
|
+
// src/build/islandEntries.ts
|
|
30290
|
+
import {
|
|
30291
|
+
mkdirSync,
|
|
30292
|
+
rmSync,
|
|
30293
|
+
writeFileSync as writeFileSync2
|
|
30294
|
+
} from "fs";
|
|
30295
|
+
import { dirname as dirname3, extname as extname2, join as join3, relative as relative2, resolve as resolve4 } from "path";
|
|
30296
|
+
var frameworks, isRecord3 = (value) => typeof value === "object" && value !== null, resolveRegistryExport = (mod) => {
|
|
30297
|
+
if (isRecord3(mod.islandRegistry))
|
|
30298
|
+
return mod.islandRegistry;
|
|
30299
|
+
if (isRecord3(mod.default))
|
|
30300
|
+
return mod.default;
|
|
30301
|
+
throw new Error("Island registry module must export `islandRegistry` or a default registry object.");
|
|
30302
|
+
}, normalizeImportPath = (wrapperPath, targetPath) => {
|
|
30303
|
+
const importPath = relative2(dirname3(wrapperPath), targetPath).replace(/\\/g, "/");
|
|
30304
|
+
return importPath.startsWith(".") ? importPath : `./${importPath}`;
|
|
30305
|
+
}, isIdentifier = (value) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value), resolveIslandSourcePath = (registryPath, sourcePath) => {
|
|
30306
|
+
if (sourcePath.startsWith("file://")) {
|
|
30307
|
+
return new URL(sourcePath).pathname;
|
|
30308
|
+
}
|
|
30309
|
+
return resolve4(dirname3(registryPath), sourcePath);
|
|
30310
|
+
}, createRegistryImportCode = (wrapperPath, registryPath, hasNamedExport) => {
|
|
30311
|
+
const normalizedPath = normalizeImportPath(wrapperPath, registryPath);
|
|
30312
|
+
if (hasNamedExport) {
|
|
30313
|
+
return {
|
|
30314
|
+
importStatement: `import { islandRegistry as __absoluteIslandRegistry } from ${JSON.stringify(normalizedPath)};`,
|
|
30315
|
+
registryReference: "__absoluteIslandRegistry"
|
|
30316
|
+
};
|
|
30317
|
+
}
|
|
30318
|
+
return {
|
|
30319
|
+
importStatement: `import __absoluteIslandRegistry from ${JSON.stringify(normalizedPath)};`,
|
|
30320
|
+
registryReference: "__absoluteIslandRegistry"
|
|
30321
|
+
};
|
|
30322
|
+
}, createDirectEntrySource = (wrapperPath, importPath, exportName) => {
|
|
30323
|
+
const normalizedImportPath = normalizeImportPath(wrapperPath, importPath);
|
|
30324
|
+
if (!exportName || exportName === "default") {
|
|
30325
|
+
return `export { default } from ${JSON.stringify(normalizedImportPath)};
|
|
30326
|
+
`;
|
|
30327
|
+
}
|
|
30328
|
+
return `export { ${exportName} as default } from ${JSON.stringify(normalizedImportPath)};
|
|
30329
|
+
`;
|
|
30330
|
+
}, createRegistryEntrySource = (wrapperPath, registryPath, hasNamedExport, framework, component) => {
|
|
30331
|
+
const { importStatement, registryReference } = createRegistryImportCode(wrapperPath, registryPath, hasNamedExport);
|
|
30332
|
+
const frameworkAccess = isIdentifier(framework) ? `${registryReference}.${framework}` : `${registryReference}[${JSON.stringify(framework)}]`;
|
|
30333
|
+
const componentAccess = isIdentifier(component) ? `${frameworkAccess}.${component}` : `${frameworkAccess}[${JSON.stringify(component)}]`;
|
|
30334
|
+
return `${importStatement}
|
|
30335
|
+
|
|
30336
|
+
const component = ${componentAccess};
|
|
30337
|
+
|
|
30338
|
+
export default component;
|
|
30339
|
+
`;
|
|
30340
|
+
}, shouldUseCompiledClientPath = (framework, sourcePath) => {
|
|
30341
|
+
if (framework === "svelte") {
|
|
30342
|
+
return /\.svelte(?:\.(?:ts|js))?$/.test(sourcePath);
|
|
30343
|
+
}
|
|
30344
|
+
if (framework === "vue") {
|
|
30345
|
+
return extname2(sourcePath) === ".vue";
|
|
30346
|
+
}
|
|
30347
|
+
return false;
|
|
30348
|
+
}, loadIslandRegistryBuildInfo = async (registryPath) => {
|
|
30349
|
+
const resolvedRegistryPath = resolve4(registryPath);
|
|
30350
|
+
const registryModule = await import(resolvedRegistryPath);
|
|
30351
|
+
const registry = resolveRegistryExport(registryModule);
|
|
30352
|
+
const definitions = [];
|
|
30353
|
+
for (const framework of frameworks) {
|
|
30354
|
+
const frameworkRegistry = registry[framework];
|
|
30355
|
+
if (!isRecord3(frameworkRegistry))
|
|
30356
|
+
continue;
|
|
30357
|
+
for (const [component, value] of Object.entries(frameworkRegistry)) {
|
|
30358
|
+
definitions.push({
|
|
30359
|
+
buildReference: getIslandBuildReference(value),
|
|
30360
|
+
component,
|
|
30361
|
+
framework
|
|
30362
|
+
});
|
|
30363
|
+
}
|
|
30364
|
+
}
|
|
30365
|
+
return {
|
|
30366
|
+
definitions,
|
|
30367
|
+
hasNamedExport: isRecord3(registryModule.islandRegistry),
|
|
30368
|
+
registry,
|
|
30369
|
+
resolvedRegistryPath
|
|
30370
|
+
};
|
|
30371
|
+
}, collectIslandFrameworkSources = (buildInfo) => {
|
|
30372
|
+
const sources = {};
|
|
30373
|
+
for (const definition of buildInfo.definitions) {
|
|
30374
|
+
const buildReference = definition.buildReference;
|
|
30375
|
+
if (!buildReference)
|
|
30376
|
+
continue;
|
|
30377
|
+
const resolvedSourcePath = resolveIslandSourcePath(buildInfo.resolvedRegistryPath, buildReference.source);
|
|
30378
|
+
if (!shouldUseCompiledClientPath(definition.framework, resolvedSourcePath)) {
|
|
30379
|
+
continue;
|
|
30380
|
+
}
|
|
30381
|
+
const frameworkSources = sources[definition.framework] ?? [];
|
|
30382
|
+
if (!frameworkSources.includes(resolvedSourcePath)) {
|
|
30383
|
+
frameworkSources.push(resolvedSourcePath);
|
|
30384
|
+
}
|
|
30385
|
+
sources[definition.framework] = frameworkSources;
|
|
30386
|
+
}
|
|
30387
|
+
return sources;
|
|
30388
|
+
}, generateIslandEntryPoints = async ({
|
|
30389
|
+
buildInfo,
|
|
30390
|
+
buildPath,
|
|
30391
|
+
clientPathMaps = {}
|
|
30392
|
+
}) => {
|
|
30393
|
+
const generatedRoot = join3(buildPath, "_island_entries");
|
|
30394
|
+
rmSync(generatedRoot, { force: true, recursive: true });
|
|
30395
|
+
const entries = [];
|
|
30396
|
+
for (const definition of buildInfo.definitions) {
|
|
30397
|
+
const entryPath = join3(generatedRoot, "islands", definition.framework, `${definition.component}.ts`);
|
|
30398
|
+
const buildReference = definition.buildReference;
|
|
30399
|
+
const source = buildReference ? resolveIslandSourcePath(buildInfo.resolvedRegistryPath, buildReference.source) : null;
|
|
30400
|
+
const compiledSourcePath = source && shouldUseCompiledClientPath(definition.framework, source) ? clientPathMaps[definition.framework]?.get(source) : undefined;
|
|
30401
|
+
const entrySource = source && (compiledSourcePath || !shouldUseCompiledClientPath(definition.framework, source)) ? createDirectEntrySource(entryPath, compiledSourcePath ?? source, compiledSourcePath ? undefined : buildReference?.export) : createRegistryEntrySource(entryPath, buildInfo.resolvedRegistryPath, buildInfo.hasNamedExport, definition.framework, definition.component);
|
|
30402
|
+
mkdirSync(dirname3(entryPath), { recursive: true });
|
|
30403
|
+
writeFileSync2(entryPath, entrySource);
|
|
30404
|
+
entries.push({
|
|
30405
|
+
component: definition.component,
|
|
30406
|
+
entryPath,
|
|
30407
|
+
framework: definition.framework
|
|
30408
|
+
});
|
|
30409
|
+
}
|
|
30410
|
+
return {
|
|
30411
|
+
entries,
|
|
30412
|
+
generatedRoot
|
|
30413
|
+
};
|
|
30414
|
+
};
|
|
30415
|
+
var init_islandEntries = __esm(() => {
|
|
30416
|
+
init_islands();
|
|
30417
|
+
frameworks = [
|
|
30418
|
+
"react",
|
|
30419
|
+
"svelte",
|
|
30420
|
+
"vue",
|
|
30421
|
+
"angular"
|
|
30422
|
+
];
|
|
30423
|
+
});
|
|
30424
|
+
|
|
30425
|
+
// src/core/currentIslandRegistry.ts
|
|
30426
|
+
var setCurrentIslandRegistry = (registry) => {
|
|
30427
|
+
globalThis.__absoluteIslandRegistry = registry;
|
|
30428
|
+
}, requireCurrentIslandRegistry = () => {
|
|
30429
|
+
const registry = globalThis.__absoluteIslandRegistry;
|
|
30430
|
+
if (!registry) {
|
|
30431
|
+
throw new Error("No island registry is active. Configure `islands.registry` in absolute.config.ts before rendering <Island />.");
|
|
30432
|
+
}
|
|
30433
|
+
return registry;
|
|
30434
|
+
};
|
|
30435
|
+
|
|
30436
|
+
// src/build/staticIslandPages.ts
|
|
30437
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
30438
|
+
var ISLAND_TAG_RE_SOURCE = "<(?:absolute-island|island)\\b([^>]*?)(?:\\/\\>|>(?:[\\s\\S]*?)<\\/(?:absolute-island|island)>)", ATTRIBUTE_RE_SOURCE = `([A-Za-z_:][-A-Za-z0-9_:.]*)\\s*=\\s*(?:"([^"]*)"|'([^']*)')`, islandFrameworks, islandHydrationModes, isRecord4 = (value) => typeof value === "object" && value !== null, isIslandFramework = (value) => islandFrameworks.some((framework) => framework === value), isIslandHydrationMode = (value) => islandHydrationModes.some((mode) => mode === value), parseIslandAttributes = (attributeString) => {
|
|
30439
|
+
const attributeRe = new RegExp(ATTRIBUTE_RE_SOURCE, "g");
|
|
30440
|
+
const attributes = new Map;
|
|
30441
|
+
let match = attributeRe.exec(attributeString);
|
|
30442
|
+
while (match) {
|
|
30443
|
+
const key = match[1];
|
|
30444
|
+
const doubleQuotedValue = match[2];
|
|
30445
|
+
const singleQuotedValue = match[3];
|
|
30446
|
+
if (!key) {
|
|
30447
|
+
match = attributeRe.exec(attributeString);
|
|
30448
|
+
continue;
|
|
30449
|
+
}
|
|
30450
|
+
const value = doubleQuotedValue ?? singleQuotedValue ?? "";
|
|
30451
|
+
attributes.set(key, value);
|
|
30452
|
+
match = attributeRe.exec(attributeString);
|
|
30453
|
+
}
|
|
30454
|
+
return attributes;
|
|
30455
|
+
}, parseIslandTag = (attributeString) => {
|
|
30456
|
+
const attributes = parseIslandAttributes(attributeString);
|
|
30457
|
+
const framework = attributes.get("framework");
|
|
30458
|
+
const component = attributes.get("component");
|
|
30459
|
+
const hydrate = attributes.get("hydrate") ?? "load";
|
|
30460
|
+
const propsSource = attributes.get("props") ?? "{}";
|
|
30461
|
+
if (!framework || !component) {
|
|
30462
|
+
return null;
|
|
30463
|
+
}
|
|
30464
|
+
if (!isIslandFramework(framework)) {
|
|
30465
|
+
throw new Error(`Unsupported static island framework "${framework}".`);
|
|
30466
|
+
}
|
|
30467
|
+
if (!isIslandHydrationMode(hydrate)) {
|
|
30468
|
+
throw new Error(`Unsupported static island hydrate mode "${hydrate}".`);
|
|
30469
|
+
}
|
|
30470
|
+
let parsedProps;
|
|
30471
|
+
try {
|
|
30472
|
+
const candidate = JSON.parse(propsSource);
|
|
30473
|
+
parsedProps = isRecord4(candidate) ? candidate : {};
|
|
30474
|
+
} catch (error) {
|
|
30475
|
+
throw new Error(`Failed to parse static island props JSON for ${framework}:${component}: ${error instanceof Error ? error.message : String(error)}`);
|
|
30476
|
+
}
|
|
30477
|
+
return {
|
|
30478
|
+
component,
|
|
30479
|
+
framework,
|
|
30480
|
+
hydrate,
|
|
30481
|
+
props: parsedProps
|
|
30482
|
+
};
|
|
30483
|
+
}, transformStaticPageHtml = async (originalHtml, registry) => {
|
|
30484
|
+
const islandTagRe = new RegExp(ISLAND_TAG_RE_SOURCE, "gi");
|
|
30485
|
+
if (!islandTagRe.test(originalHtml)) {
|
|
30486
|
+
return originalHtml;
|
|
30487
|
+
}
|
|
30488
|
+
islandTagRe.lastIndex = 0;
|
|
30489
|
+
let transformedHtml = "";
|
|
30490
|
+
let lastIndex = 0;
|
|
30491
|
+
let match = islandTagRe.exec(originalHtml);
|
|
30492
|
+
while (match) {
|
|
30493
|
+
const fullMatch = match[0];
|
|
30494
|
+
const attributeString = match[1] ?? "";
|
|
30495
|
+
const matchIndex = match.index;
|
|
30496
|
+
transformedHtml += originalHtml.slice(lastIndex, matchIndex);
|
|
30497
|
+
const props = parseIslandTag(attributeString);
|
|
30498
|
+
transformedHtml += props ? await renderIslandMarkup(registry, props) : fullMatch;
|
|
30499
|
+
lastIndex = matchIndex + fullMatch.length;
|
|
30500
|
+
match = islandTagRe.exec(originalHtml);
|
|
30501
|
+
}
|
|
30502
|
+
transformedHtml += originalHtml.slice(lastIndex);
|
|
30503
|
+
return transformedHtml;
|
|
30504
|
+
}, transformStaticPage = async (pagePath, registry) => {
|
|
30505
|
+
const originalHtml = readFileSync2(pagePath, "utf-8");
|
|
30506
|
+
const transformedHtml = await transformStaticPageHtml(originalHtml, registry);
|
|
30507
|
+
if (transformedHtml !== originalHtml) {
|
|
30508
|
+
writeFileSync3(pagePath, transformedHtml);
|
|
30509
|
+
}
|
|
30510
|
+
}, transformStaticPagesWithIslands = async (registryPath, pagePaths) => {
|
|
30511
|
+
if (!registryPath || pagePaths.length === 0) {
|
|
30512
|
+
return;
|
|
30513
|
+
}
|
|
30514
|
+
const { registry } = await loadIslandRegistryBuildInfo(registryPath);
|
|
30515
|
+
await Promise.all(pagePaths.map((pagePath) => transformStaticPage(pagePath, registry)));
|
|
30516
|
+
}, transformCurrentStaticPageHtml = async (html) => transformStaticPageHtml(html, requireCurrentIslandRegistry());
|
|
30517
|
+
var init_staticIslandPages = __esm(() => {
|
|
30518
|
+
init_renderIslandMarkup();
|
|
30519
|
+
init_islandEntries();
|
|
30520
|
+
islandFrameworks = [
|
|
30521
|
+
"react",
|
|
30522
|
+
"svelte",
|
|
30523
|
+
"vue",
|
|
30524
|
+
"angular"
|
|
30525
|
+
];
|
|
30526
|
+
islandHydrationModes = ["load", "idle", "visible", "none"];
|
|
30527
|
+
});
|
|
30528
|
+
|
|
30529
|
+
// src/core/islandPageContext.ts
|
|
30530
|
+
var BOOTSTRAP_MANIFEST_KEY = "BootstrapClient", ISLAND_MARKER = 'data-island="true"', MANIFEST_MARKER = "__ABSOLUTE_MANIFEST__", ISLAND_STATE_MARKER = "__ABS_ISLAND_STATE__", buildIslandsHeadMarkup = (manifest) => {
|
|
30531
|
+
const manifestScript = `<script>window.__ABSOLUTE_MANIFEST__ = ${JSON.stringify(manifest)}</script>`;
|
|
30532
|
+
const islandStateScript = "<script>window.__ABS_ISLAND_STATE__ = window.__ABS_ISLAND_STATE__ ?? {}</script>";
|
|
30533
|
+
const bootstrapPath = manifest[BOOTSTRAP_MANIFEST_KEY];
|
|
30534
|
+
const bootstrapScript = bootstrapPath ? `<script type="module" src="${bootstrapPath}"></script>` : "";
|
|
30535
|
+
return `${manifestScript}${islandStateScript}${bootstrapScript}`;
|
|
30536
|
+
}, injectHeadMarkup = (html, markup) => {
|
|
30537
|
+
const closingHeadIndex = html.indexOf("</head>");
|
|
30538
|
+
if (closingHeadIndex >= 0) {
|
|
30539
|
+
return `${html.slice(0, closingHeadIndex)}${markup}${html.slice(closingHeadIndex)}`;
|
|
30540
|
+
}
|
|
30541
|
+
const openingBodyIndex = html.indexOf("<body");
|
|
30542
|
+
if (openingBodyIndex >= 0) {
|
|
30543
|
+
const bodyStart = html.indexOf(">", openingBodyIndex);
|
|
30544
|
+
if (bodyStart >= 0) {
|
|
30545
|
+
return `${html.slice(0, openingBodyIndex)}<head>${markup}</head>${html.slice(openingBodyIndex)}`;
|
|
30546
|
+
}
|
|
30547
|
+
}
|
|
30548
|
+
return `<!DOCTYPE html><html><head>${markup}</head><body>${html}</body></html>`;
|
|
30549
|
+
}, setCurrentIslandManifest = (manifest) => {
|
|
30550
|
+
globalThis.__absoluteManifest = manifest;
|
|
30551
|
+
}, htmlContainsIslands = (html) => html.includes(ISLAND_MARKER), injectIslandPageContext = (html, options) => {
|
|
30552
|
+
const manifest = globalThis.__absoluteManifest;
|
|
30553
|
+
const hasIslands = options?.hasIslands ?? htmlContainsIslands(html);
|
|
30554
|
+
if (!manifest || !hasIslands) {
|
|
30555
|
+
return html;
|
|
30556
|
+
}
|
|
30557
|
+
if (html.includes(MANIFEST_MARKER) || html.includes(ISLAND_STATE_MARKER)) {
|
|
30558
|
+
return html;
|
|
30559
|
+
}
|
|
30560
|
+
return injectHeadMarkup(html, buildIslandsHeadMarkup(manifest));
|
|
30561
|
+
};
|
|
30562
|
+
|
|
30563
|
+
// src/utils/ssrErrorPage.ts
|
|
30564
|
+
var ssrErrorPage = (framework, error) => {
|
|
30565
|
+
const frameworkColors = {
|
|
30566
|
+
angular: "#dd0031",
|
|
30567
|
+
html: "#e34c26",
|
|
30568
|
+
htmx: "#1a365d",
|
|
30569
|
+
react: "#61dafb",
|
|
30570
|
+
svelte: "#ff3e00",
|
|
30571
|
+
vue: "#42b883"
|
|
30572
|
+
};
|
|
30573
|
+
const accent = frameworkColors[framework] ?? "#94a3b8";
|
|
30574
|
+
const label = framework.charAt(0).toUpperCase() + framework.slice(1);
|
|
30575
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
30576
|
+
return `<!DOCTYPE html>
|
|
30577
|
+
<html>
|
|
30578
|
+
<head>
|
|
30579
|
+
<meta charset="utf-8">
|
|
30580
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
30581
|
+
<title>SSR Error - AbsoluteJS</title>
|
|
30582
|
+
<style>
|
|
30583
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
30584
|
+
body{min-height:100vh;background:linear-gradient(135deg,rgba(15,23,42,0.98) 0%,rgba(30,41,59,0.98) 100%);color:#e2e8f0;font-family:"JetBrains Mono","Fira Code",ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:14px;line-height:1.6;display:flex;align-items:flex-start;justify-content:center;padding:32px}
|
|
30585
|
+
.card{max-width:720px;width:100%;background:rgba(30,41,59,0.6);border:1px solid rgba(71,85,105,0.5);border-radius:16px;box-shadow:0 25px 50px -12px rgba(0,0,0,0.5),0 0 0 1px rgba(255,255,255,0.05);overflow:hidden}
|
|
30586
|
+
.header{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:20px 24px;background:rgba(15,23,42,0.5);border-bottom:1px solid rgba(71,85,105,0.4)}
|
|
30587
|
+
.brand{font-weight:700;font-size:20px;color:#fff;letter-spacing:-0.02em}
|
|
30588
|
+
.badge{padding:5px 10px;border-radius:8px;font-size:12px;font-weight:600;background:${accent};color:#fff;opacity:0.95;box-shadow:0 2px 4px rgba(0,0,0,0.2)}
|
|
30589
|
+
.kind{color:#94a3b8;font-size:13px;font-weight:500}
|
|
30590
|
+
.content{padding:24px}
|
|
30591
|
+
.label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.08em;color:#94a3b8;margin-bottom:8px}
|
|
30592
|
+
.message{margin:0;padding:16px 20px;background:rgba(239,68,68,0.12);border:1px solid rgba(239,68,68,0.25);border-radius:10px;overflow-x:auto;white-space:pre-wrap;word-break:break-word;color:#fca5a5;font-size:13px;line-height:1.5}
|
|
30593
|
+
.hint{margin-top:20px;padding:12px 20px;background:rgba(71,85,105,0.3);border-radius:10px;border:1px solid rgba(71,85,105,0.4);color:#cbd5e1;font-size:13px}
|
|
30594
|
+
</style>
|
|
30595
|
+
</head>
|
|
30596
|
+
<body>
|
|
30597
|
+
<div class="card">
|
|
30598
|
+
<div class="header">
|
|
30599
|
+
<div style="display:flex;align-items:center;gap:12px">
|
|
30600
|
+
<span class="brand">AbsoluteJS</span>
|
|
30601
|
+
<span class="badge">${label}</span>
|
|
30602
|
+
</div>
|
|
30603
|
+
<span class="kind">Server Render Error</span>
|
|
30604
|
+
</div>
|
|
30605
|
+
<div class="content">
|
|
30606
|
+
<div class="label">What went wrong</div>
|
|
30607
|
+
<pre class="message">${message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")}</pre>
|
|
30608
|
+
<div class="hint">A component threw during server-side rendering. Check the terminal for the full stack trace.</div>
|
|
30609
|
+
</div>
|
|
30610
|
+
</div>
|
|
30611
|
+
</body>
|
|
30612
|
+
</html>`;
|
|
30613
|
+
};
|
|
30614
|
+
|
|
30615
|
+
// src/utils/resolveConvention.ts
|
|
30616
|
+
import { basename } from "path";
|
|
30617
|
+
var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boolean(value) && typeof value === "object", getMap = () => {
|
|
30618
|
+
const value = Reflect.get(globalThis, CONVENTIONS_KEY);
|
|
30619
|
+
if (isConventionsMap(value))
|
|
30620
|
+
return value;
|
|
30621
|
+
const empty = {};
|
|
30622
|
+
return empty;
|
|
30623
|
+
}, derivePageName = (pagePath) => {
|
|
30624
|
+
const base = basename(pagePath);
|
|
30625
|
+
const dotIndex = base.indexOf(".");
|
|
30626
|
+
const name = dotIndex > 0 ? base.slice(0, dotIndex) : base;
|
|
30627
|
+
return toPascal(name);
|
|
30628
|
+
}, resolveErrorConventionPath = (framework, pageName) => {
|
|
30629
|
+
const conventions2 = getMap()[framework];
|
|
30630
|
+
if (!conventions2)
|
|
30631
|
+
return;
|
|
30632
|
+
return conventions2.pages?.[pageName]?.error ?? conventions2.defaults?.error;
|
|
30633
|
+
}, resolveNotFoundConventionPath = (framework) => getMap()[framework]?.defaults?.notFound, setConventions = (map) => {
|
|
30634
|
+
Reflect.set(globalThis, CONVENTIONS_KEY, map);
|
|
30635
|
+
}, isDev = () => true, buildErrorProps = (error) => {
|
|
30636
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
30637
|
+
const stack = isDev() && error instanceof Error ? error.stack : undefined;
|
|
30638
|
+
return { error: { message, stack } };
|
|
30639
|
+
}, renderReactError = async (conventionPath, errorProps) => {
|
|
30640
|
+
const { createElement: createElement2 } = await import("react");
|
|
30641
|
+
const { renderToReadableStream } = await import("react-dom/server");
|
|
30642
|
+
const mod = await import(conventionPath);
|
|
30643
|
+
const [firstKey] = Object.keys(mod);
|
|
30644
|
+
const ErrorComponent = mod.default ?? (firstKey ? mod[firstKey] : undefined);
|
|
30645
|
+
const element2 = createElement2(ErrorComponent, errorProps);
|
|
30646
|
+
const stream = await renderToReadableStream(element2);
|
|
30647
|
+
return new Response(stream, {
|
|
30648
|
+
headers: { "Content-Type": "text/html" },
|
|
30649
|
+
status: 500
|
|
30650
|
+
});
|
|
30651
|
+
}, renderSvelteError = async (conventionPath, errorProps) => {
|
|
30652
|
+
const { render } = await import("svelte/server");
|
|
30653
|
+
const mod = await import(conventionPath);
|
|
30654
|
+
const ErrorComponent = mod.default;
|
|
30655
|
+
const { head, body } = render(ErrorComponent, {
|
|
30656
|
+
props: errorProps
|
|
30657
|
+
});
|
|
30658
|
+
const html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;
|
|
30659
|
+
return new Response(html, {
|
|
30660
|
+
headers: { "Content-Type": "text/html" },
|
|
30661
|
+
status: 500
|
|
30662
|
+
});
|
|
30663
|
+
}, unescapeVueStyles = (ssrBody) => {
|
|
30664
|
+
let styles = "";
|
|
30665
|
+
const body = ssrBody.replace(/<style>([\s\S]*?)<\/style>/g, (_, css) => {
|
|
30666
|
+
styles += `<style>${css.replace(/"/g, '"').replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")}</style>`;
|
|
30667
|
+
return "";
|
|
30668
|
+
});
|
|
30669
|
+
return { body, styles };
|
|
30670
|
+
}, renderVueError = async (conventionPath, errorProps) => {
|
|
30671
|
+
const { createSSRApp: createSSRApp2, h: h2 } = await import("vue");
|
|
30672
|
+
const { renderToString } = await import("vue/server-renderer");
|
|
30673
|
+
const mod = await import(conventionPath);
|
|
30674
|
+
const ErrorComponent = mod.default;
|
|
30675
|
+
const app = createSSRApp2({
|
|
30676
|
+
render: () => h2(ErrorComponent, errorProps)
|
|
30677
|
+
});
|
|
30678
|
+
const rawBody = await renderToString(app);
|
|
30679
|
+
const { styles, body } = unescapeVueStyles(rawBody);
|
|
30680
|
+
const html = `<!DOCTYPE html><html><head>${styles}</head><body><div id="root">${body}</div></body></html>`;
|
|
30681
|
+
return new Response(html, {
|
|
30682
|
+
headers: { "Content-Type": "text/html" },
|
|
30683
|
+
status: 500
|
|
30684
|
+
});
|
|
30685
|
+
}, renderAngularError = async (conventionPath, errorProps) => {
|
|
30686
|
+
const mod = await import(conventionPath);
|
|
30687
|
+
const renderError = mod.default ?? mod.renderError;
|
|
30688
|
+
if (typeof renderError !== "function")
|
|
30689
|
+
return null;
|
|
30690
|
+
const html = renderError(errorProps);
|
|
30691
|
+
return new Response(html, {
|
|
30692
|
+
headers: { "Content-Type": "text/html" },
|
|
30693
|
+
status: 500
|
|
30694
|
+
});
|
|
30695
|
+
}, logConventionRenderError = (framework, label, renderError) => {
|
|
30696
|
+
const message = renderError instanceof Error ? renderError.message : "";
|
|
30697
|
+
if (message.includes("Cannot find module") || message.includes("Cannot find package") || message.includes("not found in module")) {
|
|
30698
|
+
console.error(`[SSR] Convention ${label} page for ${framework} failed: missing framework package. Ensure the ${framework} runtime is installed (e.g. bun add ${framework === "react" ? "react react-dom" : framework}).`);
|
|
30699
|
+
return;
|
|
30700
|
+
}
|
|
30701
|
+
console.error(`[SSR] Failed to render ${framework} convention ${label} page:`, renderError);
|
|
30702
|
+
}, ERROR_RENDERERS, renderConventionError = async (framework, pageName, error) => {
|
|
30703
|
+
const conventionPath = resolveErrorConventionPath(framework, pageName);
|
|
30704
|
+
if (!conventionPath)
|
|
30705
|
+
return null;
|
|
30706
|
+
const errorProps = buildErrorProps(error);
|
|
30707
|
+
const renderer = ERROR_RENDERERS[framework];
|
|
30708
|
+
if (!renderer)
|
|
30709
|
+
return null;
|
|
30710
|
+
try {
|
|
30711
|
+
return await renderer(conventionPath, errorProps);
|
|
30712
|
+
} catch (renderError) {
|
|
30713
|
+
logConventionRenderError(framework, "error", renderError);
|
|
30714
|
+
}
|
|
30715
|
+
return null;
|
|
30716
|
+
}, renderReactNotFound = async (conventionPath) => {
|
|
30717
|
+
const { createElement: createElement2 } = await import("react");
|
|
30718
|
+
const { renderToReadableStream } = await import("react-dom/server");
|
|
30719
|
+
const mod = await import(conventionPath);
|
|
30720
|
+
const [nfKey] = Object.keys(mod);
|
|
30721
|
+
const NotFoundComponent = mod.default ?? (nfKey ? mod[nfKey] : undefined);
|
|
30722
|
+
const element2 = createElement2(NotFoundComponent);
|
|
30723
|
+
const stream = await renderToReadableStream(element2);
|
|
30724
|
+
return new Response(stream, {
|
|
30725
|
+
headers: { "Content-Type": "text/html" },
|
|
30726
|
+
status: 404
|
|
30727
|
+
});
|
|
30728
|
+
}, renderSvelteNotFound = async (conventionPath) => {
|
|
30729
|
+
const { render } = await import("svelte/server");
|
|
30730
|
+
const mod = await import(conventionPath);
|
|
30731
|
+
const NotFoundComponent = mod.default;
|
|
30732
|
+
const { head, body } = render(NotFoundComponent);
|
|
30733
|
+
const html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;
|
|
30734
|
+
return new Response(html, {
|
|
30735
|
+
headers: { "Content-Type": "text/html" },
|
|
30736
|
+
status: 404
|
|
30737
|
+
});
|
|
30738
|
+
}, renderVueNotFound = async (conventionPath) => {
|
|
30739
|
+
const { createSSRApp: createSSRApp2, h: h2 } = await import("vue");
|
|
30740
|
+
const { renderToString } = await import("vue/server-renderer");
|
|
30741
|
+
const mod = await import(conventionPath);
|
|
30742
|
+
const NotFoundComponent = mod.default;
|
|
30743
|
+
const app = createSSRApp2({
|
|
30744
|
+
render: () => h2(NotFoundComponent)
|
|
30745
|
+
});
|
|
30746
|
+
const rawBody = await renderToString(app);
|
|
30747
|
+
const { styles, body } = unescapeVueStyles(rawBody);
|
|
30748
|
+
const html = `<!DOCTYPE html><html><head>${styles}</head><body><div id="root">${body}</div></body></html>`;
|
|
30749
|
+
return new Response(html, {
|
|
30750
|
+
headers: { "Content-Type": "text/html" },
|
|
30751
|
+
status: 404
|
|
30752
|
+
});
|
|
30753
|
+
}, renderAngularNotFound = async (conventionPath) => {
|
|
30754
|
+
const mod = await import(conventionPath);
|
|
30755
|
+
const renderNotFound = mod.default ?? mod.renderNotFound;
|
|
30756
|
+
if (typeof renderNotFound !== "function")
|
|
30757
|
+
return null;
|
|
30758
|
+
const html = renderNotFound();
|
|
30759
|
+
return new Response(html, {
|
|
30760
|
+
headers: { "Content-Type": "text/html" },
|
|
30761
|
+
status: 404
|
|
30762
|
+
});
|
|
30763
|
+
}, NOT_FOUND_RENDERERS, renderConventionNotFound = async (framework) => {
|
|
30764
|
+
const conventionPath = resolveNotFoundConventionPath(framework);
|
|
30765
|
+
if (!conventionPath)
|
|
30766
|
+
return null;
|
|
30767
|
+
const renderer = NOT_FOUND_RENDERERS[framework];
|
|
30768
|
+
if (!renderer)
|
|
30769
|
+
return null;
|
|
30770
|
+
try {
|
|
30771
|
+
return await renderer(conventionPath);
|
|
30772
|
+
} catch (renderError) {
|
|
30773
|
+
logConventionRenderError(framework, "not-found", renderError);
|
|
30774
|
+
}
|
|
30775
|
+
return null;
|
|
30776
|
+
}, NOT_FOUND_PRIORITY, renderFirstNotFound = async () => {
|
|
30777
|
+
for (const framework of NOT_FOUND_PRIORITY) {
|
|
30778
|
+
if (!getMap()[framework]?.defaults?.notFound)
|
|
30779
|
+
continue;
|
|
30780
|
+
const response = await renderConventionNotFound(framework);
|
|
30781
|
+
if (response)
|
|
30782
|
+
return response;
|
|
30783
|
+
}
|
|
30784
|
+
return null;
|
|
30785
|
+
};
|
|
30786
|
+
var init_resolveConvention = __esm(() => {
|
|
30787
|
+
ERROR_RENDERERS = {
|
|
30788
|
+
angular: renderAngularError,
|
|
30789
|
+
react: renderReactError,
|
|
30790
|
+
svelte: renderSvelteError,
|
|
30791
|
+
vue: renderVueError
|
|
30792
|
+
};
|
|
30793
|
+
NOT_FOUND_RENDERERS = {
|
|
30794
|
+
angular: renderAngularNotFound,
|
|
30795
|
+
react: renderReactNotFound,
|
|
30796
|
+
svelte: renderSvelteNotFound,
|
|
30797
|
+
vue: renderVueNotFound
|
|
30798
|
+
};
|
|
30799
|
+
NOT_FOUND_PRIORITY = [
|
|
30800
|
+
"react",
|
|
30801
|
+
"svelte",
|
|
30802
|
+
"vue",
|
|
30803
|
+
"angular"
|
|
30804
|
+
];
|
|
30805
|
+
});
|
|
30806
|
+
|
|
30807
|
+
// src/react/pageHandler.ts
|
|
30808
|
+
var ssrDirty = false, buildDirtyResponse = (index, maybeProps) => {
|
|
30809
|
+
const propsScript = maybeProps ? `window.__INITIAL_PROPS__=${JSON.stringify(maybeProps)};` : "";
|
|
30810
|
+
const dirtyFlag = "window.__SSR_DIRTY__=true;";
|
|
30811
|
+
const refreshSetup = "window.__REFRESH_BUFFER__=[];" + "window.$RefreshReg$=function(t,i){window.__REFRESH_BUFFER__.push([t,i])};" + "window.$RefreshSig$=function(){return function(t){return t}};";
|
|
30812
|
+
const inlineScript = `${propsScript}${dirtyFlag}${refreshSetup}`;
|
|
30813
|
+
const html = `<!DOCTYPE html><html><head></head><body>` + `<script>${inlineScript}</script>` + `<script type="module" src="${index}"></script>` + `</body></html>`;
|
|
30814
|
+
return new Response(html, {
|
|
30815
|
+
headers: { "Content-Type": "text/html" }
|
|
30816
|
+
});
|
|
30817
|
+
}, handleReactPageRequest = async (PageComponent, index, ...props) => {
|
|
30818
|
+
const [maybeProps] = props;
|
|
30819
|
+
if (ssrDirty) {
|
|
30820
|
+
return buildDirtyResponse(index, maybeProps);
|
|
30821
|
+
}
|
|
30822
|
+
try {
|
|
30823
|
+
const { createElement: createElement2 } = await import("react");
|
|
30824
|
+
const { renderToReadableStream } = await import("react-dom/server");
|
|
30825
|
+
const element2 = maybeProps !== undefined ? createElement2(PageComponent, maybeProps) : createElement2(PageComponent);
|
|
30826
|
+
const propsScript = maybeProps ? `window.__INITIAL_PROPS__=${JSON.stringify(maybeProps)};` : "";
|
|
30827
|
+
const refreshSetup = "window.__REFRESH_BUFFER__=[];window.$RefreshReg$=function(t,i){window.__REFRESH_BUFFER__.push([t,i])};window.$RefreshSig$=function(){return function(t){return t}};";
|
|
30828
|
+
const stream = await renderToReadableStream(element2, {
|
|
30829
|
+
bootstrapModules: [index],
|
|
30830
|
+
bootstrapScriptContent: propsScript + refreshSetup || undefined,
|
|
30831
|
+
onError(error) {
|
|
30832
|
+
console.error("[SSR] React streaming error:", error);
|
|
30833
|
+
}
|
|
30834
|
+
});
|
|
30835
|
+
const html = injectIslandPageContext(await new Response(stream).text());
|
|
30836
|
+
return new Response(html, {
|
|
30837
|
+
headers: { "Content-Type": "text/html" }
|
|
30838
|
+
});
|
|
30839
|
+
} catch (error) {
|
|
30840
|
+
console.error("[SSR] React render error:", error);
|
|
30841
|
+
const pageName = PageComponent.name || PageComponent.displayName || "";
|
|
30842
|
+
const conventionResponse = await renderConventionError("react", pageName, error);
|
|
30843
|
+
if (conventionResponse)
|
|
30844
|
+
return conventionResponse;
|
|
30845
|
+
return new Response(ssrErrorPage("react", error), {
|
|
30846
|
+
headers: { "Content-Type": "text/html" },
|
|
30847
|
+
status: 500
|
|
30848
|
+
});
|
|
30849
|
+
}
|
|
30850
|
+
}, invalidateReactSsrCache = () => {
|
|
30851
|
+
ssrDirty = true;
|
|
30852
|
+
};
|
|
30853
|
+
var init_pageHandler = __esm(() => {
|
|
30854
|
+
init_resolveConvention();
|
|
30855
|
+
});
|
|
30856
|
+
|
|
30857
|
+
// src/build/scanEntryPoints.ts
|
|
30858
|
+
import { existsSync as existsSync3 } from "fs";
|
|
30859
|
+
var {Glob } = globalThis.Bun;
|
|
30860
|
+
var scanEntryPoints = async (dir, pattern) => {
|
|
30861
|
+
if (!existsSync3(dir))
|
|
30862
|
+
return [];
|
|
30863
|
+
const entryPaths = [];
|
|
30864
|
+
const glob = new Glob(pattern);
|
|
30865
|
+
for await (const file2 of glob.scan({ absolute: true, cwd: dir })) {
|
|
30866
|
+
entryPaths.push(file2);
|
|
30867
|
+
}
|
|
30868
|
+
return entryPaths;
|
|
30869
|
+
};
|
|
30870
|
+
var init_scanEntryPoints = () => {};
|
|
30871
|
+
|
|
30872
|
+
// src/islands/sourceMetadata.ts
|
|
30873
|
+
var islandFrameworks2, islandHydrationModes2, isIslandFramework2 = (value) => islandFrameworks2.some((framework) => framework === value), isIslandHydrate = (value) => islandHydrationModes2.some((hydrate) => hydrate === value), parseIslandTagAttributes = (attributeString) => {
|
|
30874
|
+
const frameworkMatch = attributeString.match(/\bframework\s*=\s*["']([^"']+)["']/);
|
|
30875
|
+
const componentMatch = attributeString.match(/\bcomponent\s*=\s*["']([^"']+)["']/);
|
|
30876
|
+
const hydrateMatch = attributeString.match(/\bhydrate\s*=\s*["']([^"']+)["']/);
|
|
30877
|
+
const framework = frameworkMatch?.[1];
|
|
30878
|
+
const component = componentMatch?.[1];
|
|
30879
|
+
if (!framework || !component) {
|
|
30880
|
+
return null;
|
|
30881
|
+
}
|
|
30882
|
+
if (!isIslandFramework2(framework)) {
|
|
30883
|
+
return null;
|
|
30884
|
+
}
|
|
30885
|
+
const hydrateCandidate = hydrateMatch?.[1];
|
|
30886
|
+
return {
|
|
30887
|
+
component,
|
|
30888
|
+
framework,
|
|
30889
|
+
hydrate: hydrateCandidate && isIslandHydrate(hydrateCandidate) ? hydrateCandidate : undefined
|
|
30890
|
+
};
|
|
30891
|
+
}, normalizeUsage = (usage) => `${usage.framework}:${usage.component}:${usage.hydrate ?? ""}`, addUsage = (usageMap, usage) => {
|
|
30892
|
+
if (!usage)
|
|
30893
|
+
return;
|
|
30894
|
+
usageMap.set(normalizeUsage(usage), usage);
|
|
30895
|
+
}, extractIslandUsagesFromSource = (source) => {
|
|
30896
|
+
const usageMap = new Map;
|
|
30897
|
+
const islandTagRegex = /<Island\b([\s\S]*?)(?:\/>|>(?:[\s\S]*?)<\/Island>)/g;
|
|
30898
|
+
let islandTagMatch = islandTagRegex.exec(source);
|
|
30899
|
+
while (islandTagMatch) {
|
|
30900
|
+
addUsage(usageMap, parseIslandTagAttributes(islandTagMatch[1] ?? ""));
|
|
30901
|
+
islandTagMatch = islandTagRegex.exec(source);
|
|
30902
|
+
}
|
|
30903
|
+
const staticRenderCallRegex = /renderIsland\s*\(\s*\{[\s\S]*?\bframework\s*:\s*['"]([^'"]+)['"][\s\S]*?\bcomponent\s*:\s*['"]([^'"]+)['"](?:[\s\S]*?\bhydrate\s*:\s*['"]([^'"]+)['"])?[\s\S]*?\}\s*\)/g;
|
|
30904
|
+
let renderMatch = staticRenderCallRegex.exec(source);
|
|
30905
|
+
while (renderMatch) {
|
|
30906
|
+
const framework = renderMatch[1];
|
|
30907
|
+
const component = renderMatch[2];
|
|
30908
|
+
const hydrate = renderMatch[3];
|
|
30909
|
+
if (!framework || !component || !isIslandFramework2(framework)) {
|
|
30910
|
+
renderMatch = staticRenderCallRegex.exec(source);
|
|
30911
|
+
continue;
|
|
30912
|
+
}
|
|
30913
|
+
addUsage(usageMap, {
|
|
30914
|
+
component,
|
|
30915
|
+
framework,
|
|
30916
|
+
hydrate: hydrate && isIslandHydrate(hydrate) ? hydrate : undefined
|
|
30917
|
+
});
|
|
30918
|
+
renderMatch = staticRenderCallRegex.exec(source);
|
|
30919
|
+
}
|
|
30920
|
+
return [...usageMap.values()];
|
|
30921
|
+
}, buildIslandMetadataExports = (source) => {
|
|
30922
|
+
const usages = extractIslandUsagesFromSource(source);
|
|
30923
|
+
const serialized = JSON.stringify(usages);
|
|
30924
|
+
return `
|
|
30925
|
+
export const __ABSOLUTE_PAGE_ISLANDS__ = ${serialized};
|
|
30926
|
+
export const __ABSOLUTE_PAGE_HAS_ISLANDS__ = ${usages.length > 0};
|
|
30927
|
+
`;
|
|
30928
|
+
};
|
|
30929
|
+
var init_sourceMetadata = __esm(() => {
|
|
30930
|
+
islandFrameworks2 = [
|
|
30931
|
+
"react",
|
|
30932
|
+
"svelte",
|
|
30933
|
+
"vue",
|
|
30934
|
+
"angular"
|
|
30935
|
+
];
|
|
30936
|
+
islandHydrationModes2 = [
|
|
30937
|
+
"load",
|
|
30938
|
+
"idle",
|
|
30939
|
+
"visible",
|
|
30940
|
+
"none"
|
|
30941
|
+
];
|
|
30942
|
+
});
|
|
30943
|
+
|
|
30944
|
+
// src/islands/pageMetadata.ts
|
|
30945
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
30946
|
+
import { dirname as dirname4, resolve as resolve7 } from "path";
|
|
30947
|
+
var pagePatterns, getPageDirs = (config) => [
|
|
30948
|
+
{ dir: config.angularDirectory, framework: "angular" },
|
|
30949
|
+
{ dir: config.reactDirectory, framework: "react" },
|
|
30950
|
+
{ dir: config.svelteDirectory, framework: "svelte" },
|
|
30951
|
+
{ dir: config.vueDirectory, framework: "vue" },
|
|
30952
|
+
{ dir: config.htmlDirectory, framework: "html" },
|
|
30953
|
+
{ dir: config.htmxDirectory, framework: "htmx" }
|
|
30954
|
+
].filter((entry) => typeof entry.dir === "string" && entry.dir.length > 0), buildIslandSourceLookup = async (config) => {
|
|
30955
|
+
const registryPath = config.islands?.registry;
|
|
30956
|
+
if (!registryPath) {
|
|
30957
|
+
return new Map;
|
|
30958
|
+
}
|
|
30959
|
+
const buildInfo = await loadIslandRegistryBuildInfo(registryPath);
|
|
30960
|
+
const lookup = new Map;
|
|
30961
|
+
for (const definition of buildInfo.definitions) {
|
|
30962
|
+
const source = definition.buildReference?.source;
|
|
30963
|
+
if (!source)
|
|
30964
|
+
continue;
|
|
30965
|
+
const resolvedSource = source.startsWith("file://") ? new URL(source).pathname : resolve7(dirname4(buildInfo.resolvedRegistryPath), source);
|
|
30966
|
+
lookup.set(`${definition.framework}:${definition.component}`, resolve7(resolvedSource));
|
|
31362
30967
|
}
|
|
31363
|
-
return
|
|
31364
|
-
},
|
|
31365
|
-
|
|
31366
|
-
|
|
30968
|
+
return lookup;
|
|
30969
|
+
}, loadPageIslandMetadata = async (config) => {
|
|
30970
|
+
const pageMetadata = new Map;
|
|
30971
|
+
const islandSourceLookup = await buildIslandSourceLookup(config);
|
|
30972
|
+
for (const entry of getPageDirs(config)) {
|
|
30973
|
+
const pattern = pagePatterns[entry.framework];
|
|
30974
|
+
if (!pattern)
|
|
30975
|
+
continue;
|
|
30976
|
+
const files = await scanEntryPoints(resolve7(entry.dir), pattern);
|
|
30977
|
+
for (const filePath of files) {
|
|
30978
|
+
const source = readFileSync3(filePath, "utf-8");
|
|
30979
|
+
const islands = extractIslandUsagesFromSource(source);
|
|
30980
|
+
pageMetadata.set(resolve7(filePath), {
|
|
30981
|
+
islands: islands.map((usage) => {
|
|
30982
|
+
const sourcePath = islandSourceLookup.get(`${usage.framework}:${usage.component}`);
|
|
30983
|
+
return sourcePath ? {
|
|
30984
|
+
...usage,
|
|
30985
|
+
source: sourcePath
|
|
30986
|
+
} : usage;
|
|
30987
|
+
}),
|
|
30988
|
+
pagePath: resolve7(filePath)
|
|
30989
|
+
});
|
|
30990
|
+
}
|
|
31367
30991
|
}
|
|
31368
|
-
|
|
31369
|
-
|
|
31370
|
-
|
|
31371
|
-
|
|
31372
|
-
|
|
31373
|
-
|
|
30992
|
+
return pageMetadata;
|
|
30993
|
+
}, setCurrentPageIslandMetadata = (metadata2) => {
|
|
30994
|
+
globalThis.__absolutePageIslandMetadata = metadata2;
|
|
30995
|
+
}, getCurrentPageIslandMetadata = () => globalThis.__absolutePageIslandMetadata ?? new Map, getPagesUsingIslandSource = (sourcePath) => {
|
|
30996
|
+
const target = resolve7(sourcePath);
|
|
30997
|
+
const matches = [];
|
|
30998
|
+
for (const metadata2 of getCurrentPageIslandMetadata().values()) {
|
|
30999
|
+
const usesTarget = metadata2.islands.some((usage) => {
|
|
31000
|
+
const candidate = usage.source;
|
|
31001
|
+
return candidate ? resolve7(candidate) === target : false;
|
|
31002
|
+
});
|
|
31003
|
+
if (usesTarget) {
|
|
31004
|
+
matches.push(metadata2.pagePath);
|
|
31374
31005
|
}
|
|
31375
|
-
const hydrate = extractIslandAttribute(attributeString, "hydrate");
|
|
31376
|
-
const props = extractIslandAttribute(attributeString, "props");
|
|
31377
|
-
const slotId = `absolute-svelte-island-${islandIndex.toString(BASE_36_RADIX)}`;
|
|
31378
|
-
islandIndex += 1;
|
|
31379
|
-
const resolveExpression = `await __absoluteResolveIslandHtml(${JSON.stringify(slotId)}, { component: ${component.expression}, framework: ${framework.expression}, hydrate: ${hydrate.found ? hydrate.expression : JSON.stringify("load")}, props: ${props.found ? props.expression : "{}"} })`;
|
|
31380
|
-
return `<div data-absolute-island-slot="${slotId}" style="display: contents">{@html ${resolveExpression}}</div>`;
|
|
31381
|
-
});
|
|
31382
|
-
const importLine = 'import { resolveIslandHtml as __absoluteResolveIslandHtml } from "@absolutejs/absolute/svelte";';
|
|
31383
|
-
if (transformedMarkup.includes("<script")) {
|
|
31384
|
-
return {
|
|
31385
|
-
code: transformedMarkup.replace(/<script(\s[^>]*)?>/, (match) => `${match}
|
|
31386
|
-
${importLine}
|
|
31387
|
-
`),
|
|
31388
|
-
transformed: true
|
|
31389
|
-
};
|
|
31390
31006
|
}
|
|
31391
|
-
return
|
|
31392
|
-
code: `<script lang="ts">
|
|
31393
|
-
${importLine}
|
|
31394
|
-
</script>
|
|
31395
|
-
${transformedMarkup}`,
|
|
31396
|
-
transformed: true
|
|
31397
|
-
};
|
|
31007
|
+
return matches;
|
|
31398
31008
|
};
|
|
31399
|
-
var
|
|
31400
|
-
|
|
31401
|
-
|
|
31009
|
+
var init_pageMetadata = __esm(() => {
|
|
31010
|
+
init_islandEntries();
|
|
31011
|
+
init_scanEntryPoints();
|
|
31012
|
+
init_sourceMetadata();
|
|
31013
|
+
pagePatterns = {
|
|
31014
|
+
angular: "pages/**/*.{ts,js}",
|
|
31015
|
+
html: "pages/**/*.html",
|
|
31016
|
+
htmx: "pages/**/*.html",
|
|
31017
|
+
react: "pages/**/*.{ts,tsx,js,jsx}",
|
|
31018
|
+
svelte: "pages/**/*.svelte",
|
|
31019
|
+
vue: "pages/**/*.vue"
|
|
31020
|
+
};
|
|
31402
31021
|
});
|
|
31403
31022
|
|
|
31404
|
-
// src/
|
|
31405
|
-
|
|
31406
|
-
|
|
31407
|
-
|
|
31408
|
-
|
|
31409
|
-
|
|
31410
|
-
|
|
31411
|
-
|
|
31412
|
-
|
|
31413
|
-
|
|
31414
|
-
|
|
31415
|
-
|
|
31416
|
-
|
|
31417
|
-
|
|
31418
|
-
|
|
31419
|
-
`${basePath}.mjs`,
|
|
31420
|
-
`${basePath}.cjs`,
|
|
31421
|
-
`${basePath}.json`,
|
|
31422
|
-
join4(basePath, "index.ts"),
|
|
31423
|
-
join4(basePath, "index.js"),
|
|
31424
|
-
join4(basePath, "index.mjs"),
|
|
31425
|
-
join4(basePath, "index.cjs"),
|
|
31426
|
-
join4(basePath, "index.json")
|
|
31427
|
-
];
|
|
31428
|
-
for (const candidate of candidates) {
|
|
31429
|
-
if (await Bun.file(candidate).exists() === true) {
|
|
31430
|
-
return candidate;
|
|
31431
|
-
}
|
|
31023
|
+
// src/build/generateIslandBindings.ts
|
|
31024
|
+
var exports_generateIslandBindings = {};
|
|
31025
|
+
__export(exports_generateIslandBindings, {
|
|
31026
|
+
generateIslandBindings: () => generateIslandBindings
|
|
31027
|
+
});
|
|
31028
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
31029
|
+
import { dirname as dirname5, resolve as resolve8 } from "path";
|
|
31030
|
+
var ensureDir = (filePath) => {
|
|
31031
|
+
mkdirSync2(dirname5(filePath), { recursive: true });
|
|
31032
|
+
}, writeIfChanged2 = (filePath, content) => {
|
|
31033
|
+
ensureDir(filePath);
|
|
31034
|
+
writeFileSync4(filePath, content);
|
|
31035
|
+
}, removeIfExists = (filePath) => {
|
|
31036
|
+
if (existsSync4(filePath)) {
|
|
31037
|
+
rmSync2(filePath, { force: true });
|
|
31432
31038
|
}
|
|
31433
|
-
|
|
31434
|
-
|
|
31435
|
-
|
|
31436
|
-
|
|
31437
|
-
return join4(serverCacheRoot, `${normalizedSourcePath}.server.js`);
|
|
31438
|
-
}, resolveSvelteImport = async (spec, from) => {
|
|
31439
|
-
if (spec.startsWith("/")) {
|
|
31440
|
-
return spec;
|
|
31039
|
+
}, generateIslandBindings = (projectRoot, config) => {
|
|
31040
|
+
const registryPath = config.islands?.registry;
|
|
31041
|
+
if (!registryPath) {
|
|
31042
|
+
return;
|
|
31441
31043
|
}
|
|
31442
|
-
|
|
31443
|
-
|
|
31044
|
+
const resolvedRegistryPath = resolve8(projectRoot, registryPath);
|
|
31045
|
+
removeIfExists(resolve8(dirname5(resolvedRegistryPath), "absolute-islands.d.ts"));
|
|
31046
|
+
if (config.reactDirectory) {
|
|
31047
|
+
const compatTarget = resolve8(config.reactDirectory, "generated", "absolute-react.ts");
|
|
31048
|
+
removeIfExists(resolve8(config.reactDirectory, "generated", "Island.tsx"));
|
|
31049
|
+
removeIfExists(resolve8(config.reactDirectory, "generated", "absolute-react.d.ts"));
|
|
31050
|
+
writeIfChanged2(compatTarget, `export * from "@absolutejs/absolute/react";
|
|
31051
|
+
`);
|
|
31444
31052
|
}
|
|
31445
|
-
|
|
31446
|
-
|
|
31447
|
-
|
|
31053
|
+
if (config.vueDirectory) {
|
|
31054
|
+
const compatTarget = resolve8(config.vueDirectory, "generated", "absolute-vue.ts");
|
|
31055
|
+
removeIfExists(resolve8(config.vueDirectory, "generated", "Island.ts"));
|
|
31056
|
+
removeIfExists(resolve8(config.vueDirectory, "generated", "absolute-vue.d.ts"));
|
|
31057
|
+
writeIfChanged2(compatTarget, `export * from "@absolutejs/absolute/vue";
|
|
31058
|
+
`);
|
|
31448
31059
|
}
|
|
31449
|
-
|
|
31450
|
-
|
|
31451
|
-
|
|
31060
|
+
if (config.svelteDirectory) {
|
|
31061
|
+
const compatTarget = resolve8(config.svelteDirectory, "generated", "absolute-svelte.ts");
|
|
31062
|
+
removeIfExists(resolve8(config.svelteDirectory, "generated", "islands.ts"));
|
|
31063
|
+
removeIfExists(resolve8(config.svelteDirectory, "generated", "absolute-svelte.d.ts"));
|
|
31064
|
+
writeIfChanged2(compatTarget, `export * from "@absolutejs/absolute/svelte";
|
|
31065
|
+
`);
|
|
31452
31066
|
}
|
|
31453
|
-
|
|
31454
|
-
|
|
31455
|
-
|
|
31456
|
-
|
|
31457
|
-
|
|
31458
|
-
|
|
31459
|
-
if (currentContent === content) {
|
|
31460
|
-
return;
|
|
31461
|
-
}
|
|
31067
|
+
if (config.angularDirectory) {
|
|
31068
|
+
const compatTarget = resolve8(config.angularDirectory, "generated", "absolute-angular.ts");
|
|
31069
|
+
removeIfExists(resolve8(config.angularDirectory, "generated", "islands.ts"));
|
|
31070
|
+
removeIfExists(resolve8(config.angularDirectory, "generated", "absolute-angular.d.ts"));
|
|
31071
|
+
writeIfChanged2(compatTarget, `export * from "@absolutejs/absolute/angular";
|
|
31072
|
+
`);
|
|
31462
31073
|
}
|
|
31463
|
-
|
|
31464
|
-
|
|
31465
|
-
|
|
31466
|
-
|
|
31467
|
-
|
|
31074
|
+
};
|
|
31075
|
+
var init_generateIslandBindings = () => {};
|
|
31076
|
+
|
|
31077
|
+
// src/utils/getDurationString.ts
|
|
31078
|
+
var getDurationString = (duration) => {
|
|
31079
|
+
let durationString;
|
|
31080
|
+
if (duration < MILLISECONDS_IN_A_SECOND) {
|
|
31081
|
+
durationString = `${duration.toFixed(TIME_PRECISION)}ms`;
|
|
31082
|
+
} else if (duration < MILLISECONDS_IN_A_MINUTE) {
|
|
31083
|
+
durationString = `${(duration / MILLISECONDS_IN_A_SECOND).toFixed(TIME_PRECISION)}s`;
|
|
31084
|
+
} else {
|
|
31085
|
+
durationString = `${(duration / MILLISECONDS_IN_A_MINUTE).toFixed(TIME_PRECISION)}m`;
|
|
31468
31086
|
}
|
|
31469
|
-
|
|
31470
|
-
|
|
31471
|
-
|
|
31472
|
-
|
|
31473
|
-
|
|
31474
|
-
|
|
31475
|
-
|
|
31476
|
-
|
|
31477
|
-
const
|
|
31478
|
-
const
|
|
31479
|
-
|
|
31480
|
-
|
|
31481
|
-
|
|
31482
|
-
|
|
31483
|
-
|
|
31484
|
-
|
|
31485
|
-
|
|
31087
|
+
return durationString;
|
|
31088
|
+
};
|
|
31089
|
+
var init_getDurationString = __esm(() => {
|
|
31090
|
+
init_constants();
|
|
31091
|
+
});
|
|
31092
|
+
|
|
31093
|
+
// src/utils/startupBanner.ts
|
|
31094
|
+
var colors, MONTHS, formatTimestamp = () => {
|
|
31095
|
+
const now = new Date;
|
|
31096
|
+
const month = MONTHS[now.getMonth()];
|
|
31097
|
+
const day = now.getDate().toString().padStart(2, "0");
|
|
31098
|
+
let hours = now.getHours();
|
|
31099
|
+
const minutes = now.getMinutes().toString().padStart(2, "0");
|
|
31100
|
+
const seconds = now.getSeconds().toString().padStart(2, "0");
|
|
31101
|
+
const ampm = hours >= HOURS_IN_HALF_DAY ? "PM" : "AM";
|
|
31102
|
+
hours = hours % HOURS_IN_HALF_DAY || HOURS_IN_HALF_DAY;
|
|
31103
|
+
return `${month} ${day} ${hours}:${minutes}:${seconds} ${ampm}`;
|
|
31104
|
+
}, startupBanner = (options) => {
|
|
31105
|
+
const {
|
|
31106
|
+
version,
|
|
31107
|
+
duration,
|
|
31108
|
+
port,
|
|
31109
|
+
host,
|
|
31110
|
+
networkUrl,
|
|
31111
|
+
protocol = "http"
|
|
31112
|
+
} = options;
|
|
31113
|
+
const name = `${colors.cyan}${colors.bold}ABSOLUTEJS${colors.reset}`;
|
|
31114
|
+
const ver = `${colors.dim}v${version}${colors.reset}`;
|
|
31115
|
+
const time = `${colors.dim}ready in${colors.reset} ${colors.bold}${getDurationString(duration)}${colors.reset}`;
|
|
31116
|
+
console.log("");
|
|
31117
|
+
console.log(` ${name} ${ver} ${time}`);
|
|
31118
|
+
console.log("");
|
|
31119
|
+
console.log(` ${colors.green}\u279C${colors.reset} ${colors.bold}Local:${colors.reset} ${protocol}://${host === "0.0.0.0" ? "localhost" : host}:${port}/`);
|
|
31120
|
+
if (networkUrl) {
|
|
31121
|
+
console.log(` ${colors.green}\u279C${colors.reset} ${colors.bold}Network:${colors.reset} ${networkUrl}`);
|
|
31486
31122
|
}
|
|
31487
|
-
|
|
31488
|
-
|
|
31489
|
-
|
|
31490
|
-
|
|
31491
|
-
|
|
31492
|
-
|
|
31493
|
-
|
|
31494
|
-
|
|
31123
|
+
console.log("");
|
|
31124
|
+
};
|
|
31125
|
+
var init_startupBanner = __esm(() => {
|
|
31126
|
+
init_constants();
|
|
31127
|
+
init_getDurationString();
|
|
31128
|
+
colors = {
|
|
31129
|
+
bold: "\x1B[1m",
|
|
31130
|
+
cyan: "\x1B[36m",
|
|
31131
|
+
dim: "\x1B[2m",
|
|
31132
|
+
green: "\x1B[32m",
|
|
31133
|
+
reset: "\x1B[0m"
|
|
31134
|
+
};
|
|
31135
|
+
MONTHS = [
|
|
31136
|
+
"Jan",
|
|
31137
|
+
"Feb",
|
|
31138
|
+
"Mar",
|
|
31139
|
+
"Apr",
|
|
31140
|
+
"May",
|
|
31141
|
+
"Jun",
|
|
31142
|
+
"Jul",
|
|
31143
|
+
"Aug",
|
|
31144
|
+
"Sep",
|
|
31145
|
+
"Oct",
|
|
31146
|
+
"Nov",
|
|
31147
|
+
"Dec"
|
|
31148
|
+
];
|
|
31149
|
+
});
|
|
31150
|
+
|
|
31151
|
+
// src/utils/logger.ts
|
|
31152
|
+
var colors2, frameworkColors, formatPath = (filePath) => {
|
|
31153
|
+
const cwd = process.cwd();
|
|
31154
|
+
let relative3 = filePath.startsWith(cwd) ? filePath.slice(cwd.length + 1) : filePath;
|
|
31155
|
+
relative3 = relative3.replace(/\\/g, "/");
|
|
31156
|
+
if (!relative3.startsWith("/")) {
|
|
31157
|
+
relative3 = `/${relative3}`;
|
|
31495
31158
|
}
|
|
31496
|
-
|
|
31497
|
-
|
|
31498
|
-
|
|
31499
|
-
|
|
31500
|
-
|
|
31501
|
-
|
|
31502
|
-
|
|
31503
|
-
|
|
31504
|
-
for (const [spec, compiledChildPath] of childModulePaths) {
|
|
31505
|
-
compiledCode = compiledCode.replaceAll(spec, ensureRelativeImportPath(getCachedModulePath(sourcePath), compiledChildPath));
|
|
31159
|
+
return relative3;
|
|
31160
|
+
}, getFrameworkColor = (framework) => frameworkColors[framework] || colors2.white, log = (action, options) => {
|
|
31161
|
+
const timestamp = `${colors2.dim}${formatTimestamp()}${colors2.reset}`;
|
|
31162
|
+
const tag = `${colors2.cyan}[hmr]${colors2.reset}`;
|
|
31163
|
+
let message = action;
|
|
31164
|
+
if (options?.path) {
|
|
31165
|
+
const pathColor = options.framework ? getFrameworkColor(options.framework) : colors2.white;
|
|
31166
|
+
message += ` ${pathColor}${formatPath(options.path)}${colors2.reset}`;
|
|
31506
31167
|
}
|
|
31507
|
-
|
|
31508
|
-
|
|
31168
|
+
if (options?.duration !== undefined) {
|
|
31169
|
+
message += ` ${colors2.dim}(${options.duration}ms)${colors2.reset}`;
|
|
31509
31170
|
}
|
|
31510
|
-
|
|
31511
|
-
|
|
31512
|
-
|
|
31513
|
-
|
|
31514
|
-
|
|
31171
|
+
console.log(`${timestamp} ${tag} ${message}`);
|
|
31172
|
+
}, logCssUpdate = (path, framework, duration) => {
|
|
31173
|
+
log("css update", { duration, framework: framework ?? "css", path });
|
|
31174
|
+
}, logError = (message, error) => {
|
|
31175
|
+
const timestamp = `${colors2.dim}${formatTimestamp()}${colors2.reset}`;
|
|
31176
|
+
const tag = `${colors2.red}[hmr]${colors2.reset}`;
|
|
31177
|
+
const errorMsg = error instanceof Error ? error.message : error;
|
|
31178
|
+
const fullMessage = `${colors2.red}error${colors2.reset} ${message}${errorMsg ? `: ${errorMsg}` : ""}`;
|
|
31179
|
+
console.error(`${timestamp} ${tag} ${fullMessage}`);
|
|
31180
|
+
}, logHmrUpdate = (path, framework, duration) => {
|
|
31181
|
+
log("hmr update", { duration, framework, path });
|
|
31182
|
+
}, logScriptUpdate = (path, framework, duration) => {
|
|
31183
|
+
log("script update", { duration, framework, path });
|
|
31184
|
+
}, logServerReload = () => {
|
|
31185
|
+
log(`${colors2.cyan}server module reloaded${colors2.reset}`);
|
|
31186
|
+
}, logWarn = (message) => {
|
|
31187
|
+
const timestamp = `${colors2.dim}${formatTimestamp()}${colors2.reset}`;
|
|
31188
|
+
const tag = `${colors2.yellow}[hmr]${colors2.reset}`;
|
|
31189
|
+
console.warn(`${timestamp} ${tag} ${colors2.yellow}warning${colors2.reset} ${message}`);
|
|
31515
31190
|
};
|
|
31516
|
-
var
|
|
31517
|
-
|
|
31518
|
-
|
|
31519
|
-
|
|
31520
|
-
|
|
31521
|
-
|
|
31522
|
-
|
|
31523
|
-
|
|
31191
|
+
var init_logger = __esm(() => {
|
|
31192
|
+
init_startupBanner();
|
|
31193
|
+
colors2 = {
|
|
31194
|
+
blue: "\x1B[34m",
|
|
31195
|
+
bold: "\x1B[1m",
|
|
31196
|
+
cyan: "\x1B[36m",
|
|
31197
|
+
dim: "\x1B[2m",
|
|
31198
|
+
green: "\x1B[32m",
|
|
31199
|
+
magenta: "\x1B[35m",
|
|
31200
|
+
red: "\x1B[31m",
|
|
31201
|
+
reset: "\x1B[0m",
|
|
31202
|
+
white: "\x1B[37m",
|
|
31203
|
+
yellow: "\x1B[33m"
|
|
31204
|
+
};
|
|
31205
|
+
frameworkColors = {
|
|
31206
|
+
angular: colors2.magenta,
|
|
31207
|
+
assets: colors2.dim,
|
|
31208
|
+
css: colors2.cyan,
|
|
31209
|
+
html: colors2.white,
|
|
31210
|
+
htmx: colors2.white,
|
|
31211
|
+
react: colors2.blue,
|
|
31212
|
+
svelte: colors2.yellow,
|
|
31213
|
+
vue: colors2.green
|
|
31214
|
+
};
|
|
31524
31215
|
});
|
|
31525
31216
|
|
|
31526
|
-
// src/
|
|
31527
|
-
var
|
|
31528
|
-
"data-component": props.component,
|
|
31529
|
-
"data-framework": props.framework,
|
|
31530
|
-
"data-hydrate": props.hydrate ?? "load",
|
|
31531
|
-
"data-island": "true",
|
|
31532
|
-
...islandId ? { "data-island-id": islandId } : {},
|
|
31533
|
-
"data-props": serializeIslandProps(props.props)
|
|
31534
|
-
}), escapeHtmlAttribute = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<").replaceAll(">", ">"), serializeIslandAttributes = (attributes) => Object.entries(attributes).map(([key, value]) => `${key}="${escapeHtmlAttribute(value)}"`).join(" ");
|
|
31535
|
-
var init_islandMarkupAttributes = __esm(() => {
|
|
31536
|
-
init_islands();
|
|
31537
|
-
});
|
|
31217
|
+
// src/utils/normalizePath.ts
|
|
31218
|
+
var normalizePath = (path) => path.replace(/\\/g, "/");
|
|
31538
31219
|
|
|
31539
|
-
// src/
|
|
31540
|
-
var
|
|
31541
|
-
|
|
31542
|
-
|
|
31543
|
-
}
|
|
31544
|
-
|
|
31545
|
-
|
|
31546
|
-
|
|
31547
|
-
|
|
31548
|
-
|
|
31549
|
-
|
|
31550
|
-
|
|
31551
|
-
return
|
|
31552
|
-
|
|
31553
|
-
|
|
31554
|
-
|
|
31555
|
-
|
|
31556
|
-
|
|
31557
|
-
|
|
31558
|
-
const
|
|
31559
|
-
|
|
31560
|
-
|
|
31561
|
-
const
|
|
31562
|
-
|
|
31563
|
-
|
|
31220
|
+
// src/build/generateManifest.ts
|
|
31221
|
+
var exports_generateManifest = {};
|
|
31222
|
+
__export(exports_generateManifest, {
|
|
31223
|
+
generateManifest: () => generateManifest
|
|
31224
|
+
});
|
|
31225
|
+
import { extname as extname3 } from "path";
|
|
31226
|
+
var getManifestKey = (folder, pascalName, isClientComponent, isReact, isVue, isSvelte, isAngular) => {
|
|
31227
|
+
if (folder === "indexes")
|
|
31228
|
+
return `${pascalName}Index`;
|
|
31229
|
+
if (isClientComponent)
|
|
31230
|
+
return `${pascalName}Client`;
|
|
31231
|
+
if (folder !== "pages")
|
|
31232
|
+
return pascalName;
|
|
31233
|
+
if (isReact)
|
|
31234
|
+
return `${pascalName}Page`;
|
|
31235
|
+
if (isVue || isSvelte || isAngular)
|
|
31236
|
+
return pascalName;
|
|
31237
|
+
return `${pascalName}Page`;
|
|
31238
|
+
}, getCssKey = (pascalName, segments) => {
|
|
31239
|
+
const isFromVue = segments.some((seg) => seg === "vue");
|
|
31240
|
+
if (isFromVue && segments.includes("css"))
|
|
31241
|
+
return `${pascalName}CompiledCSS`;
|
|
31242
|
+
const isFromReact = segments.some((seg) => seg === "react");
|
|
31243
|
+
const isFromSvelte = segments.some((seg) => seg === "svelte");
|
|
31244
|
+
const isFromAngular = segments.some((seg) => seg === "angular");
|
|
31245
|
+
if (isFromReact || isFromVue || isFromSvelte || isFromAngular)
|
|
31246
|
+
return `${pascalName}BundledCSS`;
|
|
31247
|
+
return `${pascalName}CSS`;
|
|
31248
|
+
}, generateManifest = (outputs, buildPath) => outputs.reduce((manifest, artifact) => {
|
|
31249
|
+
const normalizedArtifactPath = normalizePath(artifact.path);
|
|
31250
|
+
const normalizedBuildPath = normalizePath(buildPath);
|
|
31251
|
+
let relative3 = normalizedArtifactPath.startsWith(normalizedBuildPath) ? normalizedArtifactPath.slice(normalizedBuildPath.length) : normalizedArtifactPath;
|
|
31252
|
+
relative3 = relative3.replace(/^\/+/, "");
|
|
31253
|
+
const segments = relative3.split("/");
|
|
31254
|
+
const fileWithHash = segments.pop();
|
|
31255
|
+
if (!fileWithHash)
|
|
31256
|
+
return manifest;
|
|
31257
|
+
const [baseName] = fileWithHash.split(`.${artifact.hash}.`);
|
|
31258
|
+
if (!baseName)
|
|
31259
|
+
return manifest;
|
|
31260
|
+
const pascalName = toPascal(baseName);
|
|
31261
|
+
const ext = extname3(fileWithHash);
|
|
31262
|
+
const islandIndex = segments.findIndex((seg) => seg === "islands");
|
|
31263
|
+
if (ext === ".css") {
|
|
31264
|
+
const cssKey = getCssKey(pascalName, segments);
|
|
31265
|
+
if (manifest[cssKey] && manifest[cssKey] !== `/${relative3}`)
|
|
31266
|
+
logWarn(`Duplicate manifest key "${cssKey}" \u2014 "${manifest[cssKey]}" will be overwritten by "/${relative3}". Use unique page names across frameworks.`);
|
|
31267
|
+
manifest[cssKey] = `/${relative3}`;
|
|
31268
|
+
return manifest;
|
|
31564
31269
|
}
|
|
31565
|
-
|
|
31566
|
-
const
|
|
31567
|
-
|
|
31568
|
-
|
|
31569
|
-
|
|
31570
|
-
|
|
31571
|
-
const resolvedComponent = getIslandComponent(component);
|
|
31572
|
-
if (typeof resolvedComponent !== "string") {
|
|
31573
|
-
return resolvedComponent;
|
|
31270
|
+
if (islandIndex > UNFOUND_INDEX) {
|
|
31271
|
+
const frameworkSegment = segments[islandIndex + 1];
|
|
31272
|
+
if (frameworkSegment === "react" || frameworkSegment === "svelte" || frameworkSegment === "vue" || frameworkSegment === "angular") {
|
|
31273
|
+
const manifestKey2 = getIslandManifestKey(frameworkSegment, pascalName);
|
|
31274
|
+
manifest[manifestKey2] = `/${relative3}`;
|
|
31275
|
+
return manifest;
|
|
31574
31276
|
}
|
|
31575
|
-
return loadServerImportComponent(resolvedComponent);
|
|
31576
|
-
})();
|
|
31577
|
-
resolvedServerComponentCache.set(component, resolutionPromise);
|
|
31578
|
-
return resolutionPromise;
|
|
31579
|
-
}, resolveReactServerIslandComponent = async (component) => {
|
|
31580
|
-
const resolvedComponent = await resolveServerIslandComponent(component);
|
|
31581
|
-
if (!isReactServerIslandComponent(resolvedComponent)) {
|
|
31582
|
-
throw new Error("Resolved React island is not a valid React component.");
|
|
31583
31277
|
}
|
|
31584
|
-
|
|
31585
|
-
|
|
31586
|
-
const
|
|
31587
|
-
|
|
31588
|
-
|
|
31278
|
+
const idx = segments.findIndex((seg) => seg === "indexes" || seg === "pages" || seg === "client");
|
|
31279
|
+
const folder = idx > UNFOUND_INDEX ? segments[idx] : segments[0];
|
|
31280
|
+
const isReact = segments.some((seg) => seg === "react");
|
|
31281
|
+
const isVue = segments.some((seg) => seg === "vue");
|
|
31282
|
+
const isSvelte = segments.some((seg) => seg === "svelte");
|
|
31283
|
+
const isAngular = segments.some((seg) => seg === "angular");
|
|
31284
|
+
const isClientComponent = segments.includes("client");
|
|
31285
|
+
const manifestKey = getManifestKey(folder, pascalName, isClientComponent, isReact, isVue, isSvelte, isAngular);
|
|
31286
|
+
if (manifest[manifestKey] && manifest[manifestKey] !== `/${relative3}`) {
|
|
31287
|
+
logWarn(`Duplicate manifest key "${manifestKey}" \u2014 "${manifest[manifestKey]}" will be overwritten by "/${relative3}". Use unique page names across frameworks.`);
|
|
31589
31288
|
}
|
|
31590
|
-
|
|
31591
|
-
|
|
31592
|
-
|
|
31593
|
-
|
|
31594
|
-
|
|
31289
|
+
manifest[manifestKey] = `/${relative3}`;
|
|
31290
|
+
return manifest;
|
|
31291
|
+
}, {});
|
|
31292
|
+
var init_generateManifest = __esm(() => {
|
|
31293
|
+
init_constants();
|
|
31294
|
+
init_logger();
|
|
31295
|
+
});
|
|
31296
|
+
|
|
31297
|
+
// src/build/generateReactIndexes.ts
|
|
31298
|
+
var exports_generateReactIndexes = {};
|
|
31299
|
+
__export(exports_generateReactIndexes, {
|
|
31300
|
+
generateReactIndexFiles: () => generateReactIndexFiles
|
|
31301
|
+
});
|
|
31302
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
31303
|
+
import { readdir, rm, writeFile } from "fs/promises";
|
|
31304
|
+
import { basename as basename2, join as join4, relative as relative3, resolve as resolve9, sep } from "path";
|
|
31305
|
+
var {Glob: Glob2 } = globalThis.Bun;
|
|
31306
|
+
var indexContentCache, resolveDevClientDir = () => {
|
|
31307
|
+
const projectRoot = process.cwd();
|
|
31308
|
+
const fromSource = resolve9(import.meta.dir, "../dev/client");
|
|
31309
|
+
if (existsSync5(fromSource) && fromSource.startsWith(projectRoot)) {
|
|
31310
|
+
return fromSource;
|
|
31595
31311
|
}
|
|
31596
|
-
|
|
31597
|
-
|
|
31598
|
-
|
|
31599
|
-
|
|
31600
|
-
|
|
31312
|
+
const fromNodeModules = resolve9(projectRoot, "node_modules/@absolutejs/absolute/dist/dev/client");
|
|
31313
|
+
if (existsSync5(fromNodeModules))
|
|
31314
|
+
return fromNodeModules;
|
|
31315
|
+
return resolve9(import.meta.dir, "./dev/client");
|
|
31316
|
+
}, devClientDir, errorOverlayPath, hmrClientPath, refreshSetupPath, generateReactIndexFiles = async (reactPagesDirectory, reactIndexesDirectory, isDev2 = false) => {
|
|
31317
|
+
if (!existsSync5(reactIndexesDirectory)) {
|
|
31318
|
+
mkdirSync3(reactIndexesDirectory, { recursive: true });
|
|
31601
31319
|
}
|
|
31602
|
-
|
|
31603
|
-
|
|
31604
|
-
const
|
|
31605
|
-
const
|
|
31606
|
-
|
|
31607
|
-
|
|
31608
|
-
|
|
31609
|
-
throw new Error(`Island component "${props.component}" is not registered for framework "react".`);
|
|
31610
|
-
}
|
|
31611
|
-
const component = await resolveReactServerIslandComponent(entry);
|
|
31612
|
-
const html = renderReactIslandToHtml(component, props.props);
|
|
31613
|
-
return { attributes, html };
|
|
31320
|
+
const CONVENTION_RE = /^(?:(.+)\.)?(error|loading|not-found)\.[^.]+$/;
|
|
31321
|
+
const pagesGlob = new Glob2("*.*");
|
|
31322
|
+
const files = [];
|
|
31323
|
+
for await (const file2 of pagesGlob.scan({ cwd: reactPagesDirectory })) {
|
|
31324
|
+
if (CONVENTION_RE.test(file2))
|
|
31325
|
+
continue;
|
|
31326
|
+
files.push(file2);
|
|
31614
31327
|
}
|
|
31615
|
-
|
|
31616
|
-
|
|
31617
|
-
|
|
31618
|
-
|
|
31619
|
-
|
|
31620
|
-
|
|
31621
|
-
|
|
31622
|
-
|
|
31328
|
+
const currentPageNames = new Set(files.map((file2) => basename2(file2).split(".")[0]));
|
|
31329
|
+
const emptyStringArray = [];
|
|
31330
|
+
const existingIndexes = await readdir(reactIndexesDirectory).catch(() => emptyStringArray);
|
|
31331
|
+
const staleIndexes = existingIndexes.filter((indexFile) => {
|
|
31332
|
+
const indexName = indexFile.replace(/\.tsx$/, "");
|
|
31333
|
+
return indexName !== "_refresh" && !currentPageNames.has(indexName);
|
|
31334
|
+
});
|
|
31335
|
+
if (staleIndexes.length > 0) {
|
|
31336
|
+
await Promise.all(staleIndexes.map((indexFile) => {
|
|
31337
|
+
indexContentCache.delete(join4(reactIndexesDirectory, indexFile));
|
|
31338
|
+
return rm(join4(reactIndexesDirectory, indexFile), {
|
|
31339
|
+
force: true
|
|
31340
|
+
});
|
|
31341
|
+
}));
|
|
31623
31342
|
}
|
|
31624
|
-
|
|
31625
|
-
|
|
31626
|
-
|
|
31627
|
-
|
|
31343
|
+
const pagesRelPath = relative3(resolve9(reactIndexesDirectory), resolve9(reactPagesDirectory)).split(sep).join("/");
|
|
31344
|
+
const promises = files.map(async (file2) => {
|
|
31345
|
+
const fileName = basename2(file2);
|
|
31346
|
+
const [componentName] = fileName.split(".");
|
|
31347
|
+
const hmrPreamble = isDev2 ? [
|
|
31348
|
+
`window.__HMR_FRAMEWORK__ = "react";`,
|
|
31349
|
+
`window.__REACT_COMPONENT_KEY__ = "${componentName}Index";`,
|
|
31350
|
+
`import '${refreshSetupPath}';`,
|
|
31351
|
+
`import '${hmrClientPath}';`,
|
|
31352
|
+
`import { showErrorOverlay, hideErrorOverlay } from '${errorOverlayPath}';
|
|
31353
|
+
`
|
|
31354
|
+
] : [];
|
|
31355
|
+
const reactImports = isDev2 ? [
|
|
31356
|
+
`import { hydrateRoot, createRoot } from 'react-dom/client';`,
|
|
31357
|
+
`import { createElement, Component } from 'react';`
|
|
31358
|
+
] : [
|
|
31359
|
+
`import { hydrateRoot, createRoot } from 'react-dom/client';`,
|
|
31360
|
+
`import { createElement } from 'react';`
|
|
31361
|
+
];
|
|
31362
|
+
const errorBoundaryDef = isDev2 ? [
|
|
31363
|
+
`
|
|
31364
|
+
// Dev-only Error Boundary to catch React render errors`,
|
|
31365
|
+
`class ErrorBoundary extends Component {`,
|
|
31366
|
+
` constructor(props) {`,
|
|
31367
|
+
` super(props);`,
|
|
31368
|
+
` this.state = { hasError: false };`,
|
|
31369
|
+
` window.__ERROR_BOUNDARY__ = this;`,
|
|
31370
|
+
` }`,
|
|
31371
|
+
` static getDerivedStateFromError() {`,
|
|
31372
|
+
` return { hasError: true };`,
|
|
31373
|
+
` }`,
|
|
31374
|
+
` componentDidCatch(error) {`,
|
|
31375
|
+
` showErrorOverlay({`,
|
|
31376
|
+
` framework: 'react',`,
|
|
31377
|
+
` kind: 'runtime',`,
|
|
31378
|
+
` message: error && error.stack ? error.stack : String(error)`,
|
|
31379
|
+
` });`,
|
|
31380
|
+
` }`,
|
|
31381
|
+
` componentDidUpdate(prevProps, prevState) {`,
|
|
31382
|
+
` if (prevState.hasError && !this.state.hasError) {`,
|
|
31383
|
+
` hideErrorOverlay();`,
|
|
31384
|
+
` }`,
|
|
31385
|
+
` }`,
|
|
31386
|
+
` reset() {`,
|
|
31387
|
+
` this.setState({ hasError: false });`,
|
|
31388
|
+
` }`,
|
|
31389
|
+
` render() {`,
|
|
31390
|
+
` if (this.state.hasError) return null;`,
|
|
31391
|
+
``,
|
|
31392
|
+
` return this.props.children;`,
|
|
31393
|
+
` }`,
|
|
31394
|
+
`}
|
|
31395
|
+
`
|
|
31396
|
+
] : [];
|
|
31397
|
+
const content = [
|
|
31398
|
+
...hmrPreamble,
|
|
31399
|
+
...reactImports,
|
|
31400
|
+
`import type { ComponentType } from 'react'`,
|
|
31401
|
+
`import { ${componentName} } from '${pagesRelPath}/${componentName}';
|
|
31402
|
+
`,
|
|
31403
|
+
`type PropsOf<C> = C extends ComponentType<infer P> ? P : never;
|
|
31404
|
+
`,
|
|
31405
|
+
`declare global {`,
|
|
31406
|
+
` interface Window {`,
|
|
31407
|
+
` __INITIAL_PROPS__?: PropsOf<typeof ${componentName}>`,
|
|
31408
|
+
` __REACT_ROOT__?: ReturnType<typeof hydrateRoot | typeof createRoot>`,
|
|
31409
|
+
` __HMR_CLIENT_ONLY_MODE__?: boolean`,
|
|
31410
|
+
` }`,
|
|
31411
|
+
`}
|
|
31412
|
+
`,
|
|
31413
|
+
...errorBoundaryDef,
|
|
31414
|
+
`// Hydration with error handling and fallback`,
|
|
31415
|
+
`const isDev = ${isDev2};`,
|
|
31416
|
+
`const componentPath = '${pagesRelPath}/${componentName}';
|
|
31417
|
+
`,
|
|
31418
|
+
`function isHydrationError(error) {`,
|
|
31419
|
+
` if (!error) return false;`,
|
|
31420
|
+
` const errorMessage = error instanceof Error ? error.message : String(error);`,
|
|
31421
|
+
` const errorString = String(error);`,
|
|
31422
|
+
` const fullMessage = errorMessage + ' ' + errorString;`,
|
|
31423
|
+
` const hydrationKeywords = ['hydration', 'Hydration', 'mismatch', 'Mismatch', 'did not match', 'server rendered HTML', 'server HTML', 'client HTML', 'Hydration failed'];`,
|
|
31424
|
+
` const isHydration = hydrationKeywords.some(keyword => fullMessage.includes(keyword));`,
|
|
31425
|
+
` `,
|
|
31426
|
+
` // Ignore whitespace-only mismatches in <head> - these are harmless formatting differences`,
|
|
31427
|
+
` // The error often shows: + <link...> vs - {"\\n "} which is just formatting`,
|
|
31428
|
+
` if (isHydration) {`,
|
|
31429
|
+
` // Check if this is a head/link/stylesheet related mismatch`,
|
|
31430
|
+
` const isHeadRelated = fullMessage.includes('<head') || fullMessage.includes('</head>') || fullMessage.includes('head>') || fullMessage.includes('<link') || fullMessage.includes('link>') || fullMessage.includes('stylesheet') || fullMessage.includes('fonts.googleapis') || fullMessage.includes('rel="stylesheet"');`,
|
|
31431
|
+
` `,
|
|
31432
|
+
` // Check if the mismatch involves only whitespace/newlines`,
|
|
31433
|
+
` // Pattern: looks for {"\\n"} or {"\\n "} or similar whitespace-only content`,
|
|
31434
|
+
` // Also check for patterns like: - {"\\n "} or + <link...>`,
|
|
31435
|
+
` const hasWhitespacePattern = /\\{\\s*["']\\\\n[^"']*["']\\s*\\}/.test(fullMessage) || /\\{\\s*["'][\\\\n\\\\r\\\\s]+["']\\s*\\}/.test(fullMessage) || /-\\s*\\{\\s*["'][\\\\n\\\\r\\\\s]+["']\\s*\\}/.test(fullMessage);`,
|
|
31436
|
+
` const isWhitespaceOnly = /^[\\s\\n\\r]*$/.test(errorString) || /^[\\s\\n\\r]*$/.test(errorMessage);`,
|
|
31437
|
+
` const hasNewlinePattern = fullMessage.includes('\\\\n') || fullMessage.includes('\\\\r') || fullMessage.includes('\\n') || fullMessage.includes('\\r');`,
|
|
31438
|
+
` `,
|
|
31439
|
+
` // If it's head-related and involves whitespace/newlines, ignore it`,
|
|
31440
|
+
` if (isHeadRelated && (hasWhitespacePattern || isWhitespaceOnly || hasNewlinePattern)) {`,
|
|
31441
|
+
` return false; // Don't treat whitespace-only head mismatches as errors`,
|
|
31442
|
+
` }`,
|
|
31443
|
+
` }`,
|
|
31444
|
+
` return isHydration;`,
|
|
31445
|
+
`}
|
|
31446
|
+
`,
|
|
31447
|
+
`function logHydrationError(error, componentName) {`,
|
|
31448
|
+
` if (!isDev) return;`,
|
|
31449
|
+
` if (window.__HMR_WS__ && window.__HMR_WS__.readyState === WebSocket.OPEN) {`,
|
|
31450
|
+
` try {`,
|
|
31451
|
+
` window.__HMR_WS__.send(JSON.stringify({`,
|
|
31452
|
+
` type: 'hydration-error',`,
|
|
31453
|
+
` data: {`,
|
|
31454
|
+
` componentName: '${componentName}',`,
|
|
31455
|
+
` componentPath: componentPath,`,
|
|
31456
|
+
` error: error instanceof Error ? error.message : String(error),`,
|
|
31457
|
+
` timestamp: Date.now()`,
|
|
31458
|
+
` }`,
|
|
31459
|
+
` }));`,
|
|
31460
|
+
` } catch (err) {}`,
|
|
31461
|
+
` }`,
|
|
31462
|
+
`}
|
|
31463
|
+
`,
|
|
31464
|
+
`// Track if we've already switched to client-only mode`,
|
|
31465
|
+
`let hasSwitchedToClientOnly = false;`,
|
|
31466
|
+
`let hydrationErrorDetected = false;
|
|
31467
|
+
`,
|
|
31468
|
+
`function handleHydrationFallback(error) {`,
|
|
31469
|
+
` if (hasSwitchedToClientOnly) return; // Already handled`,
|
|
31470
|
+
` hasSwitchedToClientOnly = true;`,
|
|
31471
|
+
` hydrationErrorDetected = true;
|
|
31472
|
+
`,
|
|
31473
|
+
` logHydrationError(error, '${componentName}');
|
|
31474
|
+
`,
|
|
31475
|
+
` // Fallback: client-only render (no hydration)`,
|
|
31476
|
+
` try {`,
|
|
31477
|
+
` // Unmount existing root if it exists`,
|
|
31478
|
+
` if (window.__REACT_ROOT__ && typeof window.__REACT_ROOT__.unmount === 'function') {`,
|
|
31479
|
+
` try {`,
|
|
31480
|
+
` window.__REACT_ROOT__.unmount();`,
|
|
31481
|
+
` } catch (e) {`,
|
|
31482
|
+
` // Ignore unmount errors`,
|
|
31483
|
+
` }`,
|
|
31484
|
+
` }
|
|
31485
|
+
`,
|
|
31486
|
+
` // Render into the same root container when falling back to client-only`,
|
|
31487
|
+
` const root = createRoot(container);`,
|
|
31488
|
+
` root.render(${isDev2 ? `createElement(ErrorBoundary, null, createElement(${componentName}, mergedProps))` : `createElement(${componentName}, mergedProps)`});`,
|
|
31489
|
+
` window.__REACT_ROOT__ = root;`,
|
|
31490
|
+
` window.__HMR_CLIENT_ONLY_MODE__ = true;`,
|
|
31491
|
+
` } catch (fallbackError) {`,
|
|
31492
|
+
` window.location.reload();`,
|
|
31493
|
+
` }`,
|
|
31494
|
+
`}
|
|
31495
|
+
`,
|
|
31496
|
+
`// HMR State Preservation: Check for preserved state and merge with initial props`,
|
|
31497
|
+
`// This allows state to be preserved across HMR updates without modifying component files`,
|
|
31498
|
+
`let preservedState = (typeof window !== 'undefined' && window.__HMR_PRESERVED_STATE__) ? window.__HMR_PRESERVED_STATE__ : {};
|
|
31499
|
+
`,
|
|
31500
|
+
`// Also check sessionStorage for state that survived a page reload (for React HMR)`,
|
|
31501
|
+
`if (typeof window !== 'undefined' && typeof sessionStorage !== 'undefined') {`,
|
|
31502
|
+
` const hmrStateJson = sessionStorage.getItem('__REACT_HMR_STATE__');`,
|
|
31503
|
+
` if (hmrStateJson) {`,
|
|
31504
|
+
` try {`,
|
|
31505
|
+
` const hmrState = JSON.parse(hmrStateJson);`,
|
|
31506
|
+
` preservedState = { ...preservedState, ...hmrState };`,
|
|
31507
|
+
` sessionStorage.removeItem('__REACT_HMR_STATE__');`,
|
|
31508
|
+
` } catch (e) {}`,
|
|
31509
|
+
` }`,
|
|
31510
|
+
`}
|
|
31511
|
+
`,
|
|
31512
|
+
`const mergedProps = { ...(window.__INITIAL_PROPS__ || {}), ...preservedState };`,
|
|
31513
|
+
`// Clear preserved state after using it (so it doesn't persist across multiple updates)`,
|
|
31514
|
+
`if (typeof window !== 'undefined') {`,
|
|
31515
|
+
` window.__HMR_PRESERVED_STATE__ = undefined;`,
|
|
31516
|
+
`}
|
|
31517
|
+
`,
|
|
31518
|
+
`// Attempt hydration with error handling`,
|
|
31519
|
+
`// Use document (not document.body) when the page renders <html><head><body>`,
|
|
31520
|
+
`// to avoid "In HTML, <html> cannot be a child of <body>" hydration error`,
|
|
31521
|
+
`const container = typeof document !== 'undefined' ? document : null;`,
|
|
31522
|
+
`if (!container) {`,
|
|
31523
|
+
` throw new Error('React root container not found: document is null');`,
|
|
31524
|
+
`}
|
|
31525
|
+
`,
|
|
31526
|
+
`// Guard: only hydrate on first load. During HMR re-imports, skip hydration`,
|
|
31527
|
+
`// so React Fast Refresh can swap components in-place and preserve state.`,
|
|
31528
|
+
`if (!window.__REACT_ROOT__) {`,
|
|
31529
|
+
` let root;`,
|
|
31530
|
+
` // After HMR, SSR is skipped to avoid stale content flash \u2014 render client-only`,
|
|
31531
|
+
` if (window.__SSR_DIRTY__) {`,
|
|
31532
|
+
` root = createRoot(container);`,
|
|
31533
|
+
` root.render(${isDev2 ? `createElement(ErrorBoundary, null, createElement(${componentName}, mergedProps))` : `createElement(${componentName}, mergedProps)`});`,
|
|
31534
|
+
` window.__REACT_ROOT__ = root;`,
|
|
31535
|
+
` } else {`,
|
|
31536
|
+
` try {`,
|
|
31537
|
+
` // Use onRecoverableError to catch hydration errors (React 19)`,
|
|
31538
|
+
` root = hydrateRoot(`,
|
|
31539
|
+
` container,`,
|
|
31540
|
+
` ${isDev2 ? `createElement(ErrorBoundary, null, createElement(${componentName}, mergedProps))` : `createElement(${componentName}, mergedProps)`},`,
|
|
31541
|
+
` {`,
|
|
31542
|
+
` onRecoverableError: (error) => {`,
|
|
31543
|
+
` // Check if this is a hydration error (isHydrationError filters out whitespace-only head mismatches)`,
|
|
31544
|
+
` if (isDev && isHydrationError(error)) {`,
|
|
31545
|
+
` // Real hydration error - handle it`,
|
|
31546
|
+
` handleHydrationFallback(error);`,
|
|
31547
|
+
` } else {`,
|
|
31548
|
+
` // Not a hydration error, or it's a whitespace-only mismatch that was filtered out`,
|
|
31549
|
+
` // Check if it's a whitespace-only head mismatch using the same logic as isHydrationError`,
|
|
31550
|
+
` const errorMessage = error instanceof Error ? error.message : String(error);`,
|
|
31551
|
+
` const errorString = String(error);`,
|
|
31552
|
+
` const fullMessage = errorMessage + ' ' + errorString;`,
|
|
31553
|
+
` const hydrationKeywords = ['hydration', 'Hydration', 'mismatch', 'Mismatch', 'did not match', 'server rendered HTML', 'server HTML', 'client HTML', 'Hydration failed'];`,
|
|
31554
|
+
` const isHydration = hydrationKeywords.some(keyword => fullMessage.includes(keyword));`,
|
|
31555
|
+
` if (isHydration) {`,
|
|
31556
|
+
` // Check if this is a head/link/stylesheet related mismatch`,
|
|
31557
|
+
` const isHeadRelated = fullMessage.includes('<head') || fullMessage.includes('</head>') || fullMessage.includes('head>') || fullMessage.includes('<link') || fullMessage.includes('link>') || fullMessage.includes('stylesheet') || fullMessage.includes('fonts.googleapis') || fullMessage.includes('rel="stylesheet"');`,
|
|
31558
|
+
` // Check if the mismatch involves only whitespace/newlines`,
|
|
31559
|
+
` const hasWhitespacePattern = /\\{\\s*["']\\\\n[^"']*["']\\s*\\}/.test(fullMessage) || /\\{\\s*["'][\\\\n\\\\r\\\\s]+["']\\s*\\}/.test(fullMessage) || /-\\s*\\{\\s*["'][\\\\n\\\\r\\\\s]+["']\\s*\\}/.test(fullMessage);`,
|
|
31560
|
+
` const isWhitespaceOnly = /^[\\s\\n\\r]*$/.test(errorString) || /^[\\s\\n\\r]*$/.test(errorMessage);`,
|
|
31561
|
+
` const hasNewlinePattern = fullMessage.includes('\\\\n') || fullMessage.includes('\\\\r') || fullMessage.includes('\\n') || fullMessage.includes('\\r');`,
|
|
31562
|
+
` // If it's head-related and involves whitespace/newlines, silently ignore it`,
|
|
31563
|
+
` if (isHeadRelated && (hasWhitespacePattern || isWhitespaceOnly || hasNewlinePattern)) {`,
|
|
31564
|
+
` // Already logged by isHydrationError, just return silently`,
|
|
31565
|
+
` return;`,
|
|
31566
|
+
` }`,
|
|
31567
|
+
` }`,
|
|
31568
|
+
` // Log other recoverable errors`,
|
|
31569
|
+
` console.error('React recoverable error:', error);`,
|
|
31570
|
+
` }`,
|
|
31571
|
+
` }`,
|
|
31572
|
+
` }`,
|
|
31573
|
+
` );`,
|
|
31574
|
+
` window.__REACT_ROOT__ = root;`,
|
|
31575
|
+
` } catch (error) {`,
|
|
31576
|
+
` // Catch synchronous errors (shouldn't happen with hydrateRoot, but safety net)`,
|
|
31577
|
+
` if (isDev && isHydrationError(error)) {`,
|
|
31578
|
+
` handleHydrationFallback(error);`,
|
|
31579
|
+
` } else {`,
|
|
31580
|
+
` throw error;`,
|
|
31581
|
+
` }`,
|
|
31582
|
+
` }`,
|
|
31583
|
+
` } // end else (normal hydration path)
|
|
31584
|
+
`,
|
|
31585
|
+
` // Also listen for hydration errors via console.error (React logs them there)`,
|
|
31586
|
+
` if (isDev) {`,
|
|
31587
|
+
` const originalError = console.error;`,
|
|
31588
|
+
` console.error = function(...args) {`,
|
|
31589
|
+
` const errorMessage = args.map(arg => {`,
|
|
31590
|
+
` if (arg instanceof Error) return arg.message;`,
|
|
31591
|
+
` return String(arg);`,
|
|
31592
|
+
` }).join(' ');`,
|
|
31593
|
+
` `,
|
|
31594
|
+
` // Check if this is a hydration error`,
|
|
31595
|
+
` if (isHydrationError({ message: errorMessage }) && !hydrationErrorDetected) {`,
|
|
31596
|
+
` hydrationErrorDetected = true;`,
|
|
31597
|
+
` // Create a synthetic error for fallback`,
|
|
31598
|
+
` const syntheticError = new Error(errorMessage);`,
|
|
31599
|
+
` // Use setTimeout to ensure this happens after React's error handling`,
|
|
31600
|
+
` setTimeout(() => {`,
|
|
31601
|
+
` handleHydrationFallback(syntheticError);`,
|
|
31602
|
+
` }, 0);`,
|
|
31603
|
+
` }`,
|
|
31604
|
+
` `,
|
|
31605
|
+
` // Call original console.error`,
|
|
31606
|
+
` originalError.apply(console, args);`,
|
|
31607
|
+
` };`,
|
|
31608
|
+
` }`,
|
|
31609
|
+
`}`,
|
|
31610
|
+
...isDev2 ? [
|
|
31611
|
+
`
|
|
31612
|
+
// Pre-warm: import the page module from the module server`,
|
|
31613
|
+
`// immediately so the browser caches all /@src/ URLs.`,
|
|
31614
|
+
`import('/@src/${relative3(process.cwd(), resolve9(reactPagesDirectory, `${componentName}.tsx`)).replace(/\\/g, "/")}').catch(() => {});`
|
|
31615
|
+
] : []
|
|
31616
|
+
].join(`
|
|
31617
|
+
`);
|
|
31618
|
+
const indexPath = join4(reactIndexesDirectory, `${componentName}.tsx`);
|
|
31619
|
+
const hasher = new Bun.CryptoHasher("md5");
|
|
31620
|
+
hasher.update(content);
|
|
31621
|
+
const contentHash = hasher.digest("hex");
|
|
31622
|
+
if (indexContentCache.get(indexPath) === contentHash && existsSync5(indexPath)) {
|
|
31623
|
+
return;
|
|
31628
31624
|
}
|
|
31629
|
-
|
|
31630
|
-
|
|
31631
|
-
|
|
31625
|
+
indexContentCache.set(indexPath, contentHash);
|
|
31626
|
+
await writeFile(indexPath, content);
|
|
31627
|
+
});
|
|
31628
|
+
await Promise.all(promises);
|
|
31629
|
+
if (!isDev2) {
|
|
31630
|
+
return;
|
|
31632
31631
|
}
|
|
31633
|
-
|
|
31634
|
-
|
|
31635
|
-
|
|
31636
|
-
|
|
31637
|
-
|
|
31638
|
-
|
|
31639
|
-
const html = await renderAngularIslandToHtml(component, props.props, islandId);
|
|
31640
|
-
return {
|
|
31641
|
-
attributes: {
|
|
31642
|
-
...getIslandMarkerAttributes(props, islandId)
|
|
31643
|
-
},
|
|
31644
|
-
html
|
|
31645
|
-
};
|
|
31632
|
+
const refreshPath = join4(reactIndexesDirectory, "_refresh.tsx");
|
|
31633
|
+
if (!existsSync5(refreshPath)) {
|
|
31634
|
+
await writeFile(refreshPath, `import '${refreshSetupPath}';
|
|
31635
|
+
import 'react';
|
|
31636
|
+
import 'react-dom/client';
|
|
31637
|
+
`);
|
|
31646
31638
|
}
|
|
31647
|
-
throw new Error(`Framework "${props.framework}" is not implemented in this prototype.`);
|
|
31648
|
-
}, renderIslandMarkup = async (registry, props) => {
|
|
31649
|
-
const result = await renderIslandResult(registry, props);
|
|
31650
|
-
return `<div ${serializeIslandAttributes(result.attributes)}>${result.html}</div>`;
|
|
31651
31639
|
};
|
|
31652
|
-
var
|
|
31653
|
-
|
|
31654
|
-
|
|
31655
|
-
|
|
31656
|
-
|
|
31657
|
-
|
|
31658
|
-
resolvedServerBuildComponentCache = new Map;
|
|
31640
|
+
var init_generateReactIndexes = __esm(() => {
|
|
31641
|
+
indexContentCache = new Map;
|
|
31642
|
+
devClientDir = resolveDevClientDir();
|
|
31643
|
+
errorOverlayPath = join4(devClientDir, "errorOverlay.ts").replace(/\\/g, "/");
|
|
31644
|
+
hmrClientPath = join4(devClientDir, "hmrClient.ts").replace(/\\/g, "/");
|
|
31645
|
+
refreshSetupPath = join4(devClientDir, "reactRefreshSetup.ts").replace(/\\/g, "/");
|
|
31659
31646
|
});
|
|
31660
31647
|
|
|
31661
|
-
// src/build/
|
|
31662
|
-
import {
|
|
31663
|
-
var
|
|
31664
|
-
|
|
31665
|
-
const attributes = new Map;
|
|
31666
|
-
let match = attributeRe.exec(attributeString);
|
|
31667
|
-
while (match) {
|
|
31668
|
-
const key = match[1];
|
|
31669
|
-
const doubleQuotedValue = match[2];
|
|
31670
|
-
const singleQuotedValue = match[3];
|
|
31671
|
-
if (!key) {
|
|
31672
|
-
match = attributeRe.exec(attributeString);
|
|
31673
|
-
continue;
|
|
31674
|
-
}
|
|
31675
|
-
const value = doubleQuotedValue ?? singleQuotedValue ?? "";
|
|
31676
|
-
attributes.set(key, value);
|
|
31677
|
-
match = attributeRe.exec(attributeString);
|
|
31678
|
-
}
|
|
31679
|
-
return attributes;
|
|
31680
|
-
}, parseIslandTag = (attributeString) => {
|
|
31681
|
-
const attributes = parseIslandAttributes(attributeString);
|
|
31682
|
-
const framework = attributes.get("framework");
|
|
31683
|
-
const component = attributes.get("component");
|
|
31684
|
-
const hydrate = attributes.get("hydrate") ?? "load";
|
|
31685
|
-
const propsSource = attributes.get("props") ?? "{}";
|
|
31686
|
-
if (!framework || !component) {
|
|
31648
|
+
// src/build/islandBindingCompat.ts
|
|
31649
|
+
import { resolve as resolve10 } from "path";
|
|
31650
|
+
var packageToFramework, compatFileNames, normalize = (value) => value.replace(/\\/g, "/"), isFrameworkPackage = (value) => (value in packageToFramework), resolveIslandCompatModule = (specifier, importer, frameworkDirs) => {
|
|
31651
|
+
if (!isFrameworkPackage(specifier)) {
|
|
31687
31652
|
return null;
|
|
31688
31653
|
}
|
|
31689
|
-
|
|
31690
|
-
|
|
31654
|
+
const framework = packageToFramework[specifier];
|
|
31655
|
+
const frameworkDir = frameworkDirs[framework];
|
|
31656
|
+
if (!frameworkDir) {
|
|
31657
|
+
return null;
|
|
31691
31658
|
}
|
|
31692
|
-
|
|
31693
|
-
|
|
31659
|
+
const normalizedImporter = normalize(importer);
|
|
31660
|
+
const normalizedFrameworkDir = normalize(resolve10(frameworkDir));
|
|
31661
|
+
if (!normalizedImporter.startsWith(normalizedFrameworkDir)) {
|
|
31662
|
+
return null;
|
|
31694
31663
|
}
|
|
31695
|
-
|
|
31696
|
-
|
|
31697
|
-
const candidate = JSON.parse(propsSource);
|
|
31698
|
-
parsedProps = isRecord5(candidate) ? candidate : {};
|
|
31699
|
-
} catch (error) {
|
|
31700
|
-
throw new Error(`Failed to parse static island props JSON for ${framework}:${component}: ${error instanceof Error ? error.message : String(error)}`);
|
|
31664
|
+
if (normalizedImporter.includes("/generated/absolute-") || normalizedImporter.includes("/generated/Island.") || normalizedImporter.includes("/generated/islands.")) {
|
|
31665
|
+
return null;
|
|
31701
31666
|
}
|
|
31702
|
-
return
|
|
31703
|
-
|
|
31704
|
-
|
|
31705
|
-
|
|
31706
|
-
|
|
31667
|
+
return resolve10(frameworkDir, "generated", compatFileNames[framework]);
|
|
31668
|
+
};
|
|
31669
|
+
var init_islandBindingCompat = __esm(() => {
|
|
31670
|
+
packageToFramework = {
|
|
31671
|
+
"@absolutejs/absolute/angular": "angular",
|
|
31672
|
+
"@absolutejs/absolute/react": "react",
|
|
31673
|
+
"@absolutejs/absolute/svelte": "svelte",
|
|
31674
|
+
"@absolutejs/absolute/vue": "vue"
|
|
31707
31675
|
};
|
|
31708
|
-
|
|
31709
|
-
|
|
31710
|
-
|
|
31711
|
-
|
|
31712
|
-
|
|
31713
|
-
}
|
|
31714
|
-
|
|
31715
|
-
|
|
31716
|
-
|
|
31717
|
-
|
|
31718
|
-
|
|
31719
|
-
|
|
31720
|
-
|
|
31721
|
-
|
|
31722
|
-
|
|
31723
|
-
|
|
31724
|
-
|
|
31725
|
-
|
|
31726
|
-
|
|
31676
|
+
compatFileNames = {
|
|
31677
|
+
angular: "absolute-angular.ts",
|
|
31678
|
+
react: "absolute-react.ts",
|
|
31679
|
+
svelte: "absolute-svelte.ts",
|
|
31680
|
+
vue: "absolute-vue.ts"
|
|
31681
|
+
};
|
|
31682
|
+
});
|
|
31683
|
+
|
|
31684
|
+
// src/build/islandBindingPlugin.ts
|
|
31685
|
+
var exports_islandBindingPlugin = {};
|
|
31686
|
+
__export(exports_islandBindingPlugin, {
|
|
31687
|
+
createIslandBindingPlugin: () => createIslandBindingPlugin
|
|
31688
|
+
});
|
|
31689
|
+
var createIslandBindingPlugin = (frameworkDirs) => ({
|
|
31690
|
+
name: "absolute-island-binding-plugin",
|
|
31691
|
+
setup(build2) {
|
|
31692
|
+
build2.onResolve({
|
|
31693
|
+
filter: /^@absolutejs\/absolute\/(react|vue|svelte|angular)$/
|
|
31694
|
+
}, (args) => {
|
|
31695
|
+
const redirected = resolveIslandCompatModule(args.path, args.importer, frameworkDirs);
|
|
31696
|
+
if (!redirected) {
|
|
31697
|
+
return;
|
|
31698
|
+
}
|
|
31699
|
+
return {
|
|
31700
|
+
path: redirected
|
|
31701
|
+
};
|
|
31702
|
+
});
|
|
31727
31703
|
}
|
|
31728
|
-
|
|
31729
|
-
|
|
31730
|
-
|
|
31704
|
+
});
|
|
31705
|
+
var init_islandBindingPlugin = __esm(() => {
|
|
31706
|
+
init_islandBindingCompat();
|
|
31707
|
+
});
|
|
31708
|
+
|
|
31709
|
+
// src/build/wrapHTMLScript.ts
|
|
31710
|
+
var wrapHTMLScriptWithHMR = (code, scriptId) => {
|
|
31711
|
+
const escapedId = JSON.stringify(scriptId);
|
|
31712
|
+
return `${code}
|
|
31713
|
+
|
|
31714
|
+
// HMR acceptance - allows this script to be hot-reloaded
|
|
31715
|
+
if (typeof import.meta !== "undefined" && import.meta.hot) {
|
|
31716
|
+
import.meta.hot.accept();
|
|
31717
|
+
console.log('[HMR] Script ready:', ${escapedId});
|
|
31718
|
+
}
|
|
31719
|
+
`;
|
|
31720
|
+
};
|
|
31721
|
+
|
|
31722
|
+
// src/build/htmlScriptHMRPlugin.ts
|
|
31723
|
+
var scriptLoaders, toLoader = (ext) => {
|
|
31724
|
+
for (const loader of scriptLoaders) {
|
|
31725
|
+
if (loader === ext)
|
|
31726
|
+
return loader;
|
|
31731
31727
|
}
|
|
31732
|
-
|
|
31733
|
-
|
|
31734
|
-
|
|
31728
|
+
return "ts";
|
|
31729
|
+
}, createHTMLScriptHMRPlugin = (htmlDir, htmxDir) => ({
|
|
31730
|
+
name: "html-script-hmr",
|
|
31731
|
+
setup(build2) {
|
|
31732
|
+
build2.onLoad({ filter: /\.(ts|js|tsx|jsx)$/ }, async (args) => {
|
|
31733
|
+
const normalizedPath = args.path.replace(/\\/g, "/");
|
|
31734
|
+
const isHtmlScript = htmlDir && normalizedPath.includes(htmlDir.replace(/\\/g, "/")) && normalizedPath.includes("/scripts/");
|
|
31735
|
+
const isHtmxScript = htmxDir && normalizedPath.includes(htmxDir.replace(/\\/g, "/")) && normalizedPath.includes("/scripts/");
|
|
31736
|
+
if (!isHtmlScript && !isHtmxScript) {
|
|
31737
|
+
return;
|
|
31738
|
+
}
|
|
31739
|
+
const text2 = await Bun.file(args.path).text();
|
|
31740
|
+
const wrapped = wrapHTMLScriptWithHMR(text2, normalizedPath);
|
|
31741
|
+
const ext = args.path.split(".").pop() ?? "ts";
|
|
31742
|
+
const loader = toLoader(ext);
|
|
31743
|
+
return {
|
|
31744
|
+
contents: wrapped,
|
|
31745
|
+
loader
|
|
31746
|
+
};
|
|
31747
|
+
});
|
|
31735
31748
|
}
|
|
31736
|
-
|
|
31737
|
-
|
|
31738
|
-
|
|
31739
|
-
var init_staticIslandPages = __esm(() => {
|
|
31740
|
-
init_renderIslandMarkup();
|
|
31741
|
-
init_islandEntries();
|
|
31742
|
-
islandFrameworks2 = [
|
|
31743
|
-
"react",
|
|
31744
|
-
"svelte",
|
|
31745
|
-
"vue",
|
|
31746
|
-
"angular"
|
|
31747
|
-
];
|
|
31748
|
-
islandHydrationModes2 = ["load", "idle", "visible", "none"];
|
|
31749
|
+
});
|
|
31750
|
+
var init_htmlScriptHMRPlugin = __esm(() => {
|
|
31751
|
+
scriptLoaders = new Set(["ts", "js", "tsx", "jsx"]);
|
|
31749
31752
|
});
|
|
31750
31753
|
|
|
31751
31754
|
// src/build/outputLogs.ts
|
|
@@ -208783,11 +208786,13 @@ var asset = (source, name) => {
|
|
|
208783
208786
|
init_islands();
|
|
208784
208787
|
|
|
208785
208788
|
// src/core/pageHandlers.ts
|
|
208789
|
+
init_staticIslandPages();
|
|
208786
208790
|
init_pageHandler();
|
|
208787
208791
|
var {file } = globalThis.Bun;
|
|
208788
208792
|
var handleStaticPageRequest = async (pagePath) => {
|
|
208789
208793
|
const html = await file(pagePath).text();
|
|
208790
|
-
|
|
208794
|
+
const transformedHtml = await transformCurrentStaticPageHtml(html);
|
|
208795
|
+
return new Response(injectIslandPageContext(transformedHtml), {
|
|
208791
208796
|
headers: { "Content-Type": "text/html" }
|
|
208792
208797
|
});
|
|
208793
208798
|
};
|
|
@@ -208798,9 +208803,9 @@ import { existsSync as existsSync23, readdirSync as readdirSync2, readFileSync a
|
|
|
208798
208803
|
import { basename as basename12, join as join22, relative as relative12, resolve as resolve34 } from "path";
|
|
208799
208804
|
|
|
208800
208805
|
// src/utils/loadConfig.ts
|
|
208801
|
-
import { resolve } from "path";
|
|
208806
|
+
import { resolve as resolve5 } from "path";
|
|
208802
208807
|
var loadConfig = async (configPath) => {
|
|
208803
|
-
const resolved =
|
|
208808
|
+
const resolved = resolve5(configPath ?? process.env.ABSOLUTE_CONFIG ?? "absolute.config.ts");
|
|
208804
208809
|
const mod = await import(resolved);
|
|
208805
208810
|
const config = mod.default ?? mod.config;
|
|
208806
208811
|
if (!config) {
|
|
@@ -208810,24 +208815,24 @@ Expected: export default defineConfig({ ... })`);
|
|
|
208810
208815
|
return config;
|
|
208811
208816
|
};
|
|
208812
208817
|
// src/core/loadIslandRegistry.ts
|
|
208813
|
-
import { resolve as
|
|
208814
|
-
var
|
|
208815
|
-
var
|
|
208816
|
-
if (
|
|
208818
|
+
import { resolve as resolve6 } from "path";
|
|
208819
|
+
var isRecord5 = (value) => typeof value === "object" && value !== null;
|
|
208820
|
+
var resolveRegistryExport2 = (mod) => {
|
|
208821
|
+
if (isRecord5(mod.islandRegistry))
|
|
208817
208822
|
return mod.islandRegistry;
|
|
208818
|
-
if (
|
|
208823
|
+
if (isRecord5(mod.default))
|
|
208819
208824
|
return mod.default;
|
|
208820
208825
|
throw new Error("Island registry module must export `islandRegistry` or a default registry object.");
|
|
208821
208826
|
};
|
|
208822
|
-
var isRegistryModuleExport = (value) =>
|
|
208823
|
-
var isIslandRegistryInput = (value) =>
|
|
208827
|
+
var isRegistryModuleExport = (value) => isRecord5(value);
|
|
208828
|
+
var isIslandRegistryInput = (value) => isRecord5(value);
|
|
208824
208829
|
var loadIslandRegistry = async (registryPath) => {
|
|
208825
|
-
const resolvedRegistryPath =
|
|
208830
|
+
const resolvedRegistryPath = resolve6(registryPath);
|
|
208826
208831
|
const importedModule = await import(resolvedRegistryPath);
|
|
208827
208832
|
if (!isRegistryModuleExport(importedModule)) {
|
|
208828
208833
|
throw new Error("Island registry module must export an object namespace.");
|
|
208829
208834
|
}
|
|
208830
|
-
const registryExport =
|
|
208835
|
+
const registryExport = resolveRegistryExport2(importedModule);
|
|
208831
208836
|
if (!isIslandRegistryInput(registryExport)) {
|
|
208832
208837
|
throw new Error("Resolved island registry export is not an object.");
|
|
208833
208838
|
}
|
|
@@ -215445,5 +215450,5 @@ export {
|
|
|
215445
215450
|
ANGULAR_INIT_TIMEOUT_MS
|
|
215446
215451
|
};
|
|
215447
215452
|
|
|
215448
|
-
//# debugId=
|
|
215453
|
+
//# debugId=F4015D5A2C67198764756E2164756E21
|
|
215449
215454
|
//# sourceMappingURL=index.js.map
|