/
hydration.ts
179 lines (166 loc) · 6.32 KB
/
hydration.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/**
* @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 {HttpTransferCacheOptions, ɵwithHttpTransferCache} from '@angular/common/http';
import {ENVIRONMENT_INITIALIZER, EnvironmentProviders, inject, makeEnvironmentProviders, NgZone, Provider, ɵConsole as Console, ɵformatRuntimeError as formatRuntimeError, ɵwithDomHydration as withDomHydration,} from '@angular/core';
import {RuntimeErrorCode} from './errors';
/**
* The list of features as an enum to uniquely type each `HydrationFeature`.
* @see {@link HydrationFeature}
*
* @publicApi
* @developerPreview
*/
export const enum HydrationFeatureKind {
NoHttpTransferCache,
HttpTransferCacheOptions,
}
/**
* Helper type to represent a Hydration feature.
*
* @publicApi
* @developerPreview
*/
export interface HydrationFeature<FeatureKind extends HydrationFeatureKind> {
ɵkind: FeatureKind;
ɵproviders: Provider[];
}
/**
* Helper function to create an object that represents a Hydration feature.
*/
function hydrationFeature<FeatureKind extends HydrationFeatureKind>(
ɵkind: FeatureKind, ɵproviders: Provider[] = [],
ɵoptions: unknown = {}): HydrationFeature<FeatureKind> {
return {ɵkind, ɵproviders};
}
/**
* Disables HTTP transfer cache. Effectively causes HTTP requests to be performed twice: once on the
* server and other one on the browser.
*
* @publicApi
* @developerPreview
*/
export function withNoHttpTransferCache():
HydrationFeature<HydrationFeatureKind.NoHttpTransferCache> {
// This feature has no providers and acts as a flag that turns off
// HTTP transfer cache (which otherwise is turned on by default).
return hydrationFeature(HydrationFeatureKind.NoHttpTransferCache);
}
/**
* The function accepts a an object, which allows to configure cache parameters,
* such as which headers should be included (no headers are included by default),
* wether POST requests should be cached or a callback function to determine if a
* particular request should be cached.
*
* @publicApi
* @developerPreview
*/
export function withHttpTransferCacheOptions(
options: HttpTransferCacheOptions,
): HydrationFeature<HydrationFeatureKind.HttpTransferCacheOptions> {
// This feature has no providers and acts as a flag to pass options to the HTTP transfer cache.
return hydrationFeature(
HydrationFeatureKind.HttpTransferCacheOptions, ɵwithHttpTransferCache(options));
}
/**
* Returns an `ENVIRONMENT_INITIALIZER` token setup with a function
* that verifies whether compatible ZoneJS was used in an application
* and logs a warning in a console if it's not the case.
*/
function provideZoneJsCompatibilityDetector(): Provider[] {
return [{
provide: ENVIRONMENT_INITIALIZER,
useValue: () => {
const ngZone = inject(NgZone);
// Checking `ngZone instanceof NgZone` would be insufficient here,
// because custom implementations might use NgZone as a base class.
if (ngZone.constructor !== NgZone) {
const console = inject(Console);
const message = formatRuntimeError(
RuntimeErrorCode.UNSUPPORTED_ZONEJS_INSTANCE,
'Angular detected that hydration was enabled for an application ' +
'that uses a custom or a noop Zone.js implementation. ' +
'This is not yet a fully supported configuration.');
// tslint:disable-next-line:no-console
console.warn(message);
}
},
multi: true,
}];
}
/**
* Sets up providers necessary to enable hydration functionality for the application.
*
* By default, the function enables the recommended set of features for the optimal
* performance for most of the applications. It includes the following features:
*
* * Reconciling DOM hydration. Learn more about it [here](guide/hydration).
* * [`HttpClient`](api/common/http/HttpClient) response caching while running on the server and
* transferring this cache to the client to avoid extra HTTP requests. Learn more about data caching
* [here](/guide/universal#caching-data-when-using-httpclient).
*
* These functions allow you to disable some of the default features or configure features
* * {@link withNoHttpTransferCache} to disable HTTP transfer cache
* * {@link withHttpTransferCacheOptions} to configure some HTTP transfer cache options
*
* @usageNotes
*
* Basic example of how you can enable hydration in your application when
* `bootstrapApplication` function is used:
* ```
* bootstrapApplication(AppComponent, {
* providers: [provideClientHydration()]
* });
* ```
*
* Alternatively if you are using NgModules, you would add `provideClientHydration`
* to your root app module's provider list.
* ```
* @NgModule({
* declarations: [RootCmp],
* bootstrap: [RootCmp],
* providers: [provideClientHydration()],
* })
* export class AppModule {}
* ```
*
* @see {@link withNoHttpTransferCache}
* @see {@link withHttpTransferCacheOptions}
*
* @param features Optional features to configure additional router behaviors.
* @returns A set of providers to enable hydration.
*
* @publicApi
* @developerPreview
*/
export function provideClientHydration(...features: HydrationFeature<HydrationFeatureKind>[]):
EnvironmentProviders {
const providers: Provider[] = [];
const featuresKind = new Set<HydrationFeatureKind>();
const hasHttpTransferCacheOptions =
featuresKind.has(HydrationFeatureKind.HttpTransferCacheOptions);
for (const {ɵproviders, ɵkind} of features) {
featuresKind.add(ɵkind);
if (ɵproviders.length) {
providers.push(ɵproviders);
}
}
if (typeof ngDevMode !== 'undefined' && ngDevMode &&
featuresKind.has(HydrationFeatureKind.NoHttpTransferCache) && hasHttpTransferCacheOptions) {
// TODO: Make this a runtime error
throw new Error(
'Configuration error: found both withHttpTransferCacheOptions() and withNoHttpTransferCache() in the same call to provideClientHydration(), which is a contradiction.');
}
return makeEnvironmentProviders([
(typeof ngDevMode !== 'undefined' && ngDevMode) ? provideZoneJsCompatibilityDetector() : [],
withDomHydration(),
((featuresKind.has(HydrationFeatureKind.NoHttpTransferCache) || hasHttpTransferCacheOptions) ?
[] :
ɵwithHttpTransferCache({})),
providers,
]);
}