mirror of
https://github.com/withastro/astro.git
synced 2025-02-17 22:44:24 -05:00
enhance(prefetch): Adds a 'load'
prefetch strategy, and ignores 3g
in slow connection detection (#9513)
* [enhance:prefetch] add global ignoreSlowConnection and add none to defaultStrategy enum * changeset * change defaultStrategy enum 'none' to 'all', and fix e2e test * test:e2e prefetch * update changeset * rename defaultStrategy.all to defaultStrategy.load * fix: remove global ignoreSlowConnection config and ignore 3g in slow connection detection * fix: Revert variable name changes * Split changeset --------- Co-authored-by: bluwy <bjornlu.dev@gmail.com> Co-authored-by: Emanuele Stoppa <my.burning@gmail.com> Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
This commit is contained in:
parent
2a8b9c56b9
commit
e44f6acf99
8 changed files with 135 additions and 5 deletions
5
.changeset/bright-feet-flash.md
Normal file
5
.changeset/bright-feet-flash.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': minor
|
||||
---
|
||||
|
||||
Adds a `'load'` prefetch strategy to prefetch links on page load
|
5
.changeset/two-hats-arrive.md
Normal file
5
.changeset/two-hats-arrive.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Ignores `3g` in slow connection detection. Only `2g` and `slow-2g` are considered slow connections.
|
|
@ -20,6 +20,8 @@
|
|||
<span>Scroll down to trigger viewport prefetch</span>
|
||||
<!-- Large empty space to test viewport -->
|
||||
<div style="height: 1000px;"></div>
|
||||
<a id="prefetch-load" href="/prefetch-load" data-astro-prefetch="load">load</a>
|
||||
<br>
|
||||
<a id="prefetch-viewport" href="/prefetch-viewport" data-astro-prefetch="viewport">viewport</a>
|
||||
<script>
|
||||
// @ts-nocheck
|
||||
|
@ -29,4 +31,4 @@
|
|||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<h1>Prefetch load</h1>
|
|
@ -95,6 +95,12 @@ test.describe('Prefetch (default)', () => {
|
|||
await page.locator('#prefetch-manual').click();
|
||||
expect(reqUrls.filter((u) => u.includes('/prefetch-manual')).length).toEqual(1);
|
||||
});
|
||||
|
||||
test('data-astro-prefetch="load" should prefetch', async ({ page, astro }) => {
|
||||
await page.goto(astro.resolveUrl('/'));
|
||||
expect(reqUrls).toContainEqual('/prefetch-load');
|
||||
expect(page.locator('link[rel="prefetch"][href$="/prefetch-load"]')).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Prefetch (prefetchAll: true, defaultStrategy: 'tap')", () => {
|
||||
|
@ -182,4 +188,99 @@ test.describe("Prefetch (prefetchAll: true, defaultStrategy: 'tap')", () => {
|
|||
expect(reqUrls).toContainEqual('/prefetch-viewport');
|
||||
expect(page.locator('link[rel="prefetch"][href$="/prefetch-viewport"]')).toBeDefined();
|
||||
});
|
||||
|
||||
test('data-astro-prefetch="load" should prefetch', async ({ page, astro }) => {
|
||||
await page.goto(astro.resolveUrl('/'));
|
||||
expect(reqUrls).toContainEqual('/prefetch-load');
|
||||
expect(page.locator('link[rel="prefetch"][href$="/prefetch-load"]')).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Prefetch (prefetchAll: true, defaultStrategy: 'load')", () => {
|
||||
let devServer;
|
||||
/** @type {string[]} */
|
||||
const reqUrls = [];
|
||||
|
||||
test.beforeAll(async ({ astro }) => {
|
||||
devServer = await astro.startDevServer({
|
||||
prefetch: {
|
||||
prefetchAll: true,
|
||||
defaultStrategy: 'load',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
page.on('request', (req) => {
|
||||
const urlObj = new URL(req.url());
|
||||
reqUrls.push(urlObj.pathname + urlObj.search);
|
||||
});
|
||||
});
|
||||
|
||||
test.afterEach(() => {
|
||||
reqUrls.length = 0;
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await devServer.stop();
|
||||
});
|
||||
|
||||
test('Link without data-astro-prefetch should prefetch', async ({ page, astro }) => {
|
||||
await page.goto(astro.resolveUrl('/'));
|
||||
expect(reqUrls).toContainEqual('/prefetch-default');
|
||||
expect(page.locator('link[rel="prefetch"][href$="/prefetch-default"]')).toBeDefined();
|
||||
});
|
||||
|
||||
test('data-astro-prefetch="false" should not prefetch', async ({ page, astro }) => {
|
||||
await page.goto(astro.resolveUrl('/'));
|
||||
expect(reqUrls).not.toContainEqual('/prefetch-false');
|
||||
});
|
||||
|
||||
test('Link with search param should prefetch', async ({ page, astro }) => {
|
||||
await page.goto(astro.resolveUrl('/'));
|
||||
expect(reqUrls).not.toContainEqual('/?search-param=true');
|
||||
await Promise.all([
|
||||
page.waitForEvent('request'), // wait prefetch request
|
||||
page.locator('#prefetch-search-param').hover(),
|
||||
]);
|
||||
expect(reqUrls).toContainEqual('/?search-param=true');
|
||||
});
|
||||
|
||||
test('data-astro-prefetch="tap" should prefetch on tap', async ({ page, astro }) => {
|
||||
await page.goto(astro.resolveUrl('/'));
|
||||
expect(reqUrls).not.toContainEqual('/prefetch-tap');
|
||||
await Promise.all([
|
||||
page.waitForEvent('request'), // wait prefetch request
|
||||
page.locator('#prefetch-tap').click(),
|
||||
]);
|
||||
expect(reqUrls).toContainEqual('/prefetch-tap');
|
||||
});
|
||||
|
||||
test('data-astro-prefetch="hover" should prefetch on hover', async ({ page, astro }) => {
|
||||
await page.goto(astro.resolveUrl('/'));
|
||||
expect(reqUrls).not.toContainEqual('/prefetch-hover');
|
||||
await Promise.all([
|
||||
page.waitForEvent('request'), // wait prefetch request
|
||||
page.locator('#prefetch-hover').hover(),
|
||||
]);
|
||||
expect(reqUrls).toContainEqual('/prefetch-hover');
|
||||
});
|
||||
|
||||
test('data-astro-prefetch="viewport" should prefetch on viewport', async ({ page, astro }) => {
|
||||
await page.goto(astro.resolveUrl('/'));
|
||||
expect(reqUrls).not.toContainEqual('/prefetch-viewport');
|
||||
// Scroll down to show the element
|
||||
await Promise.all([
|
||||
page.waitForEvent('request'), // wait prefetch request
|
||||
page.locator('#prefetch-viewport').scrollIntoViewIfNeeded(),
|
||||
]);
|
||||
expect(reqUrls).toContainEqual('/prefetch-viewport');
|
||||
expect(page.locator('link[rel="prefetch"][href$="/prefetch-viewport"]')).toBeDefined();
|
||||
});
|
||||
|
||||
test('data-astro-prefetch="load" should prefetch', async ({ page, astro }) => {
|
||||
await page.goto(astro.resolveUrl('/'));
|
||||
expect(reqUrls).toContainEqual('/prefetch-load');
|
||||
expect(page.locator('link[rel="prefetch"][href$="/prefetch-load"]')).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -949,7 +949,7 @@ export interface AstroUserConfig {
|
|||
/**
|
||||
* @docs
|
||||
* @name prefetch.defaultStrategy
|
||||
* @type {'tap' | 'hover' | 'viewport'}
|
||||
* @type {'tap' | 'hover' | 'viewport' | 'load'}
|
||||
* @default `'hover'`
|
||||
* @description
|
||||
* The default prefetch strategy to use when the `data-astro-prefetch` attribute is set on a link with no value.
|
||||
|
@ -957,6 +957,7 @@ export interface AstroUserConfig {
|
|||
* - `'tap'`: Prefetch just before you click on the link.
|
||||
* - `'hover'`: Prefetch when you hover over or focus on the link. (default)
|
||||
* - `'viewport'`: Prefetch as the links enter the viewport.
|
||||
* - `'load'`: Prefetch the link without any restrictions.
|
||||
*
|
||||
* You can override this default value and select a different strategy for any individual link by setting a value on the attribute.
|
||||
*
|
||||
|
@ -964,7 +965,7 @@ export interface AstroUserConfig {
|
|||
* <a href="/about" data-astro-prefetch="viewport">About</a>
|
||||
* ```
|
||||
*/
|
||||
defaultStrategy?: 'tap' | 'hover' | 'viewport';
|
||||
defaultStrategy?: 'tap' | 'hover' | 'viewport' | 'load';
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -185,7 +185,7 @@ export const AstroConfigSchema = z.object({
|
|||
z.boolean(),
|
||||
z.object({
|
||||
prefetchAll: z.boolean().optional(),
|
||||
defaultStrategy: z.enum(['tap', 'hover', 'viewport']).optional(),
|
||||
defaultStrategy: z.enum(['tap', 'hover', 'viewport', 'load']).optional(),
|
||||
}),
|
||||
])
|
||||
.optional(),
|
||||
|
|
|
@ -45,6 +45,7 @@ export function init(defaultOpts?: InitOptions) {
|
|||
initTapStrategy();
|
||||
initHoverStrategy();
|
||||
initViewportStrategy();
|
||||
initLoadStrategy();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -169,6 +170,20 @@ function createViewportIntersectionObserver() {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefetch links with lower priority when page load
|
||||
*/
|
||||
function initLoadStrategy() {
|
||||
onPageLoad(() => {
|
||||
for (const anchor of document.getElementsByTagName('a')) {
|
||||
if (elMatchesStrategy(anchor, 'load')) {
|
||||
// Prefetch every link in this page
|
||||
prefetch(anchor.href, { with: 'link' });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export interface PrefetchOptions {
|
||||
/**
|
||||
* How the prefetch should prioritize the URL. (default `'link'`)
|
||||
|
@ -265,7 +280,7 @@ function isSlowConnection() {
|
|||
if ('connection' in navigator) {
|
||||
// Untyped Chrome-only feature: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/connection
|
||||
const conn = navigator.connection as any;
|
||||
return conn.saveData || /(2|3)g/.test(conn.effectiveType);
|
||||
return conn.saveData || /2g/.test(conn.effectiveType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue