Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/lazy-load-timeout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@geajs/core": patch
---

### @geajs/core (patch)

- **Lazy component load timeout**: `resolveLazy` now accepts a `timeout` parameter (default `10000`ms). Each load attempt is raced against the timeout, preventing the router from hanging indefinitely on a stalled network request. A timeout counts as a failure and triggers the existing retry logic with exponential backoff.
17 changes: 15 additions & 2 deletions packages/gea/src/lib/router/lazy.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
export async function resolveLazy(loader: () => Promise<any>, retries = 3, delay = 1000): Promise<any> {
export async function resolveLazy(
loader: () => Promise<any>,
retries = 3,
delay = 1000,
timeout = 10000,
): Promise<any> {
let lastError: unknown

for (let attempt = 0; attempt <= retries; attempt++) {
try {
const mod = await loader()
let timeoutId: ReturnType<typeof setTimeout>
const timeoutPromise = new Promise<never>((_, reject) => {
timeoutId = setTimeout(
() => reject(new Error(`[gea] Lazy component load timed out after ${timeout}ms`)),
timeout,
)
})
const mod = await Promise.race([loader(), timeoutPromise])
clearTimeout(timeoutId!)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
return mod && typeof mod === 'object' && 'default' in mod ? mod.default : mod
} catch (err) {
lastError = err
Expand Down