@@ -10,6 +10,7 @@ import {Injector} from '../di';
1010import { internalImportProvidersFrom } from '../di/provider_collection' ;
1111import { RuntimeError , RuntimeErrorCode } from '../errors' ;
1212import { cleanupDeferBlock } from '../hydration/cleanup' ;
13+ import { BlockSummary , ElementTrigger , NUM_ROOT_NODES } from '../hydration/interfaces' ;
1314import {
1415 assertSsrIdDefined ,
1516 getParentBlockHydrationQueue ,
@@ -30,6 +31,8 @@ import {
3031 invokeTriggerCleanupFns ,
3132 storeTriggerCleanupFn ,
3233} from './cleanup' ;
34+ import { onViewport } from './dom_triggers' ;
35+ import { onIdle } from './idle_scheduler' ;
3336import {
3437 DeferBlockBehavior ,
3538 DeferBlockState ,
@@ -51,6 +54,7 @@ import {
5154 renderDeferStateAfterResourceLoading ,
5255 renderPlaceholder ,
5356} from './rendering' ;
57+ import { onTimer } from './timer_scheduler' ;
5458import {
5559 addDepsToRegistry ,
5660 assertDeferredDependenciesLoaded ,
@@ -494,3 +498,93 @@ export function getHydrateTriggers(
494498export function getPrefetchTriggers ( tDetails : TDeferBlockDetails ) : Set < DeferBlockTrigger > {
495499 return ( tDetails . prefetchTriggers ??= new Set ( ) ) ;
496500}
501+
502+ /**
503+ * Loops through all defer block summaries and ensures all the blocks triggers are
504+ * properly initialized
505+ */
506+ export function processAndInitTriggers (
507+ injector : Injector ,
508+ blockData : Map < string , BlockSummary > ,
509+ nodes : Map < string , Comment > ,
510+ ) {
511+ const idleElements : ElementTrigger [ ] = [ ] ;
512+ const timerElements : ElementTrigger [ ] = [ ] ;
513+ const viewportElements : ElementTrigger [ ] = [ ] ;
514+ const immediateElements : ElementTrigger [ ] = [ ] ;
515+ for ( let [ blockId , blockSummary ] of blockData ) {
516+ const commentNode = nodes . get ( blockId ) ;
517+ if ( commentNode !== undefined ) {
518+ const numRootNodes = blockSummary . data [ NUM_ROOT_NODES ] ;
519+ let currentNode : Comment | HTMLElement = commentNode ;
520+ for ( let i = 0 ; i < numRootNodes ; i ++ ) {
521+ currentNode = currentNode . previousSibling as HTMLElement ;
522+ if ( currentNode . nodeType !== Node . ELEMENT_NODE ) {
523+ continue ;
524+ }
525+ const elementTrigger : ElementTrigger = { el : currentNode , blockName : blockId } ;
526+ // hydrate
527+ if ( blockSummary . hydrate . idle ) {
528+ idleElements . push ( elementTrigger ) ;
529+ }
530+ if ( blockSummary . hydrate . immediate ) {
531+ immediateElements . push ( elementTrigger ) ;
532+ }
533+ if ( blockSummary . hydrate . timer !== null ) {
534+ elementTrigger . delay = blockSummary . hydrate . timer ;
535+ timerElements . push ( elementTrigger ) ;
536+ }
537+ if ( blockSummary . hydrate . viewport ) {
538+ viewportElements . push ( elementTrigger ) ;
539+ }
540+ }
541+ }
542+ }
543+
544+ setIdleTriggers ( injector , idleElements ) ;
545+ setImmediateTriggers ( injector , immediateElements ) ;
546+ setViewportTriggers ( injector , viewportElements ) ;
547+ setTimerTriggers ( injector , timerElements ) ;
548+ }
549+
550+ async function setIdleTriggers ( injector : Injector , elementTriggers : ElementTrigger [ ] ) {
551+ for ( const elementTrigger of elementTriggers ) {
552+ const registry = injector . get ( DEHYDRATED_BLOCK_REGISTRY ) ;
553+ const onInvoke = ( ) => triggerHydrationFromBlockName ( injector , elementTrigger . blockName ) ;
554+ const cleanupFn = onIdle ( onInvoke , injector ) ;
555+ registry . addCleanupFn ( elementTrigger . blockName , cleanupFn ) ;
556+ }
557+ }
558+
559+ async function setViewportTriggers ( injector : Injector , elementTriggers : ElementTrigger [ ] ) {
560+ if ( elementTriggers . length > 0 ) {
561+ const registry = injector . get ( DEHYDRATED_BLOCK_REGISTRY ) ;
562+ for ( let elementTrigger of elementTriggers ) {
563+ const cleanupFn = onViewport (
564+ elementTrigger . el ,
565+ async ( ) => {
566+ await triggerHydrationFromBlockName ( injector , elementTrigger . blockName ) ;
567+ } ,
568+ injector ,
569+ ) ;
570+ registry . addCleanupFn ( elementTrigger . blockName , cleanupFn ) ;
571+ }
572+ }
573+ }
574+
575+ async function setTimerTriggers ( injector : Injector , elementTriggers : ElementTrigger [ ] ) {
576+ for ( const elementTrigger of elementTriggers ) {
577+ const registry = injector . get ( DEHYDRATED_BLOCK_REGISTRY ) ;
578+ const onInvoke = async ( ) =>
579+ await triggerHydrationFromBlockName ( injector , elementTrigger . blockName ) ;
580+ const timerFn = onTimer ( elementTrigger . delay ! ) ;
581+ const cleanupFn = timerFn ( onInvoke , injector ) ;
582+ registry . addCleanupFn ( elementTrigger . blockName , cleanupFn ) ;
583+ }
584+ }
585+
586+ async function setImmediateTriggers ( injector : Injector , elementTriggers : ElementTrigger [ ] ) {
587+ for ( const elementTrigger of elementTriggers ) {
588+ await triggerHydrationFromBlockName ( injector , elementTrigger . blockName ) ;
589+ }
590+ }
0 commit comments