From fa77fa63d944f709a37f08be93f0d14fe1d91188 Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Mon, 11 Sep 2023 20:39:22 +0800 Subject: [PATCH] Prevent style removal of client:only components (#8472) --- .changeset/grumpy-hotels-heal.md | 5 +++++ .../astro/components/ViewTransitions.astro | 15 ++++++++++++++ .../src/pages/client-only-one.astro | 10 ++++++++++ .../src/pages/client-only-two.astro | 10 ++++++++++ packages/astro/e2e/view-transitions.test.js | 20 +++++++++++++++++++ 5 files changed, 60 insertions(+) create mode 100644 .changeset/grumpy-hotels-heal.md create mode 100644 packages/astro/e2e/fixtures/view-transitions/src/pages/client-only-one.astro create mode 100644 packages/astro/e2e/fixtures/view-transitions/src/pages/client-only-two.astro diff --git a/.changeset/grumpy-hotels-heal.md b/.changeset/grumpy-hotels-heal.md new file mode 100644 index 000000000..f171c91fb --- /dev/null +++ b/.changeset/grumpy-hotels-heal.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Prevent client:only styles from being removed in dev (View Transitions) diff --git a/packages/astro/components/ViewTransitions.astro b/packages/astro/components/ViewTransitions.astro index 8fb506037..822be5ccb 100644 --- a/packages/astro/components/ViewTransitions.astro +++ b/packages/astro/components/ViewTransitions.astro @@ -113,6 +113,11 @@ const { fallback = 'animate' } = Astro.props as Props; const parser = new DOMParser(); + // A noop element used to prevent styles from being removed + if(import.meta.env.DEV) { + var noopEl: string | undefined = document.createElement('div'); + } + async function updateDOM(doc: Document, loc: URL, state?: State, fallback?: Fallback) { // Check for a head element that should persist, either because it has the data // attribute or is a link el. @@ -139,6 +144,16 @@ const { fallback = 'animate' } = Astro.props as Props; } } } + // Only run this in dev. This will get stripped from production builds and is not needed. + if(import.meta.env.DEV) { + if(el.tagName === 'STYLE' && el.dataset.viteDevId) { + const devId = el.dataset.viteDevId; + // If this same style tag exists, remove it from the new page + return doc.querySelector(`style[data-astro-dev-id="${devId}"]`) + // Otherwise, keep it anyways. This is client:only styles. + || noopEl; + } + } return null; }; diff --git a/packages/astro/e2e/fixtures/view-transitions/src/pages/client-only-one.astro b/packages/astro/e2e/fixtures/view-transitions/src/pages/client-only-one.astro new file mode 100644 index 000000000..a8d5e8995 --- /dev/null +++ b/packages/astro/e2e/fixtures/view-transitions/src/pages/client-only-one.astro @@ -0,0 +1,10 @@ +--- +import Layout from '../components/Layout.astro'; +import Island from '../components/Island'; +--- + + go to page 2 +
+ message here +
+
diff --git a/packages/astro/e2e/fixtures/view-transitions/src/pages/client-only-two.astro b/packages/astro/e2e/fixtures/view-transitions/src/pages/client-only-two.astro new file mode 100644 index 000000000..884ec4683 --- /dev/null +++ b/packages/astro/e2e/fixtures/view-transitions/src/pages/client-only-two.astro @@ -0,0 +1,10 @@ +--- +import Layout from '../components/Layout.astro'; +import Island from '../components/Island'; +--- + +

Page 2

+
+ message here +
+
diff --git a/packages/astro/e2e/view-transitions.test.js b/packages/astro/e2e/view-transitions.test.js index 80a180608..bd8ad5c36 100644 --- a/packages/astro/e2e/view-transitions.test.js +++ b/packages/astro/e2e/view-transitions.test.js @@ -565,4 +565,24 @@ test.describe('View Transitions', () => { p = page.locator('#one'); await expect(p, 'should have content').toHaveText('Page 1'); }); + + test("client:only styles are retained on transition", async ({ page, astro }) => { + const totalExpectedStyles = 8; + + // Go to page 1 + await page.goto(astro.resolveUrl('/client-only-one')); + let msg = page.locator('.counter-message'); + await expect(msg).toHaveText('message here'); + + let styles = await page.locator('style').all(); + expect(styles.length).toEqual(totalExpectedStyles); + + await page.click('#click-two'); + + let pageTwo = page.locator('#page-two'); + await expect(pageTwo, 'should have content').toHaveText('Page 2'); + + styles = await page.locator('style').all(); + expect(styles.length).toEqual(totalExpectedStyles, 'style count has not changed'); + }); });