Skip to content

Commit

Permalink
refactor(platform-browser): remove withNoDomReuse function
Browse files Browse the repository at this point in the history
This commit removes the `withNoDomReuse` function to minimize public API. The `withNoDomReuse` function used to disable DOM reuse, which is the main feature of the `provideClientHydration()`.

The `withNoDomReuse()` function was in the "developer preview" mode, so the removal happens without prior deprecation.

BREAKING CHANGE:

The `withNoDomReuse()` function was removed from the public API. If you need to disable hydration, you can exclude the `provideClientHydration()` call from provider list in your application (which would disable hydration features for the entire application) or use `ngSkipHydration` attribute to disable hydration for particular components. See this guide for additional information: https://angular.io/guide/hydration#how-to-skip-hydration-for-particular-components.
  • Loading branch information
AndrewKushnir committed Oct 9, 2023
1 parent 7bfe207 commit 69cab96
Show file tree
Hide file tree
Showing 5 changed files with 7 additions and 148 deletions.
9 changes: 2 additions & 7 deletions goldens/public-api/platform-browser/index.md
Expand Up @@ -155,11 +155,9 @@ export interface HydrationFeature<FeatureKind extends HydrationFeatureKind> {
// @public
export const enum HydrationFeatureKind {
// (undocumented)
HttpTransferCacheOptions = 2,
HttpTransferCacheOptions = 1,
// (undocumented)
NoDomReuseFeature = 0,
// (undocumented)
NoHttpTransferCache = 1
NoHttpTransferCache = 0
}

// @public @deprecated
Expand Down Expand Up @@ -260,9 +258,6 @@ export const VERSION: Version;
// @public
export function withHttpTransferCacheOptions(options: HttpTransferCacheOptions): HydrationFeature<HydrationFeatureKind.HttpTransferCacheOptions>;

// @public
export function withNoDomReuse(): HydrationFeature<HydrationFeatureKind.NoDomReuseFeature>;

// @public
export function withNoHttpTransferCache(): HydrationFeature<HydrationFeatureKind.NoHttpTransferCache>;

Expand Down
49 changes: 2 additions & 47 deletions packages/platform-browser/src/hydration.ts
Expand Up @@ -19,7 +19,6 @@ import {RuntimeErrorCode} from './errors';
* @developerPreview
*/
export const enum HydrationFeatureKind {
NoDomReuseFeature,
NoHttpTransferCache,
HttpTransferCacheOptions,
}
Expand All @@ -44,46 +43,6 @@ function hydrationFeature<FeatureKind extends HydrationFeatureKind>(
return {ɵkind, ɵproviders};
}

/**
* Disables DOM nodes reuse during hydration. Effectively makes
* Angular re-render an application from scratch on the client.
*
* When this option is enabled, make sure that the initial navigation
* option is configured for the Router as `enabledBlocking` by using the
* `withEnabledBlockingInitialNavigation` in the `provideRouter` call:
*
* ```
* bootstrapApplication(RootComponent, {
* providers: [
* provideRouter(
* // ... other features ...
* withEnabledBlockingInitialNavigation()
* ),
* provideClientHydration(withNoDomReuse())
* ]
* });
* ```
*
* This would ensure that the application is rerendered after all async
* operations in the Router (such as lazy-loading of components,
* waiting for async guards and resolvers) are completed to avoid
* clearing the DOM on the client too soon, thus causing content flicker.
*
* The use of this function is discouraged, because it disables DOM nodes reuse during
* hydration.
*
* @see {@link provideRouter}
* @see {@link withEnabledBlockingInitialNavigation}
*
* @publicApi
* @developerPreview
*/
export function withNoDomReuse(): HydrationFeature<HydrationFeatureKind.NoDomReuseFeature> {
// This feature has no providers and acts as a flag that turns off
// non-destructive hydration (which otherwise is turned on by default).
return hydrationFeature(HydrationFeatureKind.NoDomReuseFeature);
}

/**
* Disables HTTP transfer cache. Effectively causes HTTP requests to be performed twice: once on the
* server and other one on the browser.
Expand Down Expand Up @@ -146,17 +105,14 @@ function provideZoneJsCompatibilityDetector(): Provider[] {
* 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. You can enable/disable features by
* passing special functions (from the `HydrationFeatures` set) as arguments to the
* `provideClientHydration` function. It includes the following features:
* 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 withNoDomReuse} to disable DOM nodes reuse during hydration
* * {@link withNoHttpTransferCache} to disable HTTP transfer cache
* * {@link withHttpTransferCacheOptions} to configure some HTTP transfer cache options
*
Expand All @@ -181,7 +137,6 @@ function provideZoneJsCompatibilityDetector(): Provider[] {
* export class AppModule {}
* ```
*
* @see {@link withNoDomReuse}
* @see {@link withNoHttpTransferCache}
* @see {@link withHttpTransferCacheOptions}
*
Expand Down Expand Up @@ -215,7 +170,7 @@ export function provideClientHydration(...features: HydrationFeature<HydrationFe

return makeEnvironmentProviders([
(typeof ngDevMode !== 'undefined' && ngDevMode) ? provideZoneJsCompatibilityDetector() : [],
(featuresKind.has(HydrationFeatureKind.NoDomReuseFeature) ? [] : withDomHydration()),
withDomHydration(),
((featuresKind.has(HydrationFeatureKind.NoHttpTransferCache) || hasHttpTransferCacheOptions) ?
[] :
ɵwithHttpTransferCache({})),
Expand Down
2 changes: 1 addition & 1 deletion packages/platform-browser/src/platform-browser.ts
Expand Up @@ -78,7 +78,7 @@ export {REMOVE_STYLES_ON_COMPONENT_DESTROY} from './dom/dom_renderer';
export {EVENT_MANAGER_PLUGINS, EventManager, EventManagerPlugin} from './dom/events/event_manager';
export {HAMMER_GESTURE_CONFIG, HAMMER_LOADER, HammerGestureConfig, HammerLoader, HammerModule} from './dom/events/hammer_gestures';
export {DomSanitizer, SafeHtml, SafeResourceUrl, SafeScript, SafeStyle, SafeUrl, SafeValue} from './security/dom_sanitization_service';
export {HydrationFeature, provideClientHydration, HydrationFeatureKind, withNoDomReuse, withHttpTransferCacheOptions, withNoHttpTransferCache} from './hydration';
export {HydrationFeature, provideClientHydration, HydrationFeatureKind, withHttpTransferCacheOptions, withNoHttpTransferCache} from './hydration';

export * from './private_export';
export {VERSION} from './version';
39 changes: 1 addition & 38 deletions packages/platform-server/test/hydration_spec.ts
Expand Up @@ -16,7 +16,7 @@ import {SSR_CONTENT_INTEGRITY_MARKER} from '@angular/core/src/hydration/utils';
import {getComponentDef} from '@angular/core/src/render3/definition';
import {NoopNgZone} from '@angular/core/src/zone/ng_zone';
import {TestBed} from '@angular/core/testing';
import {bootstrapApplication, HydrationFeature, HydrationFeatureKind, provideClientHydration, withNoDomReuse} from '@angular/platform-browser';
import {bootstrapApplication, HydrationFeature, HydrationFeatureKind, provideClientHydration} from '@angular/platform-browser';
import {provideRouter, RouterOutlet, Routes} from '@angular/router';

import {provideServerRendering} from '../public_api';
Expand Down Expand Up @@ -310,43 +310,6 @@ describe('platform-server hydration integration', () => {
return bootstrapApplication(component, {providers});
}

describe('public API', () => {
it('should allow to disable DOM hydration using `withNoDomReuse` feature', async () => {
@Component({
standalone: true,
selector: 'app',
template: `
<header>Header</header>
<main>This is hydrated content in the main element.</main>
<footer>Footer</footer>
`,
})
class SimpleComponent {
}

const html =
await ssr(SimpleComponent, undefined, [withDebugConsole()], [withNoDomReuse()]);
const ssrContents = getAppContents(html);

// There should be no `ngh` annotations.
expect(ssrContents).not.toContain(`<app ${NGH_ATTR_NAME}`);

resetTViewsFor(SimpleComponent);

const appRef =
await hydrate(html, SimpleComponent, [withDebugConsole()], [withNoDomReuse()]);
const compRef = getComponentRef<SimpleComponent>(appRef);
appRef.tick();

// Make sure there is no hydration-related message in a console.
verifyHasNoLog(appRef, 'Angular hydrated');

const clientRootNode = compRef.location.nativeElement;
verifyNoNodesWereClaimedForHydration(clientRootNode);
verifyClientAndSSRContentsMatch(ssrContents, clientRootNode);
});
});

describe('annotations', () => {
it('should add hydration annotations to component host nodes during ssr', async () => {
@Component({
Expand Down
56 changes: 1 addition & 55 deletions packages/platform-server/test/integration_spec.ts
Expand Up @@ -15,7 +15,7 @@ import {ApplicationConfig, ApplicationRef, Component, destroyPlatform, Environme
import {SSR_CONTENT_INTEGRITY_MARKER} from '@angular/core/src/hydration/utils';
import {InitialRenderPendingTasks} from '@angular/core/src/initial_render_pending_tasks';
import {TestBed} from '@angular/core/testing';
import {bootstrapApplication, BrowserModule, provideClientHydration, Title, withNoDomReuse, withNoHttpTransferCache} from '@angular/platform-browser';
import {bootstrapApplication, BrowserModule, provideClientHydration, Title, withNoHttpTransferCache} from '@angular/platform-browser';
import {BEFORE_APP_SERIALIZED, INITIAL_CONFIG, platformServer, PlatformState, provideServerRendering, renderModule, ServerModule} from '@angular/platform-server';
import {provideRouter, RouterOutlet, Routes} from '@angular/router';
import {Observable} from 'rxjs';
Expand Down Expand Up @@ -910,60 +910,6 @@ describe('platform-server integration', () => {
expect(output).toMatch(/ng-server-context="ssg\|httpcache,hydration"/);
});

it('should include a set of features into `ng-server-context` attribute ' +
'(excluding disabled hydration feature)',
async () => {
const options = {
document: doc,
};
const providers = [{
provide: SERVER_CONTEXT,
useValue: 'ssg',
}];
@Component({
standalone: true,
selector: 'app',
template: `<div>Works!</div>`,
})
class SimpleApp {
}

const bootstrap = renderApplication(
getStandaloneBoostrapFn(SimpleApp, [provideClientHydration(withNoDomReuse())]),
{...options, platformProviders: providers});
const output = await bootstrap;
// Dom hydration is disabled, so it should not be included.
expect(output).toMatch(/ng-server-context="ssg\|httpcache"/);
});

it('should not include features into `ng-server-context` attribute ' +
'when all features are disabled',
async () => {
const options = {
document: doc,
};
const providers = [{
provide: SERVER_CONTEXT,
useValue: 'ssg',
}];
@Component({
standalone: true,
selector: 'app',
template: `<div>Works!</div>`,
})
class SimpleApp {
}

const bootstrap = renderApplication(
getStandaloneBoostrapFn(
SimpleApp,
[provideClientHydration(withNoDomReuse(), withNoHttpTransferCache())]),
{...options, platformProviders: providers});
const output = await bootstrap;
// All features were disabled, so none of them are included.
expect(output).toMatch(/ng-server-context="ssg"/);
});

it('should handle false values on attributes', async () => {
const options = {document: doc};
const bootstrap = isStandalone ? renderApplication(MyHostComponentStandalone, options) :
Expand Down

0 comments on commit 69cab96

Please sign in to comment.