From 76238dcec71095d8d4bee43527f06718e9aeb88d Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 13 Feb 2026 21:16:38 +0000 Subject: [PATCH] I've optimized the domain search using reactive debounce. I replaced `on:keyup` with a reactive statement to handle all input types and avoid non-input triggers. Additionally, I added `clearTimeout` to the form handler to prevent double requests, updated `vite.config.ts` polyfills to fix runtime errors, and formatted the code. Co-authored-by: Yeboster <23556525+Yeboster@users.noreply.github.com> --- .jules/bolt.md | 5 +++++ .jules/palette.md | 1 + src/routes/DomainSearch.svelte | 10 ++++++++-- vite.config.ts | 2 +- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 400b475..1575731 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -4,3 +4,8 @@ **Learning:** Asynchronous typeahead searches must implement a request ID mechanism. Without it, stale responses can overwrite newer ones, leading to correct search terms displaying incorrect results. **Action:** Always use a request ID or cancellation token pattern when implementing async search/filter operations. + +## 2025-02-13 - Reactive Statements for Input Debouncing + +**Learning:** Using `on:keyup` for search input debouncing is inefficient and incomplete; it triggers on non-character keys (e.g., Shift, Arrow keys) and misses alternative input methods like paste or drag-and-drop. Svelte's reactive statements (e.g., `$: debounce(value)`) provide a robust, comprehensive way to trigger side effects only when the value actually changes. +**Action:** Prefer reactive statements over key event listeners for debouncing bound inputs to improve performance and UX consistency. diff --git a/.jules/palette.md b/.jules/palette.md index 00f41cd..9cc85e1 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -1,3 +1,4 @@ ## 2024-10-24 - Accessible Icon Props and Loading Button State + **Learning:** Svelte wrapper components (like `Icon.svelte`) must spread `$$restProps` to allow passing accessibility attributes (e.g., `aria-label`) from parent components. Without this, icons remain inaccessible to screen readers. Also, persistent "Success" states on buttons can be confusing; auto-resetting them after a timeout improves clarity. **Action:** Always include `{...$$restProps}` in wrapper components and implement auto-reset logic for temporary success states in interactive elements. diff --git a/src/routes/DomainSearch.svelte b/src/routes/DomainSearch.svelte index 48c50fd..bb36c9c 100644 --- a/src/routes/DomainSearch.svelte +++ b/src/routes/DomainSearch.svelte @@ -22,7 +22,12 @@ $: invalid = domainName !== '' && !validator.validate(domainName, { raiseError: false }); $: nameSearchedLabel = nameSearched ? `${nameSearched}.${$metaNamesSdk.config.tld}` : null; - function debounce() { + // Reactive debounce: triggers on any value change (typing, paste, etc.) + // and avoids unnecessary triggers on non-input keys (unlike on:keyup). + $: debounce(domainName); + + function debounce(_name?: string) { + void _name; clearTimeout(debounceTimer); debounceTimer = setTimeout(async () => await search(), 400); } @@ -50,6 +55,8 @@ } async function submit() { + // Clear pending debounce timer to prevent double submission + clearTimeout(debounceTimer); await search(true); } @@ -60,7 +67,6 @@ class="domain-input" variant="outlined" bind:value={domainName} - on:keyup={() => debounce()} bind:invalid label="Domain name" withTrailingIcon diff --git a/vite.config.ts b/vite.config.ts index a9322d6..6094564 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -14,7 +14,7 @@ export default defineConfig({ }), sveltekit(), nodePolyfills({ - include: ['buffer', 'crypto', 'stream'] + include: ['buffer', 'crypto', 'stream', 'util'] }), tsconfigPaths() ],