fix(stage-tamagotchi): ERR_ABORT (-3) occurs when loading hash route window
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { withHashRoute } from './location'
|
||||
|
||||
vi.mock(import('@electron-toolkit/utils'), () => {
|
||||
return {
|
||||
is: {
|
||||
dev: true,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
describe('withHashRoute', () => {
|
||||
it('should use string url construct URL with hash route correctly', () => {
|
||||
const result = withHashRoute('http://localhost:5173', '/test/inner-test')
|
||||
expect(result).toEqual({ url: 'http://localhost:5173/#/test/inner-test' })
|
||||
})
|
||||
|
||||
it('should use object url construct URL with hash route correctly', () => {
|
||||
const result = withHashRoute({ url: 'http://localhost:5173' }, '/test/inner-test')
|
||||
expect(result).toEqual({ url: 'http://localhost:5173/#/test/inner-test' })
|
||||
})
|
||||
|
||||
it('should use file url construct URL with hash route correctly', () => {
|
||||
const result = withHashRoute({ url: 'file:////home/workspace/project/index.html' }, '/test/inner-test')
|
||||
expect(result).toEqual({ url: `file:////home/workspace/project/index.html#/test/inner-test` })
|
||||
})
|
||||
})
|
||||
@@ -34,23 +34,91 @@ export function baseUrl(parentOfIndexHtml: string, filename?: string) {
|
||||
}
|
||||
|
||||
export async function load(window: BrowserWindow, url: string | { url: string, options?: LoadURLOptions } | { file: string, options?: LoadFileOptions }) {
|
||||
if (typeof url === 'object' && 'url' in url) {
|
||||
return await window.loadURL(url.url, url.options)
|
||||
}
|
||||
if (typeof url === 'object' && 'file' in url) {
|
||||
return await window.loadFile(url.file, url.options)
|
||||
}
|
||||
try {
|
||||
if (typeof url === 'object' && 'url' in url) {
|
||||
return await window.loadURL(url.url, url.options)
|
||||
}
|
||||
if (typeof url === 'object' && 'file' in url) {
|
||||
return await window.loadFile(url.file, url.options)
|
||||
}
|
||||
|
||||
return await window.loadURL(url)
|
||||
return await window.loadURL(url)
|
||||
}
|
||||
catch (error) {
|
||||
if (!(error instanceof Error)) {
|
||||
throw error
|
||||
}
|
||||
|
||||
// Electron navigation error shape
|
||||
// https://github.com/electron/electron/blob/8d05285a1f39c759985b17c89a449e4a6b3960df/lib/browser/api/web-contents.ts#L354-L359
|
||||
if (!('code' in error) || !('errno' in error)) {
|
||||
throw error
|
||||
}
|
||||
if (error.code === 'ERR_ABORTED' && error.errno === -3) {
|
||||
if (typeof url === 'object' && 'url' in url) {
|
||||
const parsedURL = new URL(url.url)
|
||||
if (parsedURL.hash) {
|
||||
// When targeting /#/ hash route, Electron may throw
|
||||
//
|
||||
// ```
|
||||
// Error: ERR_ABORTED (-3) loading 'http://localhost:5173/#/notice/fade-on-hover?id=fade-on-hover'
|
||||
// ```
|
||||
//
|
||||
// and this will cause the `load(...)` promise to reject, while `#${hash content}` is in fact the correct URL expected by
|
||||
// electron, but from `new URL(...)` standard API, the output URL with hash will include at least one `/` before `#${hash content}`,
|
||||
// which causes the mismatch and thus the error.
|
||||
//
|
||||
// This is more likely a URL scheme standard mismatch between Electron and Node.js, and currently we can only catch and
|
||||
// ignore this error, since the URL with hash is actually loaded correctly in Electron, and the error is just a false alarm.
|
||||
//
|
||||
// Navigation started: {url: 'http://localhost:5173/#/notice/fade-on-hover?id=fade-on-hover', isSameDocument: false, isMainFrame: true, isInPlace: false}
|
||||
// Navigation started: {url: 'http://localhost:5173/#/notice/fade-on-hover?id=fade-on-hover', isSameDocument: false, isMainFrame: true, isInPlace: false}
|
||||
// Navigation started: {url: 'http://localhost:5173/#/notice/fade-on-hover?id=fade-on-hover', isSameDocument: false, isMainFrame: true, isInPlace: false}
|
||||
//
|
||||
// https://github.com/electron/electron/issues/17526
|
||||
// https://github.com/electron/electron/blob/8d05285a1f39c759985b17c89a449e4a6b3960df/lib/browser/api/web-contents.ts#L370-L387
|
||||
console.warn('Electron navigation error with hash route, ignoring:', error, 'url:', url.url)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
finally {
|
||||
window.webContents.removeAllListeners('did-start-navigation')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function to construct URL with hash route, which is commonly used in our app since we are using hash-based routing in renderer.
|
||||
*/
|
||||
export function withHashRoute(baseUrl: string | { url: string } | { file: string }, hashRoute: string) {
|
||||
if (typeof baseUrl === 'object' && 'url' in baseUrl) {
|
||||
return { url: `${baseUrl.url}/#${hashRoute}` } satisfies { url: string, options?: LoadURLOptions }
|
||||
// trim `/` suffix
|
||||
const baseURLinURL = new URL(baseUrl.url)
|
||||
|
||||
const pathname = baseURLinURL.pathname
|
||||
const trimmedPathname = pathname.endsWith('/') ? pathname.slice(0, -1) : pathname
|
||||
baseURLinURL.pathname = trimmedPathname
|
||||
|
||||
baseURLinURL.hash = hashRoute
|
||||
|
||||
return { url: baseURLinURL.toString() } satisfies { url: string, options?: LoadURLOptions }
|
||||
}
|
||||
if (typeof baseUrl === 'object' && 'file' in baseUrl) {
|
||||
return { file: `${baseUrl.file}`, options: { hash: hashRoute } } satisfies { file: string, options?: LoadFileOptions }
|
||||
}
|
||||
|
||||
return `${baseUrl}/#${hashRoute}`
|
||||
// trim `/` suffix
|
||||
const baseURLinURL = new URL(baseUrl)
|
||||
|
||||
const pathname = baseURLinURL.pathname
|
||||
const trimmedPathname = pathname.endsWith('/') ? pathname.slice(0, -1) : pathname
|
||||
baseURLinURL.pathname = trimmedPathname
|
||||
|
||||
baseURLinURL.hash = hashRoute
|
||||
|
||||
return { url: baseURLinURL.toString() } satisfies { url: string, options?: LoadURLOptions }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user