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

Prevent rerunning scripts already ran in router #12985

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/forty-houses-taste.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Prevent re-executing scripts in client router
16 changes: 16 additions & 0 deletions packages/astro/e2e/fixtures/view-transitions/src/pages/eight.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
import Layout from '../components/Layout.astro';
import { ClientRouter } from 'astro:transitions';
Astro.response.headers.set('Content-Type', 'text/html ; charset=utf-8');
---
<html>
<head>
<ClientRouter handleForms />
</head>
<body>
<p id="eight">Page 8</p>

<a id="click-one" href="/one">go to 1</a>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Layout from '../components/Layout.astro';
<a id="click-two" href="/two">go to 2</a>
<a id="click-three" href="/three">go to 3</a>
<a id="click-seven" href="/seven">go to 7</a>
<a id="click-eight" href="/eight">go to 8</a>
<a id="click-longpage" href="/long-page">go to long page</a>
<a id="click-self" href="">go to top</a>
<a id="click-redirect-two" href="/redirect-two">go to redirect 2</a>
Expand Down
17 changes: 16 additions & 1 deletion packages/astro/e2e/view-transitions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -647,14 +647,29 @@ test.describe('View Transitions', () => {
test('Scripts are only executed once', async ({ page, astro }) => {
// Go to page 1
await page.goto(astro.resolveUrl('/one'));
const p = page.locator('#one');
let p = page.locator('#one');
await expect(p, 'should have content').toHaveText('Page 1');

// go to page 2
await page.click('#click-two');
const article = page.locator('#twoarticle');
await expect(article, 'should have script content').toHaveText('works');

// Go back to page 1
await page.goBack();
p = page.locator('#one');
await expect(p, 'should have content').toHaveText('Page 1');

// Go to page 8
await page.click('#click-eight');
const article8 = page.locator('#eight');
await expect(article8, 'should have content').toHaveText('Page 8');

// Go back to page 1
await page.goBack();
p = page.locator('#one');
await expect(p, 'should have content').toHaveText('Page 1');

const meta = page.locator('[name="script-executions"]');
await expect(meta).toHaveAttribute('content', '0');
});
Expand Down
3 changes: 2 additions & 1 deletion packages/astro/src/transitions/router.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { TransitionBeforePreparationEvent } from './events.js';
import { TRANSITION_AFTER_SWAP, doPreparation, doSwap } from './events.js';
import type { Direction, Fallback, Options } from './types.js';
import { detectScriptExecuted } from './swap-functions.js';

type State = {
index: number;
Expand Down Expand Up @@ -644,7 +645,7 @@ if (inBrowser) {
}
}
for (const script of document.getElementsByTagName('script')) {
script.dataset.astroExec = '';
detectScriptExecuted(script);
}
}

Expand Down
34 changes: 19 additions & 15 deletions packages/astro/src/transitions/swap-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,29 @@ export type SavedFocus = {

const PERSIST_ATTR = 'data-astro-transition-persist';

const scriptsAlreadyRan = new Set<string>();
export function detectScriptExecuted(script: HTMLScriptElement) {
const key = script.src ? new URL(script.src, location.href).href : script.textContent!;
if (scriptsAlreadyRan.has(key)) return true;
scriptsAlreadyRan.add(key);
return false;
}

/*
* Mark new scripts that should not execute
*/
export function deselectScripts(doc: Document) {
for (const s1 of document.scripts) {
for (const s2 of doc.scripts) {
if (
// Check if the script should be rerun regardless of it being the same
!s2.hasAttribute('data-astro-rerun') &&
// Inline
((!s1.src && s1.textContent === s2.textContent) ||
// External
(s1.src && s1.type === s2.type && s1.src === s2.src))
) {
// the old script is in the new document and doesn't have the rerun attribute
// we mark it as executed to prevent re-execution
s2.dataset.astroExec = '';
break;
}
for (const s2 of doc.scripts) {
if (
// Check if the script should be rerun regardless of it being the same
!s2.hasAttribute('data-astro-rerun') &&
// Check if the script has already been executed
detectScriptExecuted(s2)
) {
// the old script is in the new document and doesn't have the rerun attribute
// we mark it as executed to prevent re-execution
s2.dataset.astroExec = '';
break;
}
}
}
Expand Down
Loading