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'); + }); });