Skip to content

Commit

Permalink
Prevent script re-execution on page evaluation (#8033)
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewp authored Aug 11, 2023
1 parent 87d4b18 commit 405913c
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/lovely-impalas-pretend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Prevent script re-evaluation on page transition
23 changes: 23 additions & 0 deletions packages/astro/components/ViewTransitions.astro
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,16 @@ const { fallback = 'animate' } = Astro.props as Props;
return 'animate';
}

function markScriptsExec() {
for (const script of document.scripts) {
script.dataset.astroExec = '';
}
}

function runScripts() {
let wait = Promise.resolve();
for (const script of Array.from(document.scripts)) {
if(script.dataset.astroExec === '') continue;
const s = document.createElement('script');
s.innerHTML = script.innerHTML;
for (const attr of script.attributes) {
Expand All @@ -77,6 +84,7 @@ const { fallback = 'animate' } = Astro.props as Props;
}
s.setAttribute(attr.name, attr.value);
}
s.dataset.astroExec = '';
script.replaceWith(s);
}
return wait;
Expand All @@ -100,6 +108,18 @@ const { fallback = 'animate' } = Astro.props as Props;
const href = el.getAttribute('href');
return doc.head.querySelector(`link[rel=stylesheet][href="${href}"]`);
}
if(el.tagName === 'SCRIPT') {
let s1 = el as HTMLScriptElement;
for(const s2 of doc.scripts) {
if(
// Inline
(s1.textContent && s1.textContent === s2.textContent) ||
// External
(s1.type === s2.type && s1.src === s2.src)) {
return s2;
}
}
}
return null;
};

Expand Down Expand Up @@ -207,6 +227,7 @@ const { fallback = 'animate' } = Astro.props as Props;
} finally {
document.documentElement.removeAttribute('data-astro-transition');
await runScripts();
markScriptsExec();
onload();
}
}
Expand All @@ -225,6 +246,8 @@ const { fallback = 'animate' } = Astro.props as Props;
}

if (supportsViewTransitions || getFallback() !== 'none') {
markScriptsExec();

document.addEventListener('click', (ev) => {
let link = ev.target;
if (link instanceof Element && link.tagName !== 'A') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ const { link } = Astro.props as Props;
</style>
<ViewTransitions />
<DarkMode />
<meta name="script-executions" content="0">
<script is:inline defer>
{
// Increment a global to see if this is running more than once
globalThis.scriptExecutions = globalThis.scriptExecutions == null ? -1 : globalThis.scriptExecutions;
globalThis.scriptExecutions++;
const el = document.querySelector('[name="script-executions"]');
el.setAttribute('content', globalThis.scriptExecutions);
}
</script>
</head>
<body>
<header transition:animate="morph">
Expand Down
15 changes: 15 additions & 0 deletions packages/astro/e2e/view-transitions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,4 +279,19 @@ test.describe('View Transitions', () => {
// Count should remain
await expect(cnt).toHaveText('6');
});

test('Scripts are only executed once', async ({ page, astro }) => {
// Go to page 1
await page.goto(astro.resolveUrl('/one'));
const 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');

const meta = page.locator('[name="script-executions"]');
await expect(meta).toHaveAttribute('content', '0');
});
});

0 comments on commit 405913c

Please sign in to comment.