Skip to content

Commit e44f6ac

Browse files
wtto00bluwyematipicosarah11918
authoredJan 3, 2024
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>
1 parent 2a8b9c5 commit e44f6ac

File tree

8 files changed

+135
-5
lines changed

8 files changed

+135
-5
lines changed
 

‎.changeset/bright-feet-flash.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'astro': minor
3+
---
4+
5+
Adds a `'load'` prefetch strategy to prefetch links on page load

‎.changeset/two-hats-arrive.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'astro': patch
3+
---
4+
5+
Ignores `3g` in slow connection detection. Only `2g` and `slow-2g` are considered slow connections.

‎packages/astro/e2e/fixtures/prefetch/src/pages/index.astro

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
<span>Scroll down to trigger viewport prefetch</span>
2121
<!-- Large empty space to test viewport -->
2222
<div style="height: 1000px;"></div>
23+
<a id="prefetch-load" href="/prefetch-load" data-astro-prefetch="load">load</a>
24+
<br>
2325
<a id="prefetch-viewport" href="/prefetch-viewport" data-astro-prefetch="viewport">viewport</a>
2426
<script>
2527
// @ts-nocheck
@@ -29,4 +31,4 @@
2931
})
3032
</script>
3133
</body>
32-
</html>
34+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<h1>Prefetch load</h1>

‎packages/astro/e2e/prefetch.test.js

+101
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ test.describe('Prefetch (default)', () => {
9595
await page.locator('#prefetch-manual').click();
9696
expect(reqUrls.filter((u) => u.includes('/prefetch-manual')).length).toEqual(1);
9797
});
98+
99+
test('data-astro-prefetch="load" should prefetch', async ({ page, astro }) => {
100+
await page.goto(astro.resolveUrl('/'));
101+
expect(reqUrls).toContainEqual('/prefetch-load');
102+
expect(page.locator('link[rel="prefetch"][href$="/prefetch-load"]')).toBeDefined();
103+
});
98104
});
99105

100106
test.describe("Prefetch (prefetchAll: true, defaultStrategy: 'tap')", () => {
@@ -182,4 +188,99 @@ test.describe("Prefetch (prefetchAll: true, defaultStrategy: 'tap')", () => {
182188
expect(reqUrls).toContainEqual('/prefetch-viewport');
183189
expect(page.locator('link[rel="prefetch"][href$="/prefetch-viewport"]')).toBeDefined();
184190
});
191+
192+
test('data-astro-prefetch="load" should prefetch', async ({ page, astro }) => {
193+
await page.goto(astro.resolveUrl('/'));
194+
expect(reqUrls).toContainEqual('/prefetch-load');
195+
expect(page.locator('link[rel="prefetch"][href$="/prefetch-load"]')).toBeDefined();
196+
});
197+
});
198+
199+
test.describe("Prefetch (prefetchAll: true, defaultStrategy: 'load')", () => {
200+
let devServer;
201+
/** @type {string[]} */
202+
const reqUrls = [];
203+
204+
test.beforeAll(async ({ astro }) => {
205+
devServer = await astro.startDevServer({
206+
prefetch: {
207+
prefetchAll: true,
208+
defaultStrategy: 'load',
209+
},
210+
});
211+
});
212+
213+
test.beforeEach(async ({ page }) => {
214+
page.on('request', (req) => {
215+
const urlObj = new URL(req.url());
216+
reqUrls.push(urlObj.pathname + urlObj.search);
217+
});
218+
});
219+
220+
test.afterEach(() => {
221+
reqUrls.length = 0;
222+
});
223+
224+
test.afterAll(async () => {
225+
await devServer.stop();
226+
});
227+
228+
test('Link without data-astro-prefetch should prefetch', async ({ page, astro }) => {
229+
await page.goto(astro.resolveUrl('/'));
230+
expect(reqUrls).toContainEqual('/prefetch-default');
231+
expect(page.locator('link[rel="prefetch"][href$="/prefetch-default"]')).toBeDefined();
232+
});
233+
234+
test('data-astro-prefetch="false" should not prefetch', async ({ page, astro }) => {
235+
await page.goto(astro.resolveUrl('/'));
236+
expect(reqUrls).not.toContainEqual('/prefetch-false');
237+
});
238+
239+
test('Link with search param should prefetch', async ({ page, astro }) => {
240+
await page.goto(astro.resolveUrl('/'));
241+
expect(reqUrls).not.toContainEqual('/?search-param=true');
242+
await Promise.all([
243+
page.waitForEvent('request'), // wait prefetch request
244+
page.locator('#prefetch-search-param').hover(),
245+
]);
246+
expect(reqUrls).toContainEqual('/?search-param=true');
247+
});
248+
249+
test('data-astro-prefetch="tap" should prefetch on tap', async ({ page, astro }) => {
250+
await page.goto(astro.resolveUrl('/'));
251+
expect(reqUrls).not.toContainEqual('/prefetch-tap');
252+
await Promise.all([
253+
page.waitForEvent('request'), // wait prefetch request
254+
page.locator('#prefetch-tap').click(),
255+
]);
256+
expect(reqUrls).toContainEqual('/prefetch-tap');
257+
});
258+
259+
test('data-astro-prefetch="hover" should prefetch on hover', async ({ page, astro }) => {
260+
await page.goto(astro.resolveUrl('/'));
261+
expect(reqUrls).not.toContainEqual('/prefetch-hover');
262+
await Promise.all([
263+
page.waitForEvent('request'), // wait prefetch request
264+
page.locator('#prefetch-hover').hover(),
265+
]);
266+
expect(reqUrls).toContainEqual('/prefetch-hover');
267+
});
268+
269+
test('data-astro-prefetch="viewport" should prefetch on viewport', async ({ page, astro }) => {
270+
await page.goto(astro.resolveUrl('/'));
271+
expect(reqUrls).not.toContainEqual('/prefetch-viewport');
272+
// Scroll down to show the element
273+
await Promise.all([
274+
page.waitForEvent('request'), // wait prefetch request
275+
page.locator('#prefetch-viewport').scrollIntoViewIfNeeded(),
276+
]);
277+
expect(reqUrls).toContainEqual('/prefetch-viewport');
278+
expect(page.locator('link[rel="prefetch"][href$="/prefetch-viewport"]')).toBeDefined();
279+
});
280+
281+
test('data-astro-prefetch="load" should prefetch', async ({ page, astro }) => {
282+
await page.goto(astro.resolveUrl('/'));
283+
expect(reqUrls).toContainEqual('/prefetch-load');
284+
expect(page.locator('link[rel="prefetch"][href$="/prefetch-load"]')).toBeDefined();
285+
});
185286
});

‎packages/astro/src/@types/astro.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -949,22 +949,23 @@ export interface AstroUserConfig {
949949
/**
950950
* @docs
951951
* @name prefetch.defaultStrategy
952-
* @type {'tap' | 'hover' | 'viewport'}
952+
* @type {'tap' | 'hover' | 'viewport' | 'load'}
953953
* @default `'hover'`
954954
* @description
955955
* The default prefetch strategy to use when the `data-astro-prefetch` attribute is set on a link with no value.
956956
*
957957
* - `'tap'`: Prefetch just before you click on the link.
958958
* - `'hover'`: Prefetch when you hover over or focus on the link. (default)
959959
* - `'viewport'`: Prefetch as the links enter the viewport.
960+
* - `'load'`: Prefetch the link without any restrictions.
960961
*
961962
* You can override this default value and select a different strategy for any individual link by setting a value on the attribute.
962963
*
963964
* ```html
964965
* <a href="/about" data-astro-prefetch="viewport">About</a>
965966
* ```
966967
*/
967-
defaultStrategy?: 'tap' | 'hover' | 'viewport';
968+
defaultStrategy?: 'tap' | 'hover' | 'viewport' | 'load';
968969
};
969970

970971
/**

‎packages/astro/src/core/config/schema.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ export const AstroConfigSchema = z.object({
185185
z.boolean(),
186186
z.object({
187187
prefetchAll: z.boolean().optional(),
188-
defaultStrategy: z.enum(['tap', 'hover', 'viewport']).optional(),
188+
defaultStrategy: z.enum(['tap', 'hover', 'viewport', 'load']).optional(),
189189
}),
190190
])
191191
.optional(),

‎packages/astro/src/prefetch/index.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export function init(defaultOpts?: InitOptions) {
4545
initTapStrategy();
4646
initHoverStrategy();
4747
initViewportStrategy();
48+
initLoadStrategy();
4849
}
4950

5051
/**
@@ -169,6 +170,20 @@ function createViewportIntersectionObserver() {
169170
});
170171
}
171172

173+
/**
174+
* Prefetch links with lower priority when page load
175+
*/
176+
function initLoadStrategy() {
177+
onPageLoad(() => {
178+
for (const anchor of document.getElementsByTagName('a')) {
179+
if (elMatchesStrategy(anchor, 'load')) {
180+
// Prefetch every link in this page
181+
prefetch(anchor.href, { with: 'link' });
182+
}
183+
}
184+
});
185+
}
186+
172187
export interface PrefetchOptions {
173188
/**
174189
* How the prefetch should prioritize the URL. (default `'link'`)
@@ -265,7 +280,7 @@ function isSlowConnection() {
265280
if ('connection' in navigator) {
266281
// Untyped Chrome-only feature: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/connection
267282
const conn = navigator.connection as any;
268-
return conn.saveData || /(2|3)g/.test(conn.effectiveType);
283+
return conn.saveData || /2g/.test(conn.effectiveType);
269284
}
270285
return false;
271286
}

0 commit comments

Comments
 (0)
Please sign in to comment.