Skip to content

Commit 5b0363c

Browse files
JeanMecheAndrewKushnir
authored andcommitted
refactor(core): warning when hydration trigger is used without hydration being enabled (angular#64185)
This replaces the error we were throwing before the change. This allows component with defer triggerrs to be used on both SSR'd and CSR. fixes angular#64184 PR Close angular#64185
1 parent 11b006e commit 5b0363c

File tree

4 files changed

+47
-34
lines changed

4 files changed

+47
-34
lines changed

packages/core/src/core_private_export.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ export {
101101
HydrationInfo as ɵHydrationInfo,
102102
readHydrationInfo as ɵreadHydrationInfo,
103103
SSR_CONTENT_INTEGRITY_MARKER as ɵSSR_CONTENT_INTEGRITY_MARKER,
104+
resetIncrementalHydrationEnabledWarnedForTests as ɵresetIncrementalHydrationEnabledWarnedForTests,
104105
} from './hydration/utils';
105106
export {
106107
CurrencyIndex as ɵCurrencyIndex,

packages/core/src/defer/instructions.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ import {
5252
trackTriggerForDebugging,
5353
} from './utils';
5454
import {DEHYDRATED_BLOCK_REGISTRY, DehydratedBlockRegistry} from './registry';
55-
import {assertIncrementalHydrationIsConfigured, assertSsrIdDefined} from '../hydration/utils';
55+
import {
56+
warnIncrementalHydrationNotConfigured,
57+
assertSsrIdDefined,
58+
isIncrementalHydrationEnabled,
59+
} from '../hydration/utils';
5660
import {ɵɵdeferEnableTimerScheduling, renderPlaceholder} from './rendering';
5761

5862
import {
@@ -136,15 +140,16 @@ export function ɵɵdefer(
136140
const tNode = declareNoDirectiveHostTemplate(lView, tView, index, null, 0, 0);
137141
const injector = lView[INJECTOR];
138142

143+
const incrementalHydrationEnabled = isIncrementalHydrationEnabled(injector);
139144
if (tView.firstCreatePass) {
140145
performanceMarkFeature('NgDefer');
141146

142147
if (ngDevMode) {
143148
if (typeof ngHmrMode !== 'undefined' && ngHmrMode) {
144149
logHmrWarning(injector);
145150
}
146-
if (hasHydrateTriggers(flags)) {
147-
assertIncrementalHydrationIsConfigured(injector);
151+
if (hasHydrateTriggers(flags) && !incrementalHydrationEnabled) {
152+
warnIncrementalHydrationNotConfigured();
148153
}
149154
}
150155

@@ -198,7 +203,7 @@ export function ɵɵdefer(
198203
setLDeferBlockDetails(lView, adjustedIndex, lDetails);
199204

200205
let registry: DehydratedBlockRegistry | null = null;
201-
if (ssrUniqueId !== null) {
206+
if (ssrUniqueId !== null && incrementalHydrationEnabled) {
202207
// Store this defer block in the registry, to have an access to
203208
// internal data structures from hydration runtime code.
204209
registry = injector.get(DEHYDRATED_BLOCK_REGISTRY);

packages/core/src/hydration/utils.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import {
3434
SerializedView,
3535
} from './interfaces';
3636
import {IS_INCREMENTAL_HYDRATION_ENABLED, JSACTION_BLOCK_ELEMENT_MAP} from './tokens';
37-
import {RuntimeError, RuntimeErrorCode} from '../errors';
37+
import {formatRuntimeError, RuntimeError, RuntimeErrorCode} from '../errors';
3838
import {DeferBlockTrigger, HydrateTriggerDetails} from '../defer/interfaces';
3939
import {hoverEventNames, interactionEventNames} from '../../primitives/defer/src/triggers';
4040
import {DEHYDRATED_BLOCK_REGISTRY} from '../defer/registry';
@@ -411,15 +411,23 @@ export function isIncrementalHydrationEnabled(injector: Injector): boolean {
411411
});
412412
}
413413

414+
let incrementalHydrationEnabledWarned = false;
415+
export function resetIncrementalHydrationEnabledWarnedForTests() {
416+
incrementalHydrationEnabledWarned = false;
417+
}
418+
414419
/** Throws an error if the incremental hydration is not enabled */
415-
export function assertIncrementalHydrationIsConfigured(injector: Injector) {
416-
if (!isIncrementalHydrationEnabled(injector)) {
417-
throw new RuntimeError(
418-
RuntimeErrorCode.MISCONFIGURED_INCREMENTAL_HYDRATION,
419-
'Angular has detected that some `@defer` blocks use `hydrate` triggers, ' +
420-
'but incremental hydration was not enabled. Please ensure that the `withIncrementalHydration()` ' +
421-
'call is added as an argument for the `provideClientHydration()` function call ' +
422-
'in your application config.',
420+
export function warnIncrementalHydrationNotConfigured(): void {
421+
if (!incrementalHydrationEnabledWarned) {
422+
incrementalHydrationEnabledWarned = true;
423+
console.warn(
424+
formatRuntimeError(
425+
RuntimeErrorCode.MISCONFIGURED_INCREMENTAL_HYDRATION,
426+
'Angular has detected that some `@defer` blocks use `hydrate` triggers, ' +
427+
'but incremental hydration was not enabled. Please ensure that the `withIncrementalHydration()` ' +
428+
'call is added as an argument for the `provideClientHydration()` function call ' +
429+
'in your application config.',
430+
),
423431
);
424432
}
425433
}

packages/platform-server/test/incremental_hydration_spec.ts

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
ɵJSACTION_BLOCK_ELEMENT_MAP as JSACTION_BLOCK_ELEMENT_MAP,
2525
ɵJSACTION_EVENT_CONTRACT as JSACTION_EVENT_CONTRACT,
2626
ɵgetDocument as getDocument,
27+
ɵresetIncrementalHydrationEnabledWarnedForTests as resetIncrementalHydrationEnabledWarnedForTests,
2728
ɵTimerScheduler as TimerScheduler,
2829
provideZoneChangeDetection,
2930
} from '@angular/core';
@@ -2823,7 +2824,7 @@ describe('platform-server partial hydration integration', () => {
28232824
});
28242825

28252826
describe('misconfiguration', () => {
2826-
it('should throw an error when `withIncrementalHydration()` is missing in SSR setup', async () => {
2827+
it('should log a warning when `withIncrementalHydration()` is missing in SSR setup', async () => {
28272828
@Component({
28282829
selector: 'app',
28292830
template: `
@@ -2839,17 +2840,15 @@ describe('platform-server partial hydration integration', () => {
28392840

28402841
// Empty list, `withIncrementalHydration()` is not included intentionally.
28412842
const hydrationFeatures = () => [];
2843+
const consoleSpy = spyOn(console, 'warn');
2844+
resetIncrementalHydrationEnabledWarnedForTests();
28422845

2843-
let producedError;
2844-
try {
2845-
await ssr(SimpleComponent, {envProviders: providers, hydrationFeatures});
2846-
} catch (error: unknown) {
2847-
producedError = error;
2848-
}
2849-
expect((producedError as Error).message).toContain('NG0508');
2846+
await ssr(SimpleComponent, {envProviders: providers, hydrationFeatures});
2847+
expect(consoleSpy).toHaveBeenCalledTimes(1);
2848+
expect(consoleSpy).toHaveBeenCalledWith(jasmine.stringMatching('NG0508'));
28502849
});
28512850

2852-
it('should throw an error when `withIncrementalHydration()` is missing in hydration setup', async () => {
2851+
it('should log a warning when `withIncrementalHydration()` is missing in hydration setup', async () => {
28532852
@Component({
28542853
selector: 'app',
28552854
template: `
@@ -2872,18 +2871,18 @@ describe('platform-server partial hydration integration', () => {
28722871

28732872
////////////////////////////////
28742873

2875-
let producedError;
2876-
try {
2877-
const doc = getDocument();
2878-
await prepareEnvironmentAndHydrate(doc, html, SimpleComponent, {
2879-
envProviders: [...providers, {provide: PLATFORM_ID, useValue: 'browser'}],
2880-
// Empty list, `withIncrementalHydration()` is not included intentionally.
2881-
hydrationFeatures: () => [],
2882-
});
2883-
} catch (error: unknown) {
2884-
producedError = error;
2885-
}
2886-
expect((producedError as Error).message).toContain('NG0508');
2874+
const consoleSpy = spyOn(console, 'warn');
2875+
resetIncrementalHydrationEnabledWarnedForTests();
2876+
2877+
const doc = getDocument();
2878+
await prepareEnvironmentAndHydrate(doc, html, SimpleComponent, {
2879+
envProviders: [...providers, {provide: PLATFORM_ID, useValue: 'browser'}],
2880+
// Empty list, `withIncrementalHydration()` is not included intentionally.
2881+
hydrationFeatures: () => [],
2882+
});
2883+
2884+
expect(consoleSpy).toHaveBeenCalledTimes(1);
2885+
expect(consoleSpy).toHaveBeenCalledWith(jasmine.stringMatching('NG0508'));
28872886
});
28882887
});
28892888
});

0 commit comments

Comments
 (0)