summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/yellow-olives-sing.md5
-rw-r--r--packages/astro/src/@types/astro.ts2
-rw-r--r--packages/astro/src/content/runtime.ts4
-rw-r--r--packages/astro/src/core/render/result.ts1
-rw-r--r--packages/astro/src/runtime/server/index.ts1
-rw-r--r--packages/astro/src/runtime/server/render/astro/render.ts20
-rw-r--r--packages/astro/src/runtime/server/render/index.ts2
-rw-r--r--packages/astro/src/runtime/server/render/tags.ts31
8 files changed, 62 insertions, 4 deletions
diff --git a/.changeset/yellow-olives-sing.md b/.changeset/yellow-olives-sing.md
new file mode 100644
index 000000000..8ba00915e
--- /dev/null
+++ b/.changeset/yellow-olives-sing.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Fixes head propagation regression
diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts
index fb34954ac..635ef0331 100644
--- a/packages/astro/src/@types/astro.ts
+++ b/packages/astro/src/@types/astro.ts
@@ -2033,6 +2033,8 @@ export interface SSRMetadata {
headInTree: boolean;
extraHead: string[];
propagators: Map<AstroComponentFactory, AstroComponentInstance>;
+ // Used to key track of unique content; links and script tags
+ contentKeys: Set<string>;
}
/* Preview server stuff */
diff --git a/packages/astro/src/content/runtime.ts b/packages/astro/src/content/runtime.ts
index a1afb2201..112428587 100644
--- a/packages/astro/src/content/runtime.ts
+++ b/packages/astro/src/content/runtime.ts
@@ -6,7 +6,7 @@ import {
createComponent,
createHeadAndContent,
renderComponent,
- renderScriptElement,
+ renderUniqueScriptElement,
renderTemplate,
renderUniqueStylesheet,
unescapeHTML,
@@ -303,7 +303,7 @@ async function render({
.join('');
}
if (Array.isArray(collectedScripts)) {
- scripts = collectedScripts.map((script: any) => renderScriptElement(script)).join('');
+ scripts = collectedScripts.map((script: any) => renderUniqueScriptElement(result, script)).join('');
}
let props = baseProps;
diff --git a/packages/astro/src/core/render/result.ts b/packages/astro/src/core/render/result.ts
index 968b232d4..2bfdb99b0 100644
--- a/packages/astro/src/core/render/result.ts
+++ b/packages/astro/src/core/render/result.ts
@@ -258,6 +258,7 @@ export function createResult(args: CreateResultArgs): SSRResult {
headInTree: false,
extraHead: [],
propagators: new Map(),
+ contentKeys: new Set(),
},
};
diff --git a/packages/astro/src/runtime/server/index.ts b/packages/astro/src/runtime/server/index.ts
index aca260d00..9acc41232 100644
--- a/packages/astro/src/runtime/server/index.ts
+++ b/packages/astro/src/runtime/server/index.ts
@@ -28,6 +28,7 @@ export {
renderTemplate,
renderToString,
renderUniqueStylesheet,
+ renderUniqueScriptElement,
voidElementNames,
} from './render/index.js';
export type {
diff --git a/packages/astro/src/runtime/server/render/astro/render.ts b/packages/astro/src/runtime/server/render/astro/render.ts
index 89dc28b75..0cb7d43fa 100644
--- a/packages/astro/src/runtime/server/render/astro/render.ts
+++ b/packages/astro/src/runtime/server/render/astro/render.ts
@@ -71,6 +71,10 @@ export async function renderToReadableStream(
// If the Astro component returns a Response on init, return that response
if (templateResult instanceof Response) return templateResult;
+ if (isPage) {
+ await bufferHeadContent(result);
+ }
+
let renderedFirstPageChunk = false;
return new ReadableStream({
@@ -144,3 +148,19 @@ async function callComponentAsTemplateResultOrResponse(
return isHeadAndContent(factoryResult) ? factoryResult.content : factoryResult;
}
+
+// Recursively calls component instances that might have head content
+// to be propagated up.
+async function bufferHeadContent(result: SSRResult) {
+ const iterator = result._metadata.propagators.values();
+ while (true) {
+ const { value, done } = iterator.next();
+ if (done) {
+ break;
+ }
+ const returnValue = await value.init(result);
+ if (isHeadAndContent(returnValue)) {
+ result._metadata.extraHead.push(returnValue.head);
+ }
+ }
+}
diff --git a/packages/astro/src/runtime/server/render/index.ts b/packages/astro/src/runtime/server/render/index.ts
index 70d63ca60..4760e07b7 100644
--- a/packages/astro/src/runtime/server/render/index.ts
+++ b/packages/astro/src/runtime/server/render/index.ts
@@ -6,6 +6,6 @@ export { renderHTMLElement } from './dom.js';
export { maybeRenderHead, renderHead } from './head.js';
export { renderPage } from './page.js';
export { renderSlot, renderSlotToString, type ComponentSlots } from './slot.js';
-export { renderScriptElement, renderUniqueStylesheet } from './tags.js';
+export { renderScriptElement, renderUniqueScriptElement, renderUniqueStylesheet } from './tags.js';
export type { RenderInstruction } from './types';
export { addAttribute, defineScriptVars, voidElementNames } from './util.js';
diff --git a/packages/astro/src/runtime/server/render/tags.ts b/packages/astro/src/runtime/server/render/tags.ts
index f15da6571..dd38f27be 100644
--- a/packages/astro/src/runtime/server/render/tags.ts
+++ b/packages/astro/src/runtime/server/render/tags.ts
@@ -9,14 +9,43 @@ export function renderScriptElement({ props, children }: SSRElement) {
});
}
+export function renderUniqueScriptElement(result: SSRResult, { props, children }: SSRElement) {
+ if(Array.from(result.scripts).some(s => {
+ if(s.props.type === props.type && s.props.src === props.src) {
+ return true;
+ }
+ if(!props.src && s.children === children) return true;
+ })) return '';
+ const key = `script-${props.type}-${props.src}-${children}`;
+ if(checkOrAddContentKey(result, key)) return '';
+ return renderScriptElement({ props, children });
+
+}
+
export function renderUniqueStylesheet(result: SSRResult, sheet: StylesheetAsset) {
if (sheet.type === 'external') {
if (Array.from(result.styles).some((s) => s.props.href === sheet.src)) return '';
- return renderElement('link', { props: { rel: 'stylesheet', href: sheet.src }, children: '' });
+ const key = 'link-external-' + sheet.src;
+ if(checkOrAddContentKey(result, key)) return '';
+ return renderElement('link', {
+ props: {
+ rel: 'stylesheet',
+ href: sheet.src
+ },
+ children: ''
+ });
}
if (sheet.type === 'inline') {
if (Array.from(result.styles).some((s) => s.children.includes(sheet.content))) return '';
+ const key = `link-inline-` + sheet.content;
+ if(checkOrAddContentKey(result, key)) return '';
return renderElement('style', { props: { type: 'text/css' }, children: sheet.content });
}
}
+
+function checkOrAddContentKey(result: SSRResult, key: string): boolean {
+ if(result._metadata.contentKeys.has(key)) return true;
+ result._metadata.contentKeys.add(key);
+ return false;
+}