mirror of
https://github.com/withastro/astro.git
synced 2025-01-27 22:19:04 -05:00
feat: support setting timeout for client:idle
(#11743)
* feat: support setting timeout for `client:idle` * tst: add client:idle timeout e2e test * Update .changeset/clever-emus-roll.md Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> * Update .changeset/clever-emus-roll.md Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> * nit: we wait for times, not values! --------- Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
This commit is contained in:
parent
5af8b4f1cb
commit
cce0894534
9 changed files with 128 additions and 4 deletions
11
.changeset/clever-emus-roll.md
Normal file
11
.changeset/clever-emus-roll.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
'astro': minor
|
||||
---
|
||||
|
||||
Adds a new, optional property `timeout` for the `client:idle` directive.
|
||||
|
||||
This value allows you to specify a maximum time to wait, in milliseconds, before hydrating a UI framework component, even if the page is not yet done with its initial load. This means you can delay hydration for lower-priority UI elements with more control to ensure your element is interactive within a specified time frame.
|
||||
|
||||
```astro
|
||||
<ShowHideButton client:idle={{timeout: 500}} />
|
||||
```
|
33
packages/astro/e2e/client-idle-timeout.test.js
Normal file
33
packages/astro/e2e/client-idle-timeout.test.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { expect } from '@playwright/test';
|
||||
import { testFactory, waitForHydrate } from './test-utils.js';
|
||||
|
||||
const test = testFactory({ root: './fixtures/client-idle-timeout/' });
|
||||
|
||||
let devServer;
|
||||
|
||||
test.beforeAll(async ({ astro }) => {
|
||||
devServer = await astro.startDevServer();
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await devServer.stop();
|
||||
});
|
||||
|
||||
test.describe('Client idle timeout', () => {
|
||||
test('React counter', async ({ astro, page }) => {
|
||||
await page.goto(astro.resolveUrl('/'));
|
||||
|
||||
const counter = page.locator('#react-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = counter.locator('pre');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
await waitForHydrate(page, counter);
|
||||
|
||||
const inc = counter.locator('.increment');
|
||||
await inc.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,9 @@
|
|||
import react from '@astrojs/react';
|
||||
import { defineConfig } from 'astro/config';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
integrations: [
|
||||
react(),
|
||||
],
|
||||
});
|
13
packages/astro/e2e/fixtures/client-idle-timeout/package.json
Normal file
13
packages/astro/e2e/fixtures/client-idle-timeout/package.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "@e2e/client-idle-timeout",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@astrojs/react": "workspace:*",
|
||||
"astro": "workspace:*"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import React, { useState } from 'react';
|
||||
|
||||
export default function Counter({ children, count: initialCount = 0, id }) {
|
||||
const [count, setCount] = useState(initialCount);
|
||||
const add = () => setCount((i) => i + 1);
|
||||
const subtract = () => setCount((i) => i - 1);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div id={id} className="counter">
|
||||
<button className="decrement" onClick={subtract}>-</button>
|
||||
<pre>{count}</pre>
|
||||
<button className="increment" onClick={add}>+</button>
|
||||
</div>
|
||||
<div className="counter-message">{children}</div>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
import Counter from '../components/Counter.jsx';
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<Counter id="react-counter" client:idle={{timeout: 200}}></Counter>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
|
@ -91,7 +91,7 @@ export type {
|
|||
|
||||
export interface AstroBuiltinProps {
|
||||
'client:load'?: boolean;
|
||||
'client:idle'?: boolean;
|
||||
'client:idle'?: IdleRequestOptions | boolean;
|
||||
'client:media'?: string;
|
||||
'client:visible'?: ClientVisibleOptions | boolean;
|
||||
'client:only'?: boolean | string;
|
||||
|
|
|
@ -1,14 +1,22 @@
|
|||
import type { ClientDirective } from '../../@types/astro.js';
|
||||
|
||||
const idleDirective: ClientDirective = (load) => {
|
||||
const idleDirective: ClientDirective = (load, options) => {
|
||||
const cb = async () => {
|
||||
const hydrate = await load();
|
||||
await hydrate();
|
||||
};
|
||||
|
||||
const rawOptions =
|
||||
typeof options.value === 'object' ? (options.value as IdleRequestOptions) : undefined;
|
||||
|
||||
const idleOptions: IdleRequestOptions = {
|
||||
timeout: rawOptions?.timeout,
|
||||
};
|
||||
|
||||
if ('requestIdleCallback' in window) {
|
||||
(window as any).requestIdleCallback(cb);
|
||||
(window as any).requestIdleCallback(cb, idleOptions);
|
||||
} else {
|
||||
setTimeout(cb, 200);
|
||||
setTimeout(cb, idleOptions.timeout || 200);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
|
@ -1004,6 +1004,22 @@ importers:
|
|||
specifier: ^3.4.38
|
||||
version: 3.4.38(typescript@5.5.4)
|
||||
|
||||
packages/astro/e2e/fixtures/client-idle-timeout:
|
||||
dependencies:
|
||||
react:
|
||||
specifier: ^18.3.1
|
||||
version: 18.3.1
|
||||
react-dom:
|
||||
specifier: ^18.3.1
|
||||
version: 18.3.1(react@18.3.1)
|
||||
devDependencies:
|
||||
'@astrojs/react':
|
||||
specifier: workspace:*
|
||||
version: link:../../../../integrations/react
|
||||
astro:
|
||||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
|
||||
packages/astro/e2e/fixtures/client-only:
|
||||
dependencies:
|
||||
preact:
|
||||
|
|
Loading…
Add table
Reference in a new issue