mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
refactor(core): tree-shake defer block registry (#58424)
This commit updates the code of the incremental hydration feature to make the `DeferBlockRegistry` class tree-shakable. The class is only needed for hydration cases and it should not be included into client bundles for client-only apps. PR Close #58424
This commit is contained in:
parent
0ca14e2c72
commit
600ef5eff2
9 changed files with 51 additions and 18 deletions
|
|
@ -83,6 +83,8 @@ export const enum RuntimeErrorCode {
|
|||
// (undocumented)
|
||||
LOOP_TRACK_RECREATE = -956,
|
||||
// (undocumented)
|
||||
MISCONFIGURED_INCREMENTAL_HYDRATION = 508,
|
||||
// (undocumented)
|
||||
MISSING_DOCUMENT = 210,
|
||||
// (undocumented)
|
||||
MISSING_GENERATED_DEF = 906,
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ import {onTimer, scheduleTimerTrigger} from './timer_scheduler';
|
|||
import {
|
||||
addDepsToRegistry,
|
||||
assertDeferredDependenciesLoaded,
|
||||
assertIncrementalHydrationIsConfigured,
|
||||
getLDeferBlockDetails,
|
||||
getLoadingBlockAfter,
|
||||
getMinimumDurationForState,
|
||||
|
|
@ -98,7 +99,7 @@ import {
|
|||
setLDeferBlockDetails,
|
||||
setTDeferBlockDetails,
|
||||
} from './utils';
|
||||
import {DeferBlockRegistry} from './registry';
|
||||
import {DEFER_BLOCK_REGISTRY, DeferBlockRegistry} from './registry';
|
||||
import {incrementallyHydrateFromBlockName} from '../hydration/blocks';
|
||||
import {isIncrementalHydrationEnabled} from '../hydration/utils';
|
||||
|
||||
|
|
@ -319,11 +320,11 @@ export function ɵɵdefer(
|
|||
|
||||
let registry: DeferBlockRegistry | null = null;
|
||||
if (ssrUniqueId !== null) {
|
||||
// TODO(incremental-hydration): explore how we can make
|
||||
// `DeferBlockRegistry` tree-shakable for client-only cases.
|
||||
registry = injector.get(DeferBlockRegistry);
|
||||
ngDevMode && assertIncrementalHydrationIsConfigured(injector);
|
||||
|
||||
// Also store this defer block in the registry.
|
||||
// Store this defer block in the registry, to have an access to
|
||||
// internal data structures from hydration runtime code.
|
||||
registry = injector.get(DEFER_BLOCK_REGISTRY);
|
||||
registry.add(ssrUniqueId, {lView, tNode, lContainer});
|
||||
}
|
||||
|
||||
|
|
@ -1444,7 +1445,7 @@ export function triggerDeferBlock(lView: LView, tNode: TNode) {
|
|||
|
||||
let registry: DeferBlockRegistry | null = null;
|
||||
if (isIncrementalHydrationEnabled(injector)) {
|
||||
registry = injector.get(DeferBlockRegistry);
|
||||
registry = injector.get(DEFER_BLOCK_REGISTRY);
|
||||
}
|
||||
// Defer block is triggered, cleanup all registered trigger functions.
|
||||
invokeAllTriggerCleanupFns(lDetails, registry);
|
||||
|
|
|
|||
|
|
@ -5,10 +5,18 @@
|
|||
* 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 {ɵɵdefineInjectable} from '../di';
|
||||
import {InjectionToken} from '../di/injection_token';
|
||||
import {ɵɵdefineInjectable} from '../di/interface/defs';
|
||||
import {DeferBlock} from './interfaces';
|
||||
|
||||
// TODO(incremental-hydration): refactor this so that it's not used in CSR cases
|
||||
/**
|
||||
* An internal injection token to reference `DeferBlockRegistry` implementation
|
||||
* in a tree-shakable way.
|
||||
*/
|
||||
export const DEFER_BLOCK_REGISTRY = new InjectionToken<DeferBlockRegistry>(
|
||||
ngDevMode ? 'DEFER_BLOCK_REGISTRY' : '',
|
||||
);
|
||||
|
||||
/**
|
||||
* The DeferBlockRegistry is used for incremental hydration purposes. It keeps
|
||||
* track of the Defer Blocks that need hydration so we can effectively
|
||||
|
|
@ -73,7 +81,7 @@ export class DeferBlockRegistry {
|
|||
/** @nocollapse */
|
||||
static ɵprov = /** @pureOrBreakMyCode */ /* @__PURE__ */ ɵɵdefineInjectable({
|
||||
token: DeferBlockRegistry,
|
||||
providedIn: 'root',
|
||||
providedIn: null,
|
||||
factory: () => new DeferBlockRegistry(),
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Injector} from '../di';
|
||||
import {RuntimeError, RuntimeErrorCode} from '../errors';
|
||||
import {isIncrementalHydrationEnabled} from '../hydration/utils';
|
||||
import {assertIndexInDeclRange} from '../render3/assert';
|
||||
import {DependencyDef} from '../render3/interfaces/definition';
|
||||
import {TContainerNode, TNode} from '../render3/interfaces/node';
|
||||
|
|
@ -181,3 +184,16 @@ export function isDeferBlock(tView: TView, tNode: TNode): boolean {
|
|||
}
|
||||
return !!tDetails && isTDeferBlockDetails(tDetails);
|
||||
}
|
||||
|
||||
/** Throws an error if the incremental hydration is not enabled */
|
||||
export function assertIncrementalHydrationIsConfigured(injector: Injector) {
|
||||
if (!isIncrementalHydrationEnabled(injector)) {
|
||||
throw new RuntimeError(
|
||||
RuntimeErrorCode.MISCONFIGURED_INCREMENTAL_HYDRATION,
|
||||
'Angular has detected that some `@defer` blocks use `hydrate` triggers, ' +
|
||||
'but incremental hydration was not enabled. Please ensure that the `withIncrementalHydration()` ' +
|
||||
'call is added as an argument for the `provideClientHydration()` function call ' +
|
||||
'in your application config.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ export const enum RuntimeErrorCode {
|
|||
MISSING_HYDRATION_ANNOTATIONS = -505,
|
||||
HYDRATION_STABLE_TIMEDOUT = -506,
|
||||
MISSING_SSR_CONTENT_INTEGRITY_MARKER = -507,
|
||||
MISCONFIGURED_INCREMENTAL_HYDRATION = 508,
|
||||
|
||||
// Signal Errors
|
||||
SIGNAL_WRITE_FROM_ILLEGAL_CONTEXT = 600,
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import {
|
|||
import {enableRetrieveHydrationInfoImpl, NGH_DATA_KEY, SSR_CONTENT_INTEGRITY_MARKER} from './utils';
|
||||
import {enableFindMatchingDehydratedViewImpl} from './views';
|
||||
import {bootstrapIncrementalHydration, enableRetrieveDeferBlockDataImpl} from './incremental';
|
||||
import {DEFER_BLOCK_REGISTRY, DeferBlockRegistry} from '../defer/registry';
|
||||
|
||||
/**
|
||||
* Indicates whether the hydration-related code was added,
|
||||
|
|
@ -326,6 +327,10 @@ export function withIncrementalHydration(): Provider[] {
|
|||
provide: IS_INCREMENTAL_HYDRATION_ENABLED,
|
||||
useValue: true,
|
||||
},
|
||||
{
|
||||
provide: DEFER_BLOCK_REGISTRY,
|
||||
useClass: DeferBlockRegistry,
|
||||
},
|
||||
{
|
||||
provide: ENVIRONMENT_INITIALIZER,
|
||||
useValue: () => {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {DeferBlockRegistry} from '../defer/registry';
|
||||
import {DEFER_BLOCK_REGISTRY} from '../defer/registry';
|
||||
import {DEFER_PARENT_BLOCK_ID} from './interfaces';
|
||||
import {NGH_DEFER_BLOCKS_KEY} from './utils';
|
||||
import {Injector} from '../di';
|
||||
|
|
@ -25,7 +25,7 @@ import {assertEqual} from '../util/assert';
|
|||
* Note: This is utilizing serialized information to navigate up the tree
|
||||
*/
|
||||
export function getParentBlockHydrationQueue(deferBlockId: string, injector: Injector) {
|
||||
const deferBlockRegistry = injector.get(DeferBlockRegistry);
|
||||
const deferBlockRegistry = injector.get(DEFER_BLOCK_REGISTRY);
|
||||
const transferState = injector.get(TransferState);
|
||||
const deferBlockParents = transferState.get(NGH_DEFER_BLOCKS_KEY, {});
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ export async function hydrateFromBlockName(
|
|||
deferBlock: DeferBlock | null;
|
||||
hydratedBlocks: Set<string>;
|
||||
}> {
|
||||
const deferBlockRegistry = injector.get(DeferBlockRegistry);
|
||||
const deferBlockRegistry = injector.get(DEFER_BLOCK_REGISTRY);
|
||||
|
||||
// Make sure we don't hydrate/trigger the same thing multiple times
|
||||
if (deferBlockRegistry.hydrating.has(blockName))
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
import {TransferState} from '../transfer_state';
|
||||
import {onIdle} from '../defer/idle_scheduler';
|
||||
import {DeferBlockTrigger} from '../defer/interfaces';
|
||||
import {DeferBlockRegistry} from '../defer/registry';
|
||||
import {DEFER_BLOCK_REGISTRY} from '../defer/registry';
|
||||
import {onTimer} from '../defer/timer_scheduler';
|
||||
import {Injector} from '../di';
|
||||
import {assertDefined} from '../util/assert';
|
||||
|
|
@ -168,7 +168,7 @@ function processAndInitTriggers(
|
|||
|
||||
async function setIdleTriggers(injector: Injector, elementTriggers: ElementTrigger[]) {
|
||||
for (const elementTrigger of elementTriggers) {
|
||||
const registry = injector.get(DeferBlockRegistry);
|
||||
const registry = injector.get(DEFER_BLOCK_REGISTRY);
|
||||
const onInvoke = () =>
|
||||
incrementallyHydrateFromBlockName(
|
||||
injector,
|
||||
|
|
@ -198,7 +198,7 @@ async function setViewportTriggers(injector: Injector, elementTriggers: ElementT
|
|||
|
||||
async function setTimerTriggers(injector: Injector, elementTriggers: ElementTrigger[]) {
|
||||
for (const elementTrigger of elementTriggers) {
|
||||
const registry = injector.get(DeferBlockRegistry);
|
||||
const registry = injector.get(DEFER_BLOCK_REGISTRY);
|
||||
const onInvoke = async () =>
|
||||
await incrementallyHydrateFromBlockName(
|
||||
injector,
|
||||
|
|
|
|||
|
|
@ -116,6 +116,9 @@
|
|||
{
|
||||
"name": "DEFER_BLOCK_ID"
|
||||
},
|
||||
{
|
||||
"name": "DEFER_BLOCK_REGISTRY"
|
||||
},
|
||||
{
|
||||
"name": "DEFER_BLOCK_STATE"
|
||||
},
|
||||
|
|
@ -143,9 +146,6 @@
|
|||
{
|
||||
"name": "DeferBlockInternalState"
|
||||
},
|
||||
{
|
||||
"name": "DeferBlockRegistry"
|
||||
},
|
||||
{
|
||||
"name": "DeferBlockState"
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue