Fix head propagation for MDX components (#7838)
This commit is contained in:
parent
365701f491
commit
e50f646758
10 changed files with 15 additions and 52 deletions
5
.changeset/friendly-bulldogs-flash.md
Normal file
5
.changeset/friendly-bulldogs-flash.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix head propagation for MDX components
|
|
@ -2033,8 +2033,6 @@ export interface SSRMetadata {
|
||||||
headInTree: boolean;
|
headInTree: boolean;
|
||||||
extraHead: string[];
|
extraHead: string[];
|
||||||
propagators: Map<AstroComponentFactory, AstroComponentInstance>;
|
propagators: Map<AstroComponentFactory, AstroComponentInstance>;
|
||||||
// Used to key track of unique content; links and script tags
|
|
||||||
contentKeys: Set<string>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Preview server stuff */
|
/* Preview server stuff */
|
||||||
|
|
|
@ -7,7 +7,7 @@ import {
|
||||||
createHeadAndContent,
|
createHeadAndContent,
|
||||||
renderComponent,
|
renderComponent,
|
||||||
renderTemplate,
|
renderTemplate,
|
||||||
renderUniqueScriptElement,
|
renderScriptElement,
|
||||||
renderUniqueStylesheet,
|
renderUniqueStylesheet,
|
||||||
unescapeHTML,
|
unescapeHTML,
|
||||||
type AstroComponentFactory,
|
type AstroComponentFactory,
|
||||||
|
@ -303,9 +303,7 @@ async function render({
|
||||||
.join('');
|
.join('');
|
||||||
}
|
}
|
||||||
if (Array.isArray(collectedScripts)) {
|
if (Array.isArray(collectedScripts)) {
|
||||||
scripts = collectedScripts
|
scripts = collectedScripts.map((script: any) => renderScriptElement(script)).join('');
|
||||||
.map((script: any) => renderUniqueScriptElement(result, script))
|
|
||||||
.join('');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let props = baseProps;
|
let props = baseProps;
|
||||||
|
|
|
@ -258,7 +258,6 @@ export function createResult(args: CreateResultArgs): SSRResult {
|
||||||
headInTree: false,
|
headInTree: false,
|
||||||
extraHead: [],
|
extraHead: [],
|
||||||
propagators: new Map(),
|
propagators: new Map(),
|
||||||
contentKeys: new Set(),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@ export {
|
||||||
renderSlotToString,
|
renderSlotToString,
|
||||||
renderTemplate,
|
renderTemplate,
|
||||||
renderToString,
|
renderToString,
|
||||||
renderUniqueScriptElement,
|
|
||||||
renderUniqueStylesheet,
|
renderUniqueStylesheet,
|
||||||
voidElementNames,
|
voidElementNames,
|
||||||
} from './render/index.js';
|
} from './render/index.js';
|
||||||
|
|
|
@ -37,6 +37,7 @@ export class AstroComponentInstance {
|
||||||
}
|
}
|
||||||
|
|
||||||
async init(result: SSRResult) {
|
async init(result: SSRResult) {
|
||||||
|
if (this.returnValue !== undefined) return this.returnValue;
|
||||||
this.returnValue = this.factory(result, this.props, this.slotValues);
|
this.returnValue = this.factory(result, this.props, this.slotValues);
|
||||||
return this.returnValue;
|
return this.returnValue;
|
||||||
}
|
}
|
||||||
|
@ -72,7 +73,7 @@ function validateComponentProps(props: any, displayName: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createAstroComponentInstance(
|
export function createAstroComponentInstance(
|
||||||
result: SSRResult,
|
result: SSRResult,
|
||||||
displayName: string,
|
displayName: string,
|
||||||
factory: AstroComponentFactory,
|
factory: AstroComponentFactory,
|
||||||
|
@ -81,16 +82,9 @@ export async function createAstroComponentInstance(
|
||||||
) {
|
) {
|
||||||
validateComponentProps(props, displayName);
|
validateComponentProps(props, displayName);
|
||||||
const instance = new AstroComponentInstance(result, props, slots, factory);
|
const instance = new AstroComponentInstance(result, props, slots, factory);
|
||||||
|
|
||||||
if (isAPropagatingComponent(result, factory) && !result._metadata.propagators.has(factory)) {
|
if (isAPropagatingComponent(result, factory) && !result._metadata.propagators.has(factory)) {
|
||||||
result._metadata.propagators.set(factory, instance);
|
result._metadata.propagators.set(factory, instance);
|
||||||
// Call component instances that might have head content to be propagated up.
|
|
||||||
const returnValue = await instance.init(result);
|
|
||||||
if (isHeadAndContent(returnValue)) {
|
|
||||||
result._metadata.extraHead.push(returnValue.head);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,12 +71,12 @@ export async function renderToReadableStream(
|
||||||
// If the Astro component returns a Response on init, return that response
|
// If the Astro component returns a Response on init, return that response
|
||||||
if (templateResult instanceof Response) return templateResult;
|
if (templateResult instanceof Response) return templateResult;
|
||||||
|
|
||||||
|
let renderedFirstPageChunk = false;
|
||||||
|
|
||||||
if (isPage) {
|
if (isPage) {
|
||||||
await bufferHeadContent(result);
|
await bufferHeadContent(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
let renderedFirstPageChunk = false;
|
|
||||||
|
|
||||||
return new ReadableStream({
|
return new ReadableStream({
|
||||||
start(controller) {
|
start(controller) {
|
||||||
const destination: RenderDestination = {
|
const destination: RenderDestination = {
|
||||||
|
@ -158,6 +158,7 @@ async function bufferHeadContent(result: SSRResult) {
|
||||||
if (done) {
|
if (done) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// Call component instances that might have head content to be propagated up.
|
||||||
const returnValue = await value.init(result);
|
const returnValue = await value.init(result);
|
||||||
if (isHeadAndContent(returnValue)) {
|
if (isHeadAndContent(returnValue)) {
|
||||||
result._metadata.extraHead.push(returnValue.head);
|
result._metadata.extraHead.push(returnValue.head);
|
||||||
|
|
|
@ -420,7 +420,7 @@ async function renderAstroComponent(
|
||||||
props: Record<string | number, any>,
|
props: Record<string | number, any>,
|
||||||
slots: any = {}
|
slots: any = {}
|
||||||
): Promise<RenderInstance> {
|
): Promise<RenderInstance> {
|
||||||
const instance = await createAstroComponentInstance(result, displayName, Component, props, slots);
|
const instance = createAstroComponentInstance(result, displayName, Component, props, slots);
|
||||||
|
|
||||||
// Eagerly render the component so they are rendered in parallel
|
// Eagerly render the component so they are rendered in parallel
|
||||||
const chunks: RenderDestinationChunk[] = [];
|
const chunks: RenderDestinationChunk[] = [];
|
||||||
|
|
|
@ -6,6 +6,6 @@ export { renderHTMLElement } from './dom.js';
|
||||||
export { maybeRenderHead, renderHead } from './head.js';
|
export { maybeRenderHead, renderHead } from './head.js';
|
||||||
export { renderPage } from './page.js';
|
export { renderPage } from './page.js';
|
||||||
export { renderSlot, renderSlotToString, type ComponentSlots } from './slot.js';
|
export { renderSlot, renderSlotToString, type ComponentSlots } from './slot.js';
|
||||||
export { renderScriptElement, renderUniqueScriptElement, renderUniqueStylesheet } from './tags.js';
|
export { renderScriptElement, renderUniqueStylesheet } from './tags.js';
|
||||||
export type { RenderInstruction } from './types';
|
export type { RenderInstruction } from './types';
|
||||||
export { addAttribute, defineScriptVars, voidElementNames } from './util.js';
|
export { addAttribute, defineScriptVars, voidElementNames } from './util.js';
|
||||||
|
|
|
@ -9,45 +9,14 @@ 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) {
|
export function renderUniqueStylesheet(result: SSRResult, sheet: StylesheetAsset) {
|
||||||
if (sheet.type === 'external') {
|
if (sheet.type === 'external') {
|
||||||
if (Array.from(result.styles).some((s) => s.props.href === sheet.src)) return '';
|
if (Array.from(result.styles).some((s) => s.props.href === sheet.src)) return '';
|
||||||
const key = 'link-external-' + sheet.src;
|
return renderElement('link', { props: { rel: 'stylesheet', href: sheet.src }, children: '' });
|
||||||
if (checkOrAddContentKey(result, key)) return '';
|
|
||||||
return renderElement('link', {
|
|
||||||
props: {
|
|
||||||
rel: 'stylesheet',
|
|
||||||
href: sheet.src,
|
|
||||||
},
|
|
||||||
children: '',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sheet.type === 'inline') {
|
if (sheet.type === 'inline') {
|
||||||
if (Array.from(result.styles).some((s) => s.children.includes(sheet.content))) return '';
|
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 });
|
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;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue