Skip to content

Commit

Permalink
fix(rendering): prevent removal of necessary <astro-slot> elements
Browse files Browse the repository at this point in the history
  • Loading branch information
lilnasy committed Mar 4, 2024
1 parent d1700cf commit 765caf8
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 2 deletions.
4 changes: 3 additions & 1 deletion packages/astro/src/runtime/server/render/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import { renderAllHeadContent } from './head.js';
import { isRenderInstruction } from './instruction.js';
import { type SlotString, isSlotString } from './slot.js';
import { restoreHydratableAstroSlot } from './component.js';

/**
* Possible chunk types to be written to the destination, and it'll
Expand Down Expand Up @@ -137,7 +138,8 @@ export function chunkToByteArray(
} else {
// `stringifyChunk` might return a HTMLString, call `.toString()` to really ensure it's a string
const stringified = stringifyChunk(result, chunk);
return encoder.encode(stringified.toString());
const restoredMarkup = restoreHydratableAstroSlot(stringified)
return encoder.encode(restoredMarkup.toString());
}
}

Expand Down
27 changes: 26 additions & 1 deletion packages/astro/src/runtime/server/render/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,35 @@ function isHTMLComponent(Component: unknown) {
}

const ASTRO_SLOT_EXP = /<\/?astro-slot\b[^>]*>/g;
// same as ASTRO_SLOT_EXP, but only includes the tag name in the match while requiring that it still be surrounded by "<" and ">"
const ASTRO_SLOT_TAGNAME_EXP = /(?<=<\/?)astro-slot(?=\b[^>]*>)/g;
// used to match temporary tags that will be replaced back with astro-slot
const ASTRO_PRESERVED_SLOT_TAGNAME_EXP = /(?<=<\/?)astro-preserved-slot(?=\b[^>]*>)/g;

const ASTRO_STATIC_SLOT_EXP = /<\/?astro-static-slot\b[^>]*>/g;
// same as ASTRO_STATIC_SLOT_EXP, but only includes the tag name in the match while requiring that it still be surrounded by "<" and ">"
const ASTRO_STATIC_SLOT_TAGNAME_EXP = /(?<=<\/?)astro-static-slot(?=\b[^>]*>)/g;
// used to match temporary tags that will be replaced back with astro-static-slot
const ASTRO_PRESERVED_STATIC_SLOT_TAGNAME_EXP = /(?<=<\/?)astro-preserved-static-slot(?=\b[^>]*>)/g;

function removeStaticAstroSlot(html: string, supportsAstroStaticSlot: boolean) {
const exp = supportsAstroStaticSlot ? ASTRO_STATIC_SLOT_EXP : ASTRO_SLOT_EXP;
return html.replace(exp, '');
}

// An HTML string may be processed by the parent of a parent, and if it isn't to be hydrated, astro-slot tags will be incorrectly removed.
// We rename them here so that the regex doesn't match.
function preserveHydratableAstroSlot(html: string, supportsAstroStaticSlot: boolean) {
const exp = supportsAstroStaticSlot ? ASTRO_STATIC_SLOT_TAGNAME_EXP : ASTRO_SLOT_TAGNAME_EXP;
const replacement = supportsAstroStaticSlot ? 'astro-preserved-static-slot' : 'astro-preserved-slot';
return html.replaceAll(exp, replacement);
}

export function restoreHydratableAstroSlot(html: string) {
return html.replaceAll(ASTRO_PRESERVED_STATIC_SLOT_TAGNAME_EXP, 'astro-static-slot')
.replaceAll(ASTRO_PRESERVED_SLOT_TAGNAME_EXP, 'astro-slot');
}

async function renderFrameworkComponent(
result: SSRResult,
displayName: string,
Expand Down Expand Up @@ -391,7 +414,9 @@ If you're still stuck, please open an issue on GitHub or join us at https://astr
})
);
}
destination.write(markHTMLString(renderElement('astro-island', island, false)));
const renderedElement = renderElement('astro-island', island, false);
const hydratableMarkup = preserveHydratableAstroSlot(renderedElement, renderer?.ssr?.supportsAstroStaticSlot ?? false);
destination.write(markHTMLString(hydratableMarkup));
},
};
}
Expand Down

0 comments on commit 765caf8

Please sign in to comment.