Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions packages/host/app/routes/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ export default class RenderRoute extends Route<Model> {
(globalThis as any).__waitForRenderLoadStability = undefined;
window.removeEventListener('boxel-render-error', this.handleRenderError);
this.#detachWindowErrorListeners();
this.#removePrerenderBaseHref();
this.lastStoreResetKey = undefined;
this.renderBaseParams = undefined;
this.lastRenderErrorSignature = undefined;
Expand Down Expand Up @@ -214,6 +215,14 @@ export default class RenderRoute extends Route<Model> {
let parsedOptions = parseRenderRouteOptions(options);
let canonicalOptions = serializeRenderRouteOptions(parsedOptions);
this.#setupTransitionHelper(id, nonce, canonicalOptions);
if (!isTesting()) {
// Without this, relative `<img src>` in a card template resolves
// against the /render/... synthetic URL and 404s. Skipped in tests:
// <base href> is document-wide, and the test harness loads libraries
// (e.g. Monaco) that resolve their worker URLs against document.baseURI.
// Real prerender headless browsers don't load Monaco. CS-11146.
this.#installPrerenderBaseHref(id);
}
// Stamp the "consuming realm" — the realm that owns the card being
// rendered — onto a global the store-service's federated-search
// wrapper reads. The realm-server's job-scoped search cache pairs
Expand Down Expand Up @@ -936,6 +945,10 @@ export default class RenderRoute extends Route<Model> {
(globalThis as any).__renderModel = undefined;
(globalThis as any).__docsInFlight = undefined;
(globalThis as any).__waitForRenderLoadStability = undefined;
// Same reason as the globals above: in tests the owner can be
// destroyed without deactivate firing, which would leak the
// injected <base> into the next route/test.
this.#removePrerenderBaseHref();
});
}

Expand Down Expand Up @@ -1509,6 +1522,46 @@ export default class RenderRoute extends Route<Model> {
return id;
}

#installPrerenderBaseHref(id: string): void {
if (typeof document === 'undefined') {
return;
}
let baseHref: string;
try {
baseHref = new URL('./', this.#normalizeCardId(id)).href;
} catch {
return;
}
let head = document.head;
if (!head) {
return;
}
let existing = head.querySelector(
'base[data-prerender-base]',
) as HTMLBaseElement | null;
if (existing) {
if (existing.href !== baseHref) {
existing.href = baseHref;
}
return;
}
let baseEl = document.createElement('base');
baseEl.setAttribute('data-prerender-base', '');
baseEl.href = baseHref;
if (head.firstChild) {
head.insertBefore(baseEl, head.firstChild);
} else {
head.appendChild(baseEl);
}
}

#removePrerenderBaseHref(): void {
if (typeof document === 'undefined') {
return;
}
document.head?.querySelector('base[data-prerender-base]')?.remove();
}
Comment on lines +1558 to +1563

#fallbackDepsFromIds(ids: (string | undefined)[]): string[] {
// Seed dependency ids in every shape we might see in index/module rows:
// original id, normalized card id, and `.json` variants. This keeps error
Expand Down
Loading