@@ -8,12 +8,15 @@ import {
88 loadWordMap ,
99 search ,
1010 LRUCache ,
11+ createSearchWorker ,
12+ supportsWorkers ,
1113 type AdvancedSearchOptions ,
1214 type MatchType ,
1315 type MorphologyAya ,
1416 type QuranText ,
1517 type ScoredVerse ,
1618 type SearchResponse ,
19+ type SearchWorkerClient ,
1720 type WordMap ,
1821} from 'quran-search-engine' ;
1922
@@ -375,21 +378,37 @@ export class AppComponent implements OnInit, OnDestroy {
375378
376379 private debounceHandle : number | null = null ;
377380 private searchCache = new LRUCache < string , SearchResponse < QuranText > > ( 50 ) ;
381+ private workerClient : SearchWorkerClient | null = null ;
378382
379383 async ngOnInit ( ) : Promise < void > {
380384 this . loadState = 'loading' ;
381385 this . errorMessage = '' ;
382386
383387 try {
384- const [ quranData , morphologyMap , wordMap ] = await Promise . all ( [
385- loadQuranData ( ) ,
386- loadMorphology ( ) ,
387- loadWordMap ( ) ,
388- ] ) ;
389-
390- this . quranData = quranData ;
391- this . morphologyMap = morphologyMap ;
392- this . wordMap = wordMap ;
388+ if ( supportsWorkers ( ) ) {
389+ try {
390+ const client = createSearchWorker ( {
391+ workerUrl : new URL ( 'quran-search-engine/worker' , import . meta. url ) ,
392+ } ) ;
393+ await client . initData ( ) ;
394+ this . workerClient = client ;
395+ } catch ( err ) {
396+ console . warn ( 'Web Worker init failed, falling back to main thread:' , err ) ;
397+ }
398+ }
399+
400+ if ( ! this . workerClient ) {
401+ const [ quranData , morphologyMap , wordMap ] = await Promise . all ( [
402+ loadQuranData ( ) ,
403+ loadMorphology ( ) ,
404+ loadWordMap ( ) ,
405+ ] ) ;
406+
407+ this . quranData = quranData ;
408+ this . morphologyMap = morphologyMap ;
409+ this . wordMap = wordMap ;
410+ }
411+
393412 this . loadState = 'ready' ;
394413 } catch ( err : unknown ) {
395414 this . loadState = 'error' ;
@@ -401,6 +420,7 @@ export class AppComponent implements OnInit, OnDestroy {
401420 if ( this . debounceHandle !== null ) {
402421 window . clearTimeout ( this . debounceHandle ) ;
403422 }
423+ this . workerClient ?. terminate ( ) ;
404424 }
405425
406426 onQueryChange ( ) : void {
@@ -414,8 +434,6 @@ export class AppComponent implements OnInit, OnDestroy {
414434 }
415435
416436 runSearch ( resetPage : boolean ) : void {
417- if ( ! this . quranData || ! this . morphologyMap || ! this . wordMap ) return ;
418-
419437 const trimmed = this . query . trim ( ) ;
420438 if ( ! trimmed ) {
421439 this . response = null ;
@@ -429,22 +447,34 @@ export class AppComponent implements OnInit, OnDestroy {
429447 lemma : this . options . lemma ,
430448 root : this . options . root ,
431449 fuzzy : this . options . fuzzy ,
432- //+
433450 suraId : this . options . suraId ,
434451 juzId : this . options . juzId ,
435452 suraName : this . options . suraName ,
436453 semantic : this . options . semantic ,
437454 } ;
438455
456+ if ( this . workerClient ) {
457+ this . workerClient
458+ . runSearch ( trimmed , searchOptions , { page : this . page , limit : this . limit } )
459+ . then ( ( res ) => {
460+ this . response = res ;
461+ this . rebuildHighlightCache ( ) ;
462+ } )
463+ . catch ( ( err ) => console . error ( 'Worker search error:' , err ) ) ;
464+ return ;
465+ }
466+
467+ if ( ! this . quranData || ! this . morphologyMap || ! this . wordMap ) return ;
468+
439469 this . response = search (
440470 trimmed ,
441471 this . quranData ,
442472 this . morphologyMap ,
443473 this . wordMap ,
444474 searchOptions ,
445475 { page : this . page , limit : this . limit } ,
446- undefined , // preComputedFuseIndex
447- this . searchCache , // LRU cache — identical queries return cached results
476+ undefined ,
477+ this . searchCache ,
448478 ) ;
449479
450480 this . rebuildHighlightCache ( ) ;
0 commit comments