From 274e6753281edde72fcb4af1cf8a9f892ee46127 Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Fri, 21 Jul 2023 16:26:42 -0400 Subject: [PATCH] Prevent FOUC with production links in ViewTransitions (#7756) * Prevent FOUC with production links in ViewTransitions * Adding changeset * Move up so it works with fallback too --- .changeset/cool-deers-dream.md | 5 +++++ packages/astro/components/ViewTransitions.astro | 10 ++++++++++ .../fixtures/view-transitions/public/two.css | 3 +++ .../src/components/Layout.astro | 7 +++++++ .../view-transitions/src/pages/two.astro | 2 +- packages/astro/e2e/view-transitions.test.js | 17 +++++++++++++++++ 6 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 .changeset/cool-deers-dream.md create mode 100644 packages/astro/e2e/fixtures/view-transitions/public/two.css diff --git a/.changeset/cool-deers-dream.md b/.changeset/cool-deers-dream.md new file mode 100644 index 000000000000..f4b462df4b1c --- /dev/null +++ b/.changeset/cool-deers-dream.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixes case where there is FOUC caused by stylesheets not loaded diff --git a/packages/astro/components/ViewTransitions.astro b/packages/astro/components/ViewTransitions.astro index 8b22671b9c77..ad5a9b0f65ce 100644 --- a/packages/astro/components/ViewTransitions.astro +++ b/packages/astro/components/ViewTransitions.astro @@ -47,6 +47,16 @@ const { fallback = 'animate' } = Astro.props as Props; doc.documentElement.dataset.astroTransition = dir; const swap = () => document.documentElement.replaceWith(doc.documentElement); + // Wait on links to finish, to prevent FOUC + const links = Array.from(doc.querySelectorAll('head link[rel=stylesheet]')).map(link => new Promise(resolve => { + const c = link.cloneNode(); + ['load', 'error'].forEach(evName => c.addEventListener(evName, resolve)); + document.head.append(c); + })); + if(links.length) { + await Promise.all(links); + } + if (fallback === 'animate') { let isAnimating = false; addEventListener('animationstart', () => (isAnimating = true), { once: true }); diff --git a/packages/astro/e2e/fixtures/view-transitions/public/two.css b/packages/astro/e2e/fixtures/view-transitions/public/two.css new file mode 100644 index 000000000000..7643138f8960 --- /dev/null +++ b/packages/astro/e2e/fixtures/view-transitions/public/two.css @@ -0,0 +1,3 @@ +#two { + font-size: 24px; +} diff --git a/packages/astro/e2e/fixtures/view-transitions/src/components/Layout.astro b/packages/astro/e2e/fixtures/view-transitions/src/components/Layout.astro index 38bc302e92e2..e4dc54015c4c 100644 --- a/packages/astro/e2e/fixtures/view-transitions/src/components/Layout.astro +++ b/packages/astro/e2e/fixtures/view-transitions/src/components/Layout.astro @@ -1,9 +1,16 @@ --- import { ViewTransitions } from 'astro:transitions'; + +interface Props { + link?: string; +} + +const { link } = Astro.props as Props; --- Testing + {link ? : ''} diff --git a/packages/astro/e2e/fixtures/view-transitions/src/pages/two.astro b/packages/astro/e2e/fixtures/view-transitions/src/pages/two.astro index b3cadcad7b71..ec5b699d8a0e 100644 --- a/packages/astro/e2e/fixtures/view-transitions/src/pages/two.astro +++ b/packages/astro/e2e/fixtures/view-transitions/src/pages/two.astro @@ -1,6 +1,6 @@ --- import Layout from '../components/Layout.astro'; --- - +

Page 2

diff --git a/packages/astro/e2e/view-transitions.test.js b/packages/astro/e2e/view-transitions.test.js index 5dbd845f4d88..f73b266757c7 100644 --- a/packages/astro/e2e/view-transitions.test.js +++ b/packages/astro/e2e/view-transitions.test.js @@ -126,4 +126,21 @@ test.describe('View Transitions', () => { p = page.locator('#one'); await expect(p, 'should have content').toHaveText('Page 1'); }); + + test('Stylesheets in the head are waited on', async ({ page, astro }) => { + page.addListener('console', data => { + console.log(data) + }) + + // Go to page 1 + await page.goto(astro.resolveUrl('/one')); + let p = page.locator('#one'); + await expect(p, 'should have content').toHaveText('Page 1'); + + // Go to page 2 + await page.click('#click-two'); + p = page.locator('#two'); + await expect(p, 'should have content').toHaveText('Page 2'); + await expect(p, 'imported CSS updated').toHaveCSS('font-size', '24px'); + }); });