mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
refactor(platform-server): split zone/zoneless tests.
The Zone tests are a subset of tests that we still using the Zone CD provider.
This commit is contained in:
parent
63d8005703
commit
08ea105aa3
5 changed files with 729 additions and 705 deletions
|
|
@ -29,12 +29,21 @@ import {performanceMarkFeature} from '../util/performance';
|
|||
import {NgZone} from '../zone';
|
||||
import {withEventReplay} from './event_replay';
|
||||
|
||||
import {
|
||||
ChangeDetectionScheduler,
|
||||
NotificationSource,
|
||||
} from '../change_detection/scheduling/zoneless_scheduling';
|
||||
import {DEHYDRATED_BLOCK_REGISTRY, DehydratedBlockRegistry} from '../defer/registry';
|
||||
import {processAndInitTriggers} from '../defer/triggering';
|
||||
import {DOCUMENT} from '../document';
|
||||
import {DOC_PAGE_BASE_URL} from '../error_details_base_url';
|
||||
import {cleanupDehydratedViews} from './cleanup';
|
||||
import {
|
||||
enableClaimDehydratedIcuCaseImpl,
|
||||
enablePrepareI18nBlockForHydrationImpl,
|
||||
setIsI18nHydrationSupportEnabled,
|
||||
} from './i18n';
|
||||
import {gatherDeferBlocksCommentNodes} from './node_lookup_utils';
|
||||
import {
|
||||
IS_HYDRATION_DOM_REUSE_ENABLED,
|
||||
IS_I18N_HYDRATION_ENABLED,
|
||||
|
|
@ -52,11 +61,6 @@ import {
|
|||
verifySsrContentsIntegrity,
|
||||
} from './utils';
|
||||
import {enableFindMatchingDehydratedViewImpl} from './views';
|
||||
import {DEHYDRATED_BLOCK_REGISTRY, DehydratedBlockRegistry} from '../defer/registry';
|
||||
import {gatherDeferBlocksCommentNodes} from './node_lookup_utils';
|
||||
import {processAndInitTriggers} from '../defer/triggering';
|
||||
import {DOCUMENT} from '../document';
|
||||
import {DOC_PAGE_BASE_URL} from '../error_details_base_url';
|
||||
|
||||
/**
|
||||
* Indicates whether the hydration-related code was added,
|
||||
|
|
@ -277,6 +281,7 @@ export function withDomHydration(): EnvironmentProviders {
|
|||
{
|
||||
provide: APP_BOOTSTRAP_LISTENER,
|
||||
useFactory: () => {
|
||||
const scheduler = inject(ChangeDetectionScheduler);
|
||||
if (inject(IS_HYDRATION_DOM_REUSE_ENABLED)) {
|
||||
const appRef = inject(ApplicationRef);
|
||||
|
||||
|
|
@ -304,6 +309,8 @@ export function withDomHydration(): EnvironmentProviders {
|
|||
countBlocksSkippedByHydration(appRef.injector);
|
||||
printHydrationStats(appRef.injector);
|
||||
}
|
||||
// We need to schedule the execution of the render hooks because the hydration cleanup alters the DOM.
|
||||
scheduler.notify(NotificationSource.RenderHook);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
load("//tools:defaults.bzl", "angular_jasmine_test", "ts_project")
|
||||
load("//tools:defaults.bzl", "angular_jasmine_test", "ts_project", "zoneless_jasmine_test")
|
||||
|
||||
ts_project(
|
||||
name = "dom_utils",
|
||||
|
|
@ -65,6 +65,7 @@ ts_project(
|
|||
],
|
||||
)
|
||||
|
||||
# This target is meant to run with Zone.js as some test cases are shared between Zone & Zoneless.
|
||||
angular_jasmine_test(
|
||||
name = "test",
|
||||
data = [
|
||||
|
|
@ -73,7 +74,7 @@ angular_jasmine_test(
|
|||
],
|
||||
)
|
||||
|
||||
angular_jasmine_test(
|
||||
zoneless_jasmine_test(
|
||||
name = "event_replay_test",
|
||||
data = [
|
||||
":event_replay_test_lib",
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ import {
|
|||
PLATFORM_ID,
|
||||
Provider,
|
||||
provideZoneChangeDetection,
|
||||
provideZonelessChangeDetection,
|
||||
QueryList,
|
||||
signal,
|
||||
TemplateRef,
|
||||
ViewChild,
|
||||
ViewContainerRef,
|
||||
|
|
@ -2821,9 +2821,9 @@ describe('platform-server full application hydration integration', () => {
|
|||
selector: 'app',
|
||||
imports: [MyLazyCmp],
|
||||
template: `
|
||||
Visible: {{ isVisible }}.
|
||||
Visible: {{ isVisible() }}.
|
||||
|
||||
@defer (when isVisible) {
|
||||
@defer (when isVisible()) {
|
||||
<my-lazy-cmp />
|
||||
} @loading {
|
||||
Loading...
|
||||
|
|
@ -2835,19 +2835,21 @@ describe('platform-server full application hydration integration', () => {
|
|||
`,
|
||||
})
|
||||
class SimpleComponent {
|
||||
isVisible = false;
|
||||
isVisible = signal(false);
|
||||
pendingTasks = inject(PendingTasks);
|
||||
|
||||
ngOnInit() {
|
||||
const removeTask = this.pendingTasks.add();
|
||||
setTimeout(() => {
|
||||
// This changes the triggering condition of the defer block,
|
||||
// but it should be ignored and the placeholder content should be visible.
|
||||
this.isVisible = true;
|
||||
this.isVisible.set(true);
|
||||
removeTask();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const envProviders = [provideZoneChangeDetection() as any];
|
||||
const html = await ssr(SimpleComponent, {envProviders});
|
||||
const html = await ssr(SimpleComponent);
|
||||
|
||||
const ssrContents = getAppContents(html);
|
||||
expect(ssrContents).toContain('<app ngh');
|
||||
|
|
@ -2859,9 +2861,7 @@ describe('platform-server full application hydration integration', () => {
|
|||
|
||||
resetTViewsFor(SimpleComponent);
|
||||
|
||||
const appRef = await prepareEnvironmentAndHydrate(doc, html, SimpleComponent, {
|
||||
envProviders,
|
||||
});
|
||||
const appRef = await prepareEnvironmentAndHydrate(doc, html, SimpleComponent);
|
||||
const compRef = getComponentRef<SimpleComponent>(appRef);
|
||||
appRef.tick();
|
||||
|
||||
|
|
@ -4591,103 +4591,129 @@ describe('platform-server full application hydration integration', () => {
|
|||
expect(clientContents).not.toContain('<b>This is a SERVER-ONLY content</b>');
|
||||
});
|
||||
|
||||
it('should trigger change detection after cleanup (immediate)', async () => {
|
||||
const observedChildCountLog: number[] = [];
|
||||
[true, false].forEach((zoneless) => {
|
||||
it(`should trigger ${zoneless ? 'zoneless' : 'zone'} change detection after cleanup (immediate)`, async () => {
|
||||
const observedChildCountLog: number[] = [];
|
||||
|
||||
@Component({
|
||||
selector: 'app',
|
||||
imports: [NgIf],
|
||||
template: `
|
||||
<span *ngIf="isServer">This is a SERVER-ONLY content</span>
|
||||
<span *ngIf="!isServer">This is a CLIENT-ONLY content</span>
|
||||
`,
|
||||
})
|
||||
class SimpleComponent {
|
||||
isServer = isPlatformServer(inject(PLATFORM_ID));
|
||||
elementRef = inject(ElementRef);
|
||||
@Component({
|
||||
selector: 'app',
|
||||
imports: [NgIf],
|
||||
template: `
|
||||
<span *ngIf="isServer">This is a SERVER-ONLY content</span>
|
||||
<span *ngIf="!isServer">This is a CLIENT-ONLY content</span>
|
||||
`,
|
||||
})
|
||||
class SimpleComponent {
|
||||
isServer = isPlatformServer(inject(PLATFORM_ID));
|
||||
elementRef = inject(ElementRef);
|
||||
|
||||
constructor() {
|
||||
afterEveryRender(() => {
|
||||
observedChildCountLog.push(this.elementRef.nativeElement.childElementCount);
|
||||
});
|
||||
constructor() {
|
||||
afterEveryRender(() => {
|
||||
observedChildCountLog.push(this.elementRef.nativeElement.childElementCount);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
const envProviders = [provideZoneChangeDetection() as any];
|
||||
const html = await ssr(SimpleComponent, {envProviders});
|
||||
let ssrContents = getAppContents(html);
|
||||
const envProviders = zoneless ? [] : [provideZoneChangeDetection() as any];
|
||||
const html = await ssr(SimpleComponent, {envProviders});
|
||||
let ssrContents = getAppContents(html);
|
||||
|
||||
expect(ssrContents).toContain('<app ngh');
|
||||
expect(ssrContents).toContain('<app ngh');
|
||||
|
||||
resetTViewsFor(SimpleComponent);
|
||||
resetTViewsFor(SimpleComponent);
|
||||
|
||||
// Before hydration
|
||||
expect(observedChildCountLog).toEqual([]);
|
||||
// Before hydration
|
||||
expect(observedChildCountLog).toEqual([]);
|
||||
|
||||
const appRef = await prepareEnvironmentAndHydrate(doc, html, SimpleComponent, {
|
||||
envProviders,
|
||||
});
|
||||
await appRef.whenStable();
|
||||
const appRef = await prepareEnvironmentAndHydrate(doc, html, SimpleComponent, {
|
||||
envProviders,
|
||||
});
|
||||
await appRef.whenStable();
|
||||
|
||||
// afterRender should be triggered by:
|
||||
// 1.) Bootstrap
|
||||
// 2.) Microtask empty event
|
||||
// 3.) Stabilization + cleanup
|
||||
expect(observedChildCountLog).toEqual([2, 2, 1]);
|
||||
});
|
||||
|
||||
it('should trigger change detection after cleanup (deferred)', async () => {
|
||||
const observedChildCountLog: number[] = [];
|
||||
|
||||
@Component({
|
||||
selector: 'app',
|
||||
imports: [NgIf],
|
||||
template: `
|
||||
<span *ngIf="isServer">This is a SERVER-ONLY content</span>
|
||||
<span *ngIf="!isServer">This is a CLIENT-ONLY content</span>
|
||||
`,
|
||||
})
|
||||
class SimpleComponent {
|
||||
isServer = isPlatformServer(inject(PLATFORM_ID));
|
||||
elementRef = inject(ElementRef);
|
||||
|
||||
constructor() {
|
||||
afterEveryRender(() => {
|
||||
observedChildCountLog.push(this.elementRef.nativeElement.childElementCount);
|
||||
});
|
||||
|
||||
// Create a dummy promise to prevent stabilization
|
||||
new Promise<void>((resolve) => {
|
||||
setTimeout(resolve, 0);
|
||||
});
|
||||
if (zoneless) {
|
||||
// 1.) Bootstrap
|
||||
// 2.) After cleanup
|
||||
expect(observedChildCountLog).toEqual([2, 1]);
|
||||
} else {
|
||||
// afterRender should be triggered by:
|
||||
// 1.) Bootstrap
|
||||
// 2.) Microtask empty event
|
||||
// 3.) Stabilization + cleanup
|
||||
expect(observedChildCountLog).toEqual([2, 2, 1]);
|
||||
}
|
||||
}
|
||||
|
||||
const envProviders = [provideZoneChangeDetection() as any];
|
||||
const html = await ssr(SimpleComponent, {envProviders});
|
||||
let ssrContents = getAppContents(html);
|
||||
|
||||
expect(ssrContents).toContain('<app ngh');
|
||||
|
||||
resetTViewsFor(SimpleComponent);
|
||||
|
||||
// Before hydration
|
||||
expect(observedChildCountLog).toEqual([]);
|
||||
|
||||
const appRef = await prepareEnvironmentAndHydrate(doc, html, SimpleComponent, {
|
||||
envProviders,
|
||||
});
|
||||
|
||||
// afterRender should be triggered by:
|
||||
// 1.) Bootstrap
|
||||
// 2.) Microtask empty event
|
||||
expect(observedChildCountLog).toEqual([2, 2]);
|
||||
it(`should trigger ${zoneless ? 'zoneless' : 'zone'} change detection after cleanup (deferred)`, async () => {
|
||||
const observedChildCountLog: number[] = [];
|
||||
|
||||
await appRef.whenStable();
|
||||
@Component({
|
||||
selector: 'app',
|
||||
imports: [NgIf],
|
||||
template: `
|
||||
<span *ngIf="isServer">This is a SERVER-ONLY content</span>
|
||||
<span *ngIf="!isServer">This is a CLIENT-ONLY content</span>
|
||||
`,
|
||||
})
|
||||
class SimpleComponent {
|
||||
isServer = isPlatformServer(inject(PLATFORM_ID));
|
||||
elementRef = inject(ElementRef);
|
||||
|
||||
// afterRender should be triggered by:
|
||||
// 3.) Microtask empty event
|
||||
// 4.) Stabilization + cleanup
|
||||
expect(observedChildCountLog).toEqual([2, 2, 2, 1]);
|
||||
constructor() {
|
||||
afterEveryRender(() => {
|
||||
observedChildCountLog.push(this.elementRef.nativeElement.childElementCount);
|
||||
});
|
||||
|
||||
// Create a dummy promise to prevent stabilization
|
||||
inject(PendingTasks).run(
|
||||
async () =>
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(resolve, 0);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const envProviders = zoneless ? [] : [provideZoneChangeDetection() as any];
|
||||
const html = await ssr(SimpleComponent, {envProviders});
|
||||
let ssrContents = getAppContents(html);
|
||||
|
||||
expect(ssrContents).toContain('<app ngh');
|
||||
|
||||
resetTViewsFor(SimpleComponent);
|
||||
|
||||
// Before hydration
|
||||
expect(observedChildCountLog).toEqual([]);
|
||||
|
||||
const appRef = await prepareEnvironmentAndHydrate(doc, html, SimpleComponent, {
|
||||
envProviders,
|
||||
});
|
||||
|
||||
if (zoneless) {
|
||||
// afterRender should be triggered by:
|
||||
// 1.) Bootstrap
|
||||
expect(observedChildCountLog).toEqual([2]);
|
||||
} else {
|
||||
// afterRender should be triggered by:
|
||||
// 1.) Bootstrap
|
||||
// 2.) Microtask empty event
|
||||
expect(observedChildCountLog).toEqual([2, 2]);
|
||||
}
|
||||
|
||||
// Cleanup will happen when stable, it will also schedule another change detection run, so we need to wait for stability again.
|
||||
await appRef.whenStable();
|
||||
|
||||
await appRef.whenStable();
|
||||
|
||||
if (zoneless) {
|
||||
// afterRender should be triggered by:
|
||||
// 2.) After stablization & cleanup
|
||||
expect(observedChildCountLog).toEqual([2, 1]);
|
||||
} else {
|
||||
// afterRender should be triggered by:
|
||||
// 3.) Microtask empty event
|
||||
// 4.) Stabilization + cleanup
|
||||
expect(observedChildCountLog).toEqual([2, 2, 2, 2, 1]);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -6896,13 +6922,16 @@ describe('platform-server full application hydration integration', () => {
|
|||
// and the server: we use it to test the logic to cleanup
|
||||
// dehydrated views.
|
||||
isServer = isPlatformServer(inject(PLATFORM_ID));
|
||||
pendingTasks = inject(PendingTasks);
|
||||
ngOnInit() {
|
||||
setTimeout(() => {}, 100);
|
||||
const remove = this.pendingTasks.add();
|
||||
setTimeout(() => {
|
||||
remove();
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
const envProviders = [provideZoneChangeDetection() as any];
|
||||
const html = await ssr(SimpleComponent, {envProviders});
|
||||
const html = await ssr(SimpleComponent);
|
||||
let ssrContents = getAppContents(html);
|
||||
|
||||
expect(ssrContents).toContain('<app ngh');
|
||||
|
|
@ -6916,9 +6945,7 @@ describe('platform-server full application hydration integration', () => {
|
|||
expect(ssrContents).toContain('<b>This is NgSwitch SERVER-ONLY content</b>');
|
||||
|
||||
resetTViewsFor(SimpleComponent);
|
||||
const appRef = await prepareEnvironmentAndHydrate(doc, html, SimpleComponent, {
|
||||
envProviders,
|
||||
});
|
||||
const appRef = await prepareEnvironmentAndHydrate(doc, html, SimpleComponent);
|
||||
const compRef = getComponentRef<SimpleComponent>(appRef);
|
||||
appRef.tick();
|
||||
|
||||
|
|
@ -7629,46 +7656,6 @@ describe('platform-server full application hydration integration', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('zoneless', () => {
|
||||
it('should not produce "unsupported configuration" warnings for zoneless mode', async () => {
|
||||
@Component({
|
||||
selector: 'app',
|
||||
template: `
|
||||
<header>Header</header>
|
||||
<footer>Footer</footer>
|
||||
`,
|
||||
})
|
||||
class SimpleComponent {}
|
||||
|
||||
const html = await ssr(SimpleComponent);
|
||||
const ssrContents = getAppContents(html);
|
||||
|
||||
expect(ssrContents).toContain(`<app ${NGH_ATTR_NAME}`);
|
||||
|
||||
resetTViewsFor(SimpleComponent);
|
||||
|
||||
const appRef = await prepareEnvironmentAndHydrate(doc, html, SimpleComponent, {
|
||||
envProviders: [
|
||||
withDebugConsole(),
|
||||
provideZonelessChangeDetection() as unknown as Provider[],
|
||||
],
|
||||
});
|
||||
const compRef = getComponentRef<SimpleComponent>(appRef);
|
||||
appRef.tick();
|
||||
|
||||
// Make sure there are no extra logs in case zoneless mode is enabled.
|
||||
verifyHasNoLog(
|
||||
appRef,
|
||||
'NG05000: Angular detected that hydration was enabled for an application ' +
|
||||
'that uses a custom or a noop Zone.js implementation.',
|
||||
);
|
||||
|
||||
const clientRootNode = compRef.location.nativeElement;
|
||||
verifyAllNodesClaimedForHydration(clientRootNode);
|
||||
verifyClientAndSSRContentsMatch(ssrContents, clientRootNode);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Router', () => {
|
||||
it('should wait for lazy routes before triggering post-hydration cleanup', async () => {
|
||||
const ngZone = TestBed.inject(NgZone);
|
||||
|
|
@ -7764,7 +7751,6 @@ describe('platform-server full application hydration integration', () => {
|
|||
class SimpleComponent {}
|
||||
|
||||
const envProviders = [
|
||||
provideZonelessChangeDetection(),
|
||||
{provide: PlatformLocation, useClass: MockPlatformLocation},
|
||||
provideRouter(routes),
|
||||
] as unknown as Provider[];
|
||||
|
|
|
|||
|
|
@ -10,25 +10,38 @@ import {
|
|||
APP_ID,
|
||||
ApplicationRef,
|
||||
Component,
|
||||
ɵDEHYDRATED_BLOCK_REGISTRY as DEHYDRATED_BLOCK_REGISTRY,
|
||||
destroyPlatform,
|
||||
ɵgetDocument as getDocument,
|
||||
inject,
|
||||
Input,
|
||||
NgZone,
|
||||
ɵJSACTION_BLOCK_ELEMENT_MAP as JSACTION_BLOCK_ELEMENT_MAP,
|
||||
ɵJSACTION_EVENT_CONTRACT as JSACTION_EVENT_CONTRACT,
|
||||
PendingTasks,
|
||||
PLATFORM_ID,
|
||||
Provider,
|
||||
QueryList,
|
||||
ɵresetIncrementalHydrationEnabledWarnedForTests as resetIncrementalHydrationEnabledWarnedForTests,
|
||||
signal,
|
||||
ɵTimerScheduler as TimerScheduler,
|
||||
ViewChildren,
|
||||
ɵDEFER_BLOCK_DEPENDENCY_INTERCEPTOR,
|
||||
ɵDEHYDRATED_BLOCK_REGISTRY as DEHYDRATED_BLOCK_REGISTRY,
|
||||
ɵJSACTION_BLOCK_ELEMENT_MAP as JSACTION_BLOCK_ELEMENT_MAP,
|
||||
ɵJSACTION_EVENT_CONTRACT as JSACTION_EVENT_CONTRACT,
|
||||
ɵgetDocument as getDocument,
|
||||
ɵresetIncrementalHydrationEnabledWarnedForTests as resetIncrementalHydrationEnabledWarnedForTests,
|
||||
ɵTimerScheduler as TimerScheduler,
|
||||
provideZoneChangeDetection,
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
isPlatformServer,
|
||||
Location,
|
||||
ɵPLATFORM_BROWSER_ID as PLATFORM_BROWSER_ID,
|
||||
PlatformLocation,
|
||||
} from '@angular/common';
|
||||
import {MockPlatformLocation} from '@angular/common/testing';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {
|
||||
provideClientHydration,
|
||||
withEventReplay,
|
||||
withIncrementalHydration,
|
||||
} from '@angular/platform-browser';
|
||||
import {provideRouter, RouterLink, RouterOutlet, Routes} from '@angular/router';
|
||||
import {getAppContents, prepareEnvironmentAndHydrate, resetTViewsFor} from './dom_utils';
|
||||
import {
|
||||
clearConsole,
|
||||
|
|
@ -41,20 +54,6 @@ import {
|
|||
verifyNodeWasNotHydrated,
|
||||
withDebugConsole,
|
||||
} from './hydration_utils';
|
||||
import {
|
||||
isPlatformServer,
|
||||
Location,
|
||||
PlatformLocation,
|
||||
ɵPLATFORM_BROWSER_ID as PLATFORM_BROWSER_ID,
|
||||
} from '@angular/common';
|
||||
import {
|
||||
provideClientHydration,
|
||||
withEventReplay,
|
||||
withIncrementalHydration,
|
||||
} from '@angular/platform-browser';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {provideRouter, RouterLink, RouterOutlet, Routes} from '@angular/router';
|
||||
import {MockPlatformLocation} from '@angular/common/testing';
|
||||
|
||||
/**
|
||||
* Emulates a dynamic import promise.
|
||||
|
|
@ -1410,7 +1409,6 @@ describe('platform-server partial hydration integration', () => {
|
|||
): number => {
|
||||
onIdleCallbackQueue.set(id, callback);
|
||||
expect(idleCallbacksRequested).toBe(0);
|
||||
expect(NgZone.isInAngularZone()).toBe(true);
|
||||
idleCallbacksRequested++;
|
||||
return id++;
|
||||
};
|
||||
|
|
@ -1469,10 +1467,7 @@ describe('platform-server partial hydration integration', () => {
|
|||
}
|
||||
|
||||
const appId = 'custom-app-id';
|
||||
const providers = [
|
||||
{provide: APP_ID, useValue: appId},
|
||||
provideZoneChangeDetection() as any,
|
||||
];
|
||||
const providers = [{provide: APP_ID, useValue: appId}];
|
||||
const hydrationFeatures = () => [withIncrementalHydration()];
|
||||
|
||||
const html = await ssr(SimpleComponent, {envProviders: providers, hydrationFeatures});
|
||||
|
|
@ -2062,10 +2057,18 @@ describe('platform-server partial hydration integration', () => {
|
|||
this.value.set('end');
|
||||
}
|
||||
registry = inject(DEHYDRATED_BLOCK_REGISTRY);
|
||||
|
||||
constructor() {
|
||||
// TODO: Understand why this is needed to get the full rendering of the HTML
|
||||
// Without it, bindings aren't properly rendered in SSR and the test fails.
|
||||
// There was no issue with the zone based scheduler.
|
||||
const remove = inject(PendingTasks).add();
|
||||
setTimeout(() => remove(), 10);
|
||||
}
|
||||
}
|
||||
|
||||
const appId = 'custom-app-id';
|
||||
const providers = [{provide: APP_ID, useValue: appId}, provideZoneChangeDetection() as any];
|
||||
const providers = [{provide: APP_ID, useValue: appId}];
|
||||
const hydrationFeatures = () => [withIncrementalHydration()];
|
||||
|
||||
const html = await ssr(SimpleComponent, {envProviders: providers, hydrationFeatures});
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue