diff --git a/.changeset/khaki-ducks-give.md b/.changeset/khaki-ducks-give.md new file mode 100644 index 000000000000..3f759891b824 --- /dev/null +++ b/.changeset/khaki-ducks-give.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixes an edge case with view transitions where some spec-compliant `Content-Type` headers would cause a valid HTML response to be ignored. diff --git a/packages/astro/e2e/fixtures/view-transitions/src/pages/one.astro b/packages/astro/e2e/fixtures/view-transitions/src/pages/one.astro index d05973036e14..b78565c86db9 100644 --- a/packages/astro/e2e/fixtures/view-transitions/src/pages/one.astro +++ b/packages/astro/e2e/fixtures/view-transitions/src/pages/one.astro @@ -6,6 +6,7 @@ import Layout from '../components/Layout.astro'; test go to 2 go to 3 + go to 7 go to long page go to top go to redirect 2 diff --git a/packages/astro/e2e/fixtures/view-transitions/src/pages/seven.astro b/packages/astro/e2e/fixtures/view-transitions/src/pages/seven.astro new file mode 100644 index 000000000000..625c4a8df661 --- /dev/null +++ b/packages/astro/e2e/fixtures/view-transitions/src/pages/seven.astro @@ -0,0 +1,10 @@ +--- +import Layout from '../components/Layout.astro'; + +Astro.response.headers.set('Content-Type', 'text/html ; charset=utf-8'); +--- + +

Page 7

+ +
test content
+
diff --git a/packages/astro/e2e/view-transitions.test.js b/packages/astro/e2e/view-transitions.test.js index 222c9dfdf2aa..a3c88b8b039b 100644 --- a/packages/astro/e2e/view-transitions.test.js +++ b/packages/astro/e2e/view-transitions.test.js @@ -97,6 +97,25 @@ test.describe('View Transitions', () => { expect(loads.length, 'There should only be 1 page load').toEqual(1); }); + test('Clicking on a link to a page with non-recommended headers', async ({page, astro}) => { + const loads = []; + page.addListener('load', (p) => { + loads.push(p.title()); + }); + + // Go to page 4 + await page.goto(astro.resolveUrl('/one')); + let p = page.locator('#one'); + await expect(p, 'should have content').toHaveText('Page 1'); + + // Go to page 1 + await page.click('#click-seven'); + p = page.locator('#seven'); + await expect(p, 'should have content').toHaveText('Page 7'); + + expect(loads.length, 'There should only be 1 page load').toEqual(1); + }); + test('Moving to a page without ViewTransitions triggers a full page navigation', async ({ page, astro, diff --git a/packages/astro/src/transitions/router.ts b/packages/astro/src/transitions/router.ts index e710c2e1b2e8..6588fd71f960 100644 --- a/packages/astro/src/transitions/router.ts +++ b/packages/astro/src/transitions/router.ts @@ -119,8 +119,9 @@ async function fetchHTML( ): Promise { try { const res = await fetch(href, init); + const contentType = res.headers.get('content-type') ?? ''; // drop potential charset (+ other name/value pairs) as parser needs the mediaType - const mediaType = res.headers.get('content-type')?.replace(/;.*$/, ''); + const mediaType = contentType.split(';', 1)[0].trim(); // the DOMParser can handle two types of HTML if (mediaType !== 'text/html' && mediaType !== 'application/xhtml+xml') { // everything else (e.g. audio/mp3) will be handled by the browser but not by us