diff --git a/packages/next/client/route-loader.ts b/packages/next/client/route-loader.ts index 3603b6851798b..c57eece8ac754 100644 --- a/packages/next/client/route-loader.ts +++ b/packages/next/client/route-loader.ts @@ -99,7 +99,11 @@ function prefetchViaDom( link?: HTMLLinkElement ): Promise { return new Promise((res, rej) => { - if (document.querySelector(`link[rel="prefetch"][href^="${href}"]`)) { + const selector = ` + link[rel="prefetch"][href^="${href}"], + link[rel="preload"][href^="${href}"], + script[src^="${href}"]` + if (document.querySelector(selector)) { return res() } diff --git a/test/integration/preload-viewport/test/index.test.js b/test/integration/preload-viewport/test/index.test.js index f08e7138ea840..79d1f00dec570 100644 --- a/test/integration/preload-viewport/test/index.test.js +++ b/test/integration/preload-viewport/test/index.test.js @@ -339,6 +339,29 @@ describe('Prefetching Links in viewport', () => { expect(found).toBe(false) }) + it('should not prefetch already loaded scripts', async () => { + const browser = await webdriver(appPort, '/') + + const scriptSrcs = await browser.eval(`(function() { + return Array.from(document.querySelectorAll('script')) + .map(function(el) { + return el.src && new URL(el.src).pathname + }).filter(Boolean) + })()`) + + await browser.eval('next.router.prefetch("/")') + + const linkHrefs = await browser.eval(`(function() { + return Array.from(document.querySelectorAll('link')) + .map(function(el) { + return el.href && new URL(el.href).pathname + }).filter(Boolean) + })()`) + + console.log({ linkHrefs, scriptSrcs }) + expect(linkHrefs.some((href) => scriptSrcs.includes(href))).toBe(false) + }) + it('should not duplicate prefetches', async () => { const browser = await webdriver(appPort, '/multi-prefetch')