Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(rendering): prevent removal of necessary <astro-slot> elements #10317

Merged
merged 7 commits into from
Mar 7, 2024

Conversation

lilnasy
Copy link
Contributor

@lilnasy lilnasy commented Mar 4, 2024

Changes

Testing

  • Added a case to a pre-existing E2E fixture.

Docs

  • Does not affect usage.

Copy link

changeset-bot bot commented Mar 4, 2024

🦋 Changeset detected

Latest commit: 1ff765a

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added the pkg: astro Related to the core `astro` package (scope) label Mar 4, 2024
@lilnasy lilnasy force-pushed the fix/8247 branch 2 times, most recently from e713ce0 to 765caf8 Compare March 4, 2024 23:03
Comment on lines -21 to 25
it('Astro slot tags are cleaned', async () => {
it('Astro slot tags are kept', async () => {
const html = await fixture.readFile('/index.html');
const $ = cheerio.load(html);
assert.equal($('astro-slot').length, 0);
assert.equal($('astro-slot').length, 1);
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test was checking for the conditions that cause the bug. We need <astro-slot> elements to exist to allow slots to render after hydration.

@lilnasy lilnasy marked this pull request as ready for review March 5, 2024 00:59
Copy link
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix seems reasonable to me, but it would be great if @matthewp or @bluwy could weigh in

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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"parent of a parent" -> "grandparent"?

Copy link
Contributor

@matthewp matthewp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice explanation!

Given that this is a sticky part of the code, I think we should release this in its own patch so it's easier to spot regressions if they happen.

Copy link
Member

@bluwy bluwy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternating the slots feels like working around the issue and could have a performance impact compared to if we can render it directly correctly. Could this be fixed instead by only stripping away <astro-slot> for non-slot/child templates? e.g.

const childSlots = Object.values(children).join('');
const renderTemplateResult = renderTemplate`<${Tag}${internalSpreadAttributes(
props
)}${markHTMLString(
childSlots === '' && voidElementNames.test(Tag) ? `/>` : `>${childSlots}</${Tag}>`
)}`;

Could we only replace <astro-slot> for non childSlots rendered strings? Is this issue also affected by those html that're assigned by renderToStaticMarkup too?

@lilnasy
Copy link
Contributor Author

lilnasy commented Mar 7, 2024

@bluwy Do you mean to make an exception for the "tagname as component" case?

@bluwy
Copy link
Member

bluwy commented Mar 7, 2024

I mean that html can be derived from several ways, e.g. renderToStaticMarkup, "tagname as component", etc. And I noticed the tests only tested for "tagname as component", and I wonder if the issue only arises in this way?

If so, I was thinking we can make the fix directly in the if block for the "tagname as component" handling. Or if not, then I think this PR is probably the easiest fix, since I'm not sure if there's a reliable way to say "this chunk belongs to a slot, and we skip replacing astro-slots in it. For other chunks, we do the replacement"

@lilnasy
Copy link
Contributor Author

lilnasy commented Mar 7, 2024

I noticed the tests only tested for "tagname as component", and I wonder if the issue only arises in this way?

I don't think the issue is limited to it. but I'll take another look.

Copy link
Member

@natemoo-re natemoo-re left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works for me! If there's a cleaner way to do the transformations as Blu suggested, I'm all for it. But this solution is aligned with our current hacky code, so I'm cool if the RegExp approach is the one that gets merged.

@lilnasy
Copy link
Contributor Author

lilnasy commented Mar 7, 2024

@bluwy

First-party framework components are not affected because they signal using "supportsAstroStaticSlots" that they will render astro-static-slot for the non-hydration case.

A much simpler 90% fix could be assuming that renderers do that by default.

@lilnasy
Copy link
Contributor Author

lilnasy commented Mar 7, 2024

The simpler fix works.

Required slots could still be removed if there's a third-party renderer that explicitly sets the "supportsAstroStaticSlots" flag to false. Qwik sets the flag to true, and analog doesn't set it, so it's more like a 99% fix.

For Astro 5.0, we should remove the flag to assume renderers that will always distinguish between hydratable and non-hydratable slots on their own. This was originally intended for Astro 3.0, but wasn't tracked.

Copy link
Member

@bluwy bluwy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! Thanks for looking into it. This looks a ton simpler and makes sense to me too.

packages/astro/src/runtime/server/render/component.ts Outdated Show resolved Hide resolved
@lilnasy lilnasy merged commit 33583e8 into withastro:main Mar 7, 2024
13 checks passed
@lilnasy lilnasy deleted the fix/8247 branch March 7, 2024 16:25
@astrobot-houston astrobot-houston mentioned this pull request Mar 7, 2024
@natemoo-re natemoo-re mentioned this pull request Mar 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg: astro Related to the core `astro` package (scope)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

slot content disappears upon hydration when using polymorphic tags
5 participants