mirror of
https://github.com/ThatGuySam/doesitarm.git
synced 2026-05-15 06:35:20 -07:00
fix(search): prevent pagefind filter hangs
Resolve the Pagefind browser loader in Vite dev and cap filter-only result hydration so broad filters render promptly instead of stalling behind thousands of fragment fetches.
This commit is contained in:
parent
e1da6eb880
commit
a1ae595717
2 changed files with 85 additions and 2 deletions
|
|
@ -366,6 +366,9 @@ export default {
|
||||||
...this.filterQueryList
|
...this.filterQueryList
|
||||||
].filter( Boolean ).join(' ')
|
].filter( Boolean ).join(' ')
|
||||||
},
|
},
|
||||||
|
pagefindResultLimit () {
|
||||||
|
return Math.max( this.initialList.length, 25 )
|
||||||
|
},
|
||||||
pagefindFilters () {
|
pagefindFilters () {
|
||||||
const filters = new SearchFilters()
|
const filters = new SearchFilters()
|
||||||
filters.setFromStringArray( this.filterQueryList )
|
filters.setFromStringArray( this.filterQueryList )
|
||||||
|
|
@ -518,10 +521,20 @@ export default {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const resultData = await Promise.all( ( pagefindQuery.results || [] ).map( async result => {
|
const limitedResults = ( pagefindQuery.results || [] ).slice( 0, this.pagefindResultLimit )
|
||||||
|
const settledResultData = await Promise.allSettled( limitedResults.map( async result => {
|
||||||
return await result.data()
|
return await result.data()
|
||||||
} ) )
|
} ) )
|
||||||
|
|
||||||
|
const resultData = settledResultData.flatMap( settledResult => {
|
||||||
|
if ( settledResult.status === 'fulfilled' ) {
|
||||||
|
return [ settledResult.value ]
|
||||||
|
}
|
||||||
|
|
||||||
|
console.warn('Failed to load Pagefind result data', settledResult.reason)
|
||||||
|
return []
|
||||||
|
} )
|
||||||
|
|
||||||
return resultData.map( data => {
|
return resultData.map( data => {
|
||||||
return mapPagefindDataToListing( data, {
|
return mapPagefindDataToListing( data, {
|
||||||
highlightTerms: this.inputTerms
|
highlightTerms: this.inputTerms
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,10 @@ import {
|
||||||
pagefindScriptURL
|
pagefindScriptURL
|
||||||
} from '~/helpers/pagefind/config.js'
|
} from '~/helpers/pagefind/config.js'
|
||||||
|
|
||||||
|
const pagefindGlobalKey = '__doesItArmPagefind'
|
||||||
|
const pagefindLoaderPromiseKey = '__doesItArmPagefindLoaderPromise'
|
||||||
|
const pagefindLoaderTimeoutMs = 10 * 1000
|
||||||
|
|
||||||
function escapeHtml ( text = '' ) {
|
function escapeHtml ( text = '' ) {
|
||||||
return text
|
return text
|
||||||
.replaceAll('&', '&')
|
.replaceAll('&', '&')
|
||||||
|
|
@ -70,6 +74,72 @@ export function mapPagefindDataToListing ( resultData, {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPagefindModuleSource () {
|
||||||
|
return [
|
||||||
|
`import * as pagefindModule from ${ JSON.stringify( pagefindScriptURL ) }`,
|
||||||
|
`globalThis.${ pagefindGlobalKey } = pagefindModule.default || pagefindModule`
|
||||||
|
].join('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
function waitForPagefindGlobal () {
|
||||||
|
return new Promise( ( resolve, reject ) => {
|
||||||
|
if ( globalThis[ pagefindGlobalKey ] ) {
|
||||||
|
resolve( globalThis[ pagefindGlobalKey ] )
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const startedAt = Date.now()
|
||||||
|
const timer = setInterval( () => {
|
||||||
|
if ( globalThis[ pagefindGlobalKey ] ) {
|
||||||
|
clearInterval( timer )
|
||||||
|
resolve( globalThis[ pagefindGlobalKey ] )
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( Date.now() - startedAt >= pagefindLoaderTimeoutMs ) {
|
||||||
|
clearInterval( timer )
|
||||||
|
reject( new Error(`Timed out waiting for Pagefind browser module at ${ pagefindScriptURL }`) )
|
||||||
|
}
|
||||||
|
}, 20 )
|
||||||
|
} )
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadPagefindBrowserModule () {
|
||||||
|
if ( typeof document === 'undefined' ) {
|
||||||
|
throw new Error('PagefindClient can only load in a browser document')
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( globalThis[ pagefindGlobalKey ] ) {
|
||||||
|
return globalThis[ pagefindGlobalKey ]
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !globalThis[ pagefindLoaderPromiseKey ] ) {
|
||||||
|
globalThis[ pagefindLoaderPromiseKey ] = new Promise( async ( resolve, reject ) => {
|
||||||
|
const script = document.createElement('script')
|
||||||
|
|
||||||
|
script.async = true
|
||||||
|
script.type = 'module'
|
||||||
|
script.textContent = getPagefindModuleSource()
|
||||||
|
|
||||||
|
script.onerror = () => {
|
||||||
|
delete globalThis[ pagefindLoaderPromiseKey ]
|
||||||
|
reject( new Error(`Failed to load Pagefind browser module from ${ pagefindScriptURL }`) )
|
||||||
|
}
|
||||||
|
|
||||||
|
document.head.append( script )
|
||||||
|
|
||||||
|
try {
|
||||||
|
resolve( await waitForPagefindGlobal() )
|
||||||
|
} catch ( err ) {
|
||||||
|
delete globalThis[ pagefindLoaderPromiseKey ]
|
||||||
|
reject( err )
|
||||||
|
}
|
||||||
|
} )
|
||||||
|
}
|
||||||
|
|
||||||
|
return await globalThis[ pagefindLoaderPromiseKey ]
|
||||||
|
}
|
||||||
|
|
||||||
export class PagefindClient {
|
export class PagefindClient {
|
||||||
constructor ( options = {} ) {
|
constructor ( options = {} ) {
|
||||||
this.bundlePath = options.bundlePath || pagefindBundleRelativeURL
|
this.bundlePath = options.bundlePath || pagefindBundleRelativeURL
|
||||||
|
|
@ -100,7 +170,7 @@ export class PagefindClient {
|
||||||
async loadPagefindScript () {
|
async loadPagefindScript () {
|
||||||
if ( this.pagefind ) return
|
if ( this.pagefind ) return
|
||||||
|
|
||||||
const pagefindModule = await import(/* @vite-ignore */ pagefindScriptURL)
|
const pagefindModule = await loadPagefindBrowserModule()
|
||||||
this.pagefind = pagefindModule.default || pagefindModule
|
this.pagefind = pagefindModule.default || pagefindModule
|
||||||
|
|
||||||
this.pagefind.options({
|
this.pagefind.options({
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue