From c962f2d6a4947ff162c3f2c4767e615147e74057 Mon Sep 17 00:00:00 2001 From: Nathan Hammond Date: Thu, 10 Nov 2022 03:58:20 +0800 Subject: [PATCH] Adopt script rejection pattern for link onerror. (#42645) The HTML `` element's `onerror` function receives an Event-shaped object. The rejection here expects an `Error` shaped object. This PR 1:1 adopts the same pattern for `` `onerror` that `script` `onerror` uses. Attached you'll see an image that demonstrates that it _can_ end up in this state from turbo.build's Sentry logs: Screen Shot 2022-11-09 at 2 43 11 AM --- packages/next/client/route-loader.ts | 29 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/packages/next/client/route-loader.ts b/packages/next/client/route-loader.ts index 22eb2ae151e0159..9365e899acfc686 100644 --- a/packages/next/client/route-loader.ts +++ b/packages/next/client/route-loader.ts @@ -80,6 +80,16 @@ export interface RouteLoader { prefetch(route: string): Promise } +const ASSET_LOAD_ERROR = Symbol('ASSET_LOAD_ERROR') +// TODO: unexport +export function markAssetError(err: Error): Error { + return Object.defineProperty(err, ASSET_LOAD_ERROR, {}) +} + +export function isAssetError(err?: Error): boolean | undefined { + return err && ASSET_LOAD_ERROR in err +} + function hasPrefetch(link?: HTMLLinkElement): boolean { try { link = document.createElement('link') @@ -101,13 +111,13 @@ function prefetchViaDom( as: string, link?: HTMLLinkElement ): Promise { - return new Promise((res, rej) => { + return new Promise((resolve, reject) => { const selector = ` link[rel="prefetch"][href^="${href}"], link[rel="preload"][href^="${href}"], script[src^="${href}"]` if (document.querySelector(selector)) { - return res() + return resolve() } link = document.createElement('link') @@ -116,8 +126,9 @@ function prefetchViaDom( if (as) link!.as = as link!.rel = `prefetch` link!.crossOrigin = process.env.__NEXT_CROSS_ORIGIN! - link!.onload = res as any - link!.onerror = rej + link!.onload = resolve as any + link!.onerror = () => + reject(markAssetError(new Error(`Failed to prefetch: ${href}`))) // `href` should always be last: link!.href = href @@ -126,16 +137,6 @@ function prefetchViaDom( }) } -const ASSET_LOAD_ERROR = Symbol('ASSET_LOAD_ERROR') -// TODO: unexport -export function markAssetError(err: Error): Error { - return Object.defineProperty(err, ASSET_LOAD_ERROR, {}) -} - -export function isAssetError(err?: Error): boolean | undefined { - return err && ASSET_LOAD_ERROR in err -} - function appendScript( src: TrustedScriptURL | string, script?: HTMLScriptElement