@angular/core
Version:
Angular - the core framework
677 lines • 100 kB
JavaScript
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { setActiveConsumer } from '@angular/core/primitives/signals';
import { InjectionToken } from '../di';
import { RuntimeError } from '../errors';
import { findMatchingDehydratedView } from '../hydration/views';
import { populateDehydratedViewsInLContainer } from '../linker/view_container_ref';
import { assertLContainer, assertTNodeForLView } from '../render3/assert';
import { bindingUpdated } from '../render3/bindings';
import { getComponentDef, getDirectiveDef, getPipeDef } from '../render3/definition';
import { getTemplateLocationDetails } from '../render3/instructions/element_validation';
import { markViewDirty } from '../render3/instructions/mark_view_dirty';
import { handleError } from '../render3/instructions/shared';
import { ɵɵtemplate } from '../render3/instructions/template';
import { isDestroyed } from '../render3/interfaces/type_checks';
import { HEADER_OFFSET, INJECTOR, PARENT, TVIEW } from '../render3/interfaces/view';
import { getCurrentTNode, getLView, getSelectedTNode, getTView, nextBindingIndex } from '../render3/state';
import { isPlatformBrowser } from '../render3/util/misc_utils';
import { getConstant, getTNode, removeLViewOnDestroy, storeLViewOnDestroy } from '../render3/util/view_utils';
import { addLViewToLContainer, createAndRenderEmbeddedLView, removeLViewFromLContainer, shouldAddViewToDom } from '../render3/view_manipulation';
import { assertDefined, throwError } from '../util/assert';
import { performanceMarkFeature } from '../util/performance';
import { invokeAllTriggerCleanupFns, invokeTriggerCleanupFns, storeTriggerCleanupFn } from './cleanup';
import { onHover, onInteraction, onViewport, registerDomTrigger } from './dom_triggers';
import { onIdle } from './idle_scheduler';
import { DEFER_BLOCK_STATE, DeferBlockBehavior, DeferBlockInternalState, DeferBlockState, DeferDependenciesLoadingState, LOADING_AFTER_CLEANUP_FN, NEXT_DEFER_BLOCK_STATE, STATE_IS_FROZEN_UNTIL } from './interfaces';
import { onTimer, scheduleTimerTrigger } from './timer_scheduler';
import { addDepsToRegistry, assertDeferredDependenciesLoaded, getLDeferBlockDetails, getLoadingBlockAfter, getMinimumDurationForState, getPrimaryBlockTNode, getTDeferBlockDetails, getTemplateIndexForState, setLDeferBlockDetails, setTDeferBlockDetails } from './utils';
/**
* **INTERNAL**, avoid referencing it in application code.
*
* Injector token that allows to provide `DeferBlockDependencyInterceptor` class
* implementation.
*/
export const DEFER_BLOCK_DEPENDENCY_INTERCEPTOR = new InjectionToken('DEFER_BLOCK_DEPENDENCY_INTERCEPTOR');
/**
* **INTERNAL**, token used for configuring defer block behavior.
*/
export const DEFER_BLOCK_CONFIG = new InjectionToken(ngDevMode ? 'DEFER_BLOCK_CONFIG' : '');
/**
* Returns whether defer blocks should be triggered.
*
* Currently, defer blocks are not triggered on the server,
* only placeholder content is rendered (if provided).
*/
function shouldTriggerDeferBlock(injector) {
const config = injector.get(DEFER_BLOCK_CONFIG, null, { optional: true });
if (config?.behavior === DeferBlockBehavior.Manual) {
return false;
}
return isPlatformBrowser(injector);
}
/**
* Reference to the timer-based scheduler implementation of defer block state
* rendering method. It's used to make timer-based scheduling tree-shakable.
* If `minimum` or `after` parameters are used, compiler generates an extra
* argument for the `ɵɵdefer` instruction, which references a timer-based
* implementation.
*/
let applyDeferBlockStateWithSchedulingImpl = null;
/**
* Enables timer-related scheduling if `after` or `minimum` parameters are setup
* on the `@loading` or `@placeholder` blocks.
*/
export function ɵɵdeferEnableTimerScheduling(tView, tDetails, placeholderConfigIndex, loadingConfigIndex) {
const tViewConsts = tView.consts;
if (placeholderConfigIndex != null) {
tDetails.placeholderBlockConfig =
getConstant(tViewConsts, placeholderConfigIndex);
}
if (loadingConfigIndex != null) {
tDetails.loadingBlockConfig =
getConstant(tViewConsts, loadingConfigIndex);
}
// Enable implementation that supports timer-based scheduling.
if (applyDeferBlockStateWithSchedulingImpl === null) {
applyDeferBlockStateWithSchedulingImpl = applyDeferBlockStateWithScheduling;
}
}
/**
* Creates runtime data structures for defer blocks.
*
* @param index Index of the `defer` instruction.
* @param primaryTmplIndex Index of the template with the primary block content.
* @param dependencyResolverFn Function that contains dependencies for this defer block.
* @param loadingTmplIndex Index of the template with the loading block content.
* @param placeholderTmplIndex Index of the template with the placeholder block content.
* @param errorTmplIndex Index of the template with the error block content.
* @param loadingConfigIndex Index in the constants array of the configuration of the loading.
* block.
* @param placeholderConfigIndex Index in the constants array of the configuration of the
* placeholder block.
* @param enableTimerScheduling Function that enables timer-related scheduling if `after`
* or `minimum` parameters are setup on the `@loading` or `@placeholder` blocks.
*
* @codeGenApi
*/
export function ɵɵdefer(index, primaryTmplIndex, dependencyResolverFn, loadingTmplIndex, placeholderTmplIndex, errorTmplIndex, loadingConfigIndex, placeholderConfigIndex, enableTimerScheduling) {
const lView = getLView();
const tView = getTView();
const adjustedIndex = index + HEADER_OFFSET;
ɵɵtemplate(index, null, 0, 0);
if (tView.firstCreatePass) {
performanceMarkFeature('NgDefer');
const tDetails = {
primaryTmplIndex,
loadingTmplIndex: loadingTmplIndex ?? null,
placeholderTmplIndex: placeholderTmplIndex ?? null,
errorTmplIndex: errorTmplIndex ?? null,
placeholderBlockConfig: null,
loadingBlockConfig: null,
dependencyResolverFn: dependencyResolverFn ?? null,
loadingState: DeferDependenciesLoadingState.NOT_STARTED,
loadingPromise: null,
};
enableTimerScheduling?.(tView, tDetails, placeholderConfigIndex, loadingConfigIndex);
setTDeferBlockDetails(tView, adjustedIndex, tDetails);
}
const tNode = getCurrentTNode();
const lContainer = lView[adjustedIndex];
// If hydration is enabled, looks up dehydrated views in the DOM
// using hydration annotation info and stores those views on LContainer.
// In client-only mode, this function is a noop.
populateDehydratedViewsInLContainer(lContainer, tNode, lView);
// Init instance-specific defer details and store it.
const lDetails = [
null, // NEXT_DEFER_BLOCK_STATE
DeferBlockInternalState.Initial, // DEFER_BLOCK_STATE
null, // STATE_IS_FROZEN_UNTIL
null, // LOADING_AFTER_CLEANUP_FN
null, // TRIGGER_CLEANUP_FNS
null // PREFETCH_TRIGGER_CLEANUP_FNS
];
setLDeferBlockDetails(lView, adjustedIndex, lDetails);
const cleanupTriggersFn = () => invokeAllTriggerCleanupFns(lDetails);
// When defer block is triggered - unsubscribe from LView destroy cleanup.
storeTriggerCleanupFn(0 /* TriggerType.Regular */, lDetails, () => removeLViewOnDestroy(lView, cleanupTriggersFn));
storeLViewOnDestroy(lView, cleanupTriggersFn);
}
/**
* Loads defer block dependencies when a trigger value becomes truthy.
* @codeGenApi
*/
export function ɵɵdeferWhen(rawValue) {
const lView = getLView();
const bindingIndex = nextBindingIndex();
if (bindingUpdated(lView, bindingIndex, rawValue)) {
const prevConsumer = setActiveConsumer(null);
try {
const value = Boolean(rawValue); // handle truthy or falsy values
const tNode = getSelectedTNode();
const lDetails = getLDeferBlockDetails(lView, tNode);
const renderedState = lDetails[DEFER_BLOCK_STATE];
if (value === false && renderedState === DeferBlockInternalState.Initial) {
// If nothing is rendered yet, render a placeholder (if defined).
renderPlaceholder(lView, tNode);
}
else if (value === true &&
(renderedState === DeferBlockInternalState.Initial ||
renderedState === DeferBlockState.Placeholder)) {
// The `when` condition has changed to `true`, trigger defer block loading
// if the block is either in initial (nothing is rendered) or a placeholder
// state.
triggerDeferBlock(lView, tNode);
}
}
finally {
setActiveConsumer(prevConsumer);
}
}
}
/**
* Prefetches the deferred content when a value becomes truthy.
* @codeGenApi
*/
export function ɵɵdeferPrefetchWhen(rawValue) {
const lView = getLView();
const bindingIndex = nextBindingIndex();
if (bindingUpdated(lView, bindingIndex, rawValue)) {
const prevConsumer = setActiveConsumer(null);
try {
const value = Boolean(rawValue); // handle truthy or falsy values
const tView = lView[TVIEW];
const tNode = getSelectedTNode();
const tDetails = getTDeferBlockDetails(tView, tNode);
if (value === true && tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
// If loading has not been started yet, trigger it now.
triggerPrefetching(tDetails, lView, tNode);
}
}
finally {
setActiveConsumer(prevConsumer);
}
}
}
/**
* Sets up logic to handle the `on idle` deferred trigger.
* @codeGenApi
*/
export function ɵɵdeferOnIdle() {
scheduleDelayedTrigger(onIdle);
}
/**
* Sets up logic to handle the `prefetch on idle` deferred trigger.
* @codeGenApi
*/
export function ɵɵdeferPrefetchOnIdle() {
scheduleDelayedPrefetching(onIdle);
}
/**
* Sets up logic to handle the `on immediate` deferred trigger.
* @codeGenApi
*/
export function ɵɵdeferOnImmediate() {
const lView = getLView();
const tNode = getCurrentTNode();
const tView = lView[TVIEW];
const tDetails = getTDeferBlockDetails(tView, tNode);
// Render placeholder block only if loading template is not present
// to avoid content flickering, since it would be immediately replaced
// by the loading block.
if (tDetails.loadingTmplIndex === null) {
renderPlaceholder(lView, tNode);
}
triggerDeferBlock(lView, tNode);
}
/**
* Sets up logic to handle the `prefetch on immediate` deferred trigger.
* @codeGenApi
*/
export function ɵɵdeferPrefetchOnImmediate() {
const lView = getLView();
const tNode = getCurrentTNode();
const tView = lView[TVIEW];
const tDetails = getTDeferBlockDetails(tView, tNode);
if (tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
triggerResourceLoading(tDetails, lView, tNode);
}
}
/**
* Creates runtime data structures for the `on timer` deferred trigger.
* @param delay Amount of time to wait before loading the content.
* @codeGenApi
*/
export function ɵɵdeferOnTimer(delay) {
scheduleDelayedTrigger(onTimer(delay));
}
/**
* Creates runtime data structures for the `prefetch on timer` deferred trigger.
* @param delay Amount of time to wait before prefetching the content.
* @codeGenApi
*/
export function ɵɵdeferPrefetchOnTimer(delay) {
scheduleDelayedPrefetching(onTimer(delay));
}
/**
* Creates runtime data structures for the `on hover` deferred trigger.
* @param triggerIndex Index at which to find the trigger element.
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
* @codeGenApi
*/
export function ɵɵdeferOnHover(triggerIndex, walkUpTimes) {
const lView = getLView();
const tNode = getCurrentTNode();
renderPlaceholder(lView, tNode);
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onHover, () => triggerDeferBlock(lView, tNode), 0 /* TriggerType.Regular */);
}
/**
* Creates runtime data structures for the `prefetch on hover` deferred trigger.
* @param triggerIndex Index at which to find the trigger element.
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
* @codeGenApi
*/
export function ɵɵdeferPrefetchOnHover(triggerIndex, walkUpTimes) {
const lView = getLView();
const tNode = getCurrentTNode();
const tView = lView[TVIEW];
const tDetails = getTDeferBlockDetails(tView, tNode);
if (tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onHover, () => triggerPrefetching(tDetails, lView, tNode), 1 /* TriggerType.Prefetch */);
}
}
/**
* Creates runtime data structures for the `on interaction` deferred trigger.
* @param triggerIndex Index at which to find the trigger element.
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
* @codeGenApi
*/
export function ɵɵdeferOnInteraction(triggerIndex, walkUpTimes) {
const lView = getLView();
const tNode = getCurrentTNode();
renderPlaceholder(lView, tNode);
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onInteraction, () => triggerDeferBlock(lView, tNode), 0 /* TriggerType.Regular */);
}
/**
* Creates runtime data structures for the `prefetch on interaction` deferred trigger.
* @param triggerIndex Index at which to find the trigger element.
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
* @codeGenApi
*/
export function ɵɵdeferPrefetchOnInteraction(triggerIndex, walkUpTimes) {
const lView = getLView();
const tNode = getCurrentTNode();
const tView = lView[TVIEW];
const tDetails = getTDeferBlockDetails(tView, tNode);
if (tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onInteraction, () => triggerPrefetching(tDetails, lView, tNode), 1 /* TriggerType.Prefetch */);
}
}
/**
* Creates runtime data structures for the `on viewport` deferred trigger.
* @param triggerIndex Index at which to find the trigger element.
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
* @codeGenApi
*/
export function ɵɵdeferOnViewport(triggerIndex, walkUpTimes) {
const lView = getLView();
const tNode = getCurrentTNode();
renderPlaceholder(lView, tNode);
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onViewport, () => triggerDeferBlock(lView, tNode), 0 /* TriggerType.Regular */);
}
/**
* Creates runtime data structures for the `prefetch on viewport` deferred trigger.
* @param triggerIndex Index at which to find the trigger element.
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
* @codeGenApi
*/
export function ɵɵdeferPrefetchOnViewport(triggerIndex, walkUpTimes) {
const lView = getLView();
const tNode = getCurrentTNode();
const tView = lView[TVIEW];
const tDetails = getTDeferBlockDetails(tView, tNode);
if (tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onViewport, () => triggerPrefetching(tDetails, lView, tNode), 1 /* TriggerType.Prefetch */);
}
}
/********** Helper functions **********/
/**
* Schedules triggering of a defer block for `on idle` and `on timer` conditions.
*/
function scheduleDelayedTrigger(scheduleFn) {
const lView = getLView();
const tNode = getCurrentTNode();
renderPlaceholder(lView, tNode);
const cleanupFn = scheduleFn(() => triggerDeferBlock(lView, tNode), lView);
const lDetails = getLDeferBlockDetails(lView, tNode);
storeTriggerCleanupFn(0 /* TriggerType.Regular */, lDetails, cleanupFn);
}
/**
* Schedules prefetching for `on idle` and `on timer` triggers.
*
* @param scheduleFn A function that does the scheduling.
*/
function scheduleDelayedPrefetching(scheduleFn) {
const lView = getLView();
const tNode = getCurrentTNode();
const tView = lView[TVIEW];
const tDetails = getTDeferBlockDetails(tView, tNode);
if (tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
const lDetails = getLDeferBlockDetails(lView, tNode);
const prefetch = () => triggerPrefetching(tDetails, lView, tNode);
const cleanupFn = scheduleFn(prefetch, lView);
storeTriggerCleanupFn(1 /* TriggerType.Prefetch */, lDetails, cleanupFn);
}
}
/**
* Transitions a defer block to the new state. Updates the necessary
* data structures and renders corresponding block.
*
* @param newState New state that should be applied to the defer block.
* @param tNode TNode that represents a defer block.
* @param lContainer Represents an instance of a defer block.
* @param skipTimerScheduling Indicates that `@loading` and `@placeholder` block
* should be rendered immediately, even if they have `after` or `minimum` config
* options setup. This flag to needed for testing APIs to transition defer block
* between states via `DeferFixture.render` method.
*/
export function renderDeferBlockState(newState, tNode, lContainer, skipTimerScheduling = false) {
const hostLView = lContainer[PARENT];
const hostTView = hostLView[TVIEW];
// Check if this view is not destroyed. Since the loading process was async,
// the view might end up being destroyed by the time rendering happens.
if (isDestroyed(hostLView))
return;
// Make sure this TNode belongs to TView that represents host LView.
ngDevMode && assertTNodeForLView(tNode, hostLView);
const lDetails = getLDeferBlockDetails(hostLView, tNode);
ngDevMode && assertDefined(lDetails, 'Expected a defer block state defined');
const currentState = lDetails[DEFER_BLOCK_STATE];
if (isValidStateChange(currentState, newState) &&
isValidStateChange(lDetails[NEXT_DEFER_BLOCK_STATE] ?? -1, newState)) {
const tDetails = getTDeferBlockDetails(hostTView, tNode);
const needsScheduling = !skipTimerScheduling &&
(getLoadingBlockAfter(tDetails) !== null ||
getMinimumDurationForState(tDetails, DeferBlockState.Loading) !== null ||
getMinimumDurationForState(tDetails, DeferBlockState.Placeholder));
if (ngDevMode && needsScheduling) {
assertDefined(applyDeferBlockStateWithSchedulingImpl, 'Expected scheduling function to be defined');
}
const applyStateFn = needsScheduling ? applyDeferBlockStateWithSchedulingImpl : applyDeferBlockState;
try {
applyStateFn(newState, lDetails, lContainer, tNode, hostLView);
}
catch (error) {
handleError(hostLView, error);
}
}
}
/**
* Applies changes to the DOM to reflect a given state.
*/
function applyDeferBlockState(newState, lDetails, lContainer, tNode, hostLView) {
const stateTmplIndex = getTemplateIndexForState(newState, hostLView, tNode);
if (stateTmplIndex !== null) {
lDetails[DEFER_BLOCK_STATE] = newState;
const hostTView = hostLView[TVIEW];
const adjustedIndex = stateTmplIndex + HEADER_OFFSET;
const tNode = getTNode(hostTView, adjustedIndex);
// There is only 1 view that can be present in an LContainer that
// represents a defer block, so always refer to the first one.
const viewIndex = 0;
removeLViewFromLContainer(lContainer, viewIndex);
const dehydratedView = findMatchingDehydratedView(lContainer, tNode.tView.ssrId);
const embeddedLView = createAndRenderEmbeddedLView(hostLView, tNode, null, { dehydratedView });
addLViewToLContainer(lContainer, embeddedLView, viewIndex, shouldAddViewToDom(tNode, dehydratedView));
markViewDirty(embeddedLView);
}
}
/**
* Extends the `applyDeferBlockState` with timer-based scheduling.
* This function becomes available on a page if there are defer blocks
* that use `after` or `minimum` parameters in the `@loading` or
* `@placeholder` blocks.
*/
function applyDeferBlockStateWithScheduling(newState, lDetails, lContainer, tNode, hostLView) {
const now = Date.now();
const hostTView = hostLView[TVIEW];
const tDetails = getTDeferBlockDetails(hostTView, tNode);
if (lDetails[STATE_IS_FROZEN_UNTIL] === null || lDetails[STATE_IS_FROZEN_UNTIL] <= now) {
lDetails[STATE_IS_FROZEN_UNTIL] = null;
const loadingAfter = getLoadingBlockAfter(tDetails);
const inLoadingAfterPhase = lDetails[LOADING_AFTER_CLEANUP_FN] !== null;
if (newState === DeferBlockState.Loading && loadingAfter !== null && !inLoadingAfterPhase) {
// Trying to render loading, but it has an `after` config,
// so schedule an update action after a timeout.
lDetails[NEXT_DEFER_BLOCK_STATE] = newState;
const cleanupFn = scheduleDeferBlockUpdate(loadingAfter, lDetails, tNode, lContainer, hostLView);
lDetails[LOADING_AFTER_CLEANUP_FN] = cleanupFn;
}
else {
// If we transition to a complete or an error state and there is a pending
// operation to render loading after a timeout - invoke a cleanup operation,
// which stops the timer.
if (newState > DeferBlockState.Loading && inLoadingAfterPhase) {
lDetails[LOADING_AFTER_CLEANUP_FN]();
lDetails[LOADING_AFTER_CLEANUP_FN] = null;
lDetails[NEXT_DEFER_BLOCK_STATE] = null;
}
applyDeferBlockState(newState, lDetails, lContainer, tNode, hostLView);
const duration = getMinimumDurationForState(tDetails, newState);
if (duration !== null) {
lDetails[STATE_IS_FROZEN_UNTIL] = now + duration;
scheduleDeferBlockUpdate(duration, lDetails, tNode, lContainer, hostLView);
}
}
}
else {
// We are still rendering the previous state.
// Update the `NEXT_DEFER_BLOCK_STATE`, which would be
// picked up once it's time to transition to the next state.
lDetails[NEXT_DEFER_BLOCK_STATE] = newState;
}
}
/**
* Schedules an update operation after a specified timeout.
*/
function scheduleDeferBlockUpdate(timeout, lDetails, tNode, lContainer, hostLView) {
const callback = () => {
const nextState = lDetails[NEXT_DEFER_BLOCK_STATE];
lDetails[STATE_IS_FROZEN_UNTIL] = null;
lDetails[NEXT_DEFER_BLOCK_STATE] = null;
if (nextState !== null) {
renderDeferBlockState(nextState, tNode, lContainer);
}
};
return scheduleTimerTrigger(timeout, callback, hostLView);
}
/**
* Checks whether we can transition to the next state.
*
* We transition to the next state if the previous state was represented
* with a number that is less than the next state. For example, if the current
* state is "loading" (represented as `1`), we should not show a placeholder
* (represented as `0`), but we can show a completed state (represented as `2`)
* or an error state (represented as `3`).
*/
function isValidStateChange(currentState, newState) {
return currentState < newState;
}
/**
* Trigger prefetching of dependencies for a defer block.
*
* @param tDetails Static information about this defer block.
* @param lView LView of a host view.
*/
export function triggerPrefetching(tDetails, lView, tNode) {
if (lView[INJECTOR] && shouldTriggerDeferBlock(lView[INJECTOR])) {
triggerResourceLoading(tDetails, lView, tNode);
}
}
/**
* Trigger loading of defer block dependencies if the process hasn't started yet.
*
* @param tDetails Static information about this defer block.
* @param lView LView of a host view.
*/
export function triggerResourceLoading(tDetails, lView, tNode) {
const injector = lView[INJECTOR];
const tView = lView[TVIEW];
if (tDetails.loadingState !== DeferDependenciesLoadingState.NOT_STARTED) {
// If the loading status is different from initial one, it means that
// the loading of dependencies is in progress and there is nothing to do
// in this function. All details can be obtained from the `tDetails` object.
return;
}
const lDetails = getLDeferBlockDetails(lView, tNode);
const primaryBlockTNode = getPrimaryBlockTNode(tView, tDetails);
// Switch from NOT_STARTED -> IN_PROGRESS state.
tDetails.loadingState = DeferDependenciesLoadingState.IN_PROGRESS;
// Prefetching is triggered, cleanup all registered prefetch triggers.
invokeTriggerCleanupFns(1 /* TriggerType.Prefetch */, lDetails);
let dependenciesFn = tDetails.dependencyResolverFn;
if (ngDevMode) {
// Check if dependency function interceptor is configured.
const deferDependencyInterceptor = injector.get(DEFER_BLOCK_DEPENDENCY_INTERCEPTOR, null, { optional: true });
if (deferDependencyInterceptor) {
dependenciesFn = deferDependencyInterceptor.intercept(dependenciesFn);
}
}
// The `dependenciesFn` might be `null` when all dependencies within
// a given defer block were eagerly referenced elsewhere in a file,
// thus no dynamic `import()`s were produced.
if (!dependenciesFn) {
tDetails.loadingPromise = Promise.resolve().then(() => {
tDetails.loadingPromise = null;
tDetails.loadingState = DeferDependenciesLoadingState.COMPLETE;
});
return;
}
// Start downloading of defer block dependencies.
tDetails.loadingPromise = Promise.allSettled(dependenciesFn()).then(results => {
let failed = false;
const directiveDefs = [];
const pipeDefs = [];
for (const result of results) {
if (result.status === 'fulfilled') {
const dependency = result.value;
const directiveDef = getComponentDef(dependency) || getDirectiveDef(dependency);
if (directiveDef) {
directiveDefs.push(directiveDef);
}
else {
const pipeDef = getPipeDef(dependency);
if (pipeDef) {
pipeDefs.push(pipeDef);
}
}
}
else {
failed = true;
break;
}
}
// Loading is completed, we no longer need this Promise.
tDetails.loadingPromise = null;
if (failed) {
tDetails.loadingState = DeferDependenciesLoadingState.FAILED;
if (tDetails.errorTmplIndex === null) {
const templateLocation = getTemplateLocationDetails(lView);
const error = new RuntimeError(750 /* RuntimeErrorCode.DEFER_LOADING_FAILED */, ngDevMode &&
'Loading dependencies for `@defer` block failed, ' +
`but no \`@error\` block was configured${templateLocation}. ` +
'Consider using the `@error` block to render an error state.');
handleError(lView, error);
}
}
else {
tDetails.loadingState = DeferDependenciesLoadingState.COMPLETE;
// Update directive and pipe registries to add newly downloaded dependencies.
const primaryBlockTView = primaryBlockTNode.tView;
if (directiveDefs.length > 0) {
primaryBlockTView.directiveRegistry =
addDepsToRegistry(primaryBlockTView.directiveRegistry, directiveDefs);
}
if (pipeDefs.length > 0) {
primaryBlockTView.pipeRegistry =
addDepsToRegistry(primaryBlockTView.pipeRegistry, pipeDefs);
}
}
});
}
/** Utility function to render placeholder content (if present) */
function renderPlaceholder(lView, tNode) {
const lContainer = lView[tNode.index];
ngDevMode && assertLContainer(lContainer);
renderDeferBlockState(DeferBlockState.Placeholder, tNode, lContainer);
}
/**
* Subscribes to the "loading" Promise and renders corresponding defer sub-block,
* based on the loading results.
*
* @param lContainer Represents an instance of a defer block.
* @param tNode Represents defer block info shared across all instances.
*/
function renderDeferStateAfterResourceLoading(tDetails, tNode, lContainer) {
ngDevMode &&
assertDefined(tDetails.loadingPromise, 'Expected loading Promise to exist on this defer block');
tDetails.loadingPromise.then(() => {
if (tDetails.loadingState === DeferDependenciesLoadingState.COMPLETE) {
ngDevMode && assertDeferredDependenciesLoaded(tDetails);
// Everything is loaded, show the primary block content
renderDeferBlockState(DeferBlockState.Complete, tNode, lContainer);
}
else if (tDetails.loadingState === DeferDependenciesLoadingState.FAILED) {
renderDeferBlockState(DeferBlockState.Error, tNode, lContainer);
}
});
}
/**
* Attempts to trigger loading of defer block dependencies.
* If the block is already in a loading, completed or an error state -
* no additional actions are taken.
*/
function triggerDeferBlock(lView, tNode) {
const tView = lView[TVIEW];
const lContainer = lView[tNode.index];
const injector = lView[INJECTOR];
ngDevMode && assertLContainer(lContainer);
if (!shouldTriggerDeferBlock(injector))
return;
const lDetails = getLDeferBlockDetails(lView, tNode);
const tDetails = getTDeferBlockDetails(tView, tNode);
// Defer block is triggered, cleanup all registered trigger functions.
invokeAllTriggerCleanupFns(lDetails);
switch (tDetails.loadingState) {
case DeferDependenciesLoadingState.NOT_STARTED:
renderDeferBlockState(DeferBlockState.Loading, tNode, lContainer);
triggerResourceLoading(tDetails, lView, tNode);
// The `loadingState` might have changed to "loading".
if (tDetails.loadingState ===
DeferDependenciesLoadingState.IN_PROGRESS) {
renderDeferStateAfterResourceLoading(tDetails, tNode, lContainer);
}
break;
case DeferDependenciesLoadingState.IN_PROGRESS:
renderDeferBlockState(DeferBlockState.Loading, tNode, lContainer);
renderDeferStateAfterResourceLoading(tDetails, tNode, lContainer);
break;
case DeferDependenciesLoadingState.COMPLETE:
ngDevMode && assertDeferredDependenciesLoaded(tDetails);
renderDeferBlockState(DeferBlockState.Complete, tNode, lContainer);
break;
case DeferDependenciesLoadingState.FAILED:
renderDeferBlockState(DeferBlockState.Error, tNode, lContainer);
break;
default:
if (ngDevMode) {
throwError('Unknown defer block state');
}
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5zdHJ1Y3Rpb25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvY29yZS9zcmMvZGVmZXIvaW5zdHJ1Y3Rpb25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQUVILE9BQU8sRUFBQyxpQkFBaUIsRUFBQyxNQUFNLGtDQUFrQyxDQUFDO0FBRW5FLE9BQU8sRUFBQyxjQUFjLEVBQVcsTUFBTSxPQUFPLENBQUM7QUFDL0MsT0FBTyxFQUFDLFlBQVksRUFBbUIsTUFBTSxXQUFXLENBQUM7QUFDekQsT0FBTyxFQUFDLDBCQUEwQixFQUFDLE1BQU0sb0JBQW9CLENBQUM7QUFDOUQsT0FBTyxFQUFDLG1DQUFtQyxFQUFDLE1BQU0sOEJBQThCLENBQUM7QUFDakYsT0FBTyxFQUFDLGdCQUFnQixFQUFFLG1CQUFtQixFQUFDLE1BQU0sbUJBQW1CLENBQUM7QUFDeEUsT0FBTyxFQUFDLGNBQWMsRUFBQyxNQUFNLHFCQUFxQixDQUFDO0FBQ25ELE9BQU8sRUFBQyxlQUFlLEVBQUUsZUFBZSxFQUFFLFVBQVUsRUFBQyxNQUFNLHVCQUF1QixDQUFDO0FBQ25GLE9BQU8sRUFBQywwQkFBMEIsRUFBQyxNQUFNLDRDQUE0QyxDQUFDO0FBQ3RGLE9BQU8sRUFBQyxhQUFhLEVBQUMsTUFBTSx5Q0FBeUMsQ0FBQztBQUN0RSxPQUFPLEVBQUMsV0FBVyxFQUFDLE1BQU0sZ0NBQWdDLENBQUM7QUFDM0QsT0FBTyxFQUFDLFVBQVUsRUFBQyxNQUFNLGtDQUFrQyxDQUFDO0FBSTVELE9BQU8sRUFBQyxXQUFXLEVBQUMsTUFBTSxtQ0FBbUMsQ0FBQztBQUM5RCxPQUFPLEVBQUMsYUFBYSxFQUFFLFFBQVEsRUFBUyxNQUFNLEVBQUUsS0FBSyxFQUFRLE1BQU0sNEJBQTRCLENBQUM7QUFDaEcsT0FBTyxFQUFDLGVBQWUsRUFBRSxRQUFRLEVBQUUsZ0JBQWdCLEVBQUUsUUFBUSxFQUFFLGdCQUFn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