Commit graph

159 commits

Author SHA1 Message Date
Alan Agius
06452af31f fix(platform-server): remove dependency on @angular/platform-browser-dynamic (#50064)
Using `@angular/platform-browser-dynamic` is no longer required for JIT scenarios with Ivy. Instead `@angular/compiler` should be imported instead.

This change is part of the effort to reduce the server bundles sizes, which is needed to support cloud workers.

BREAKING CHANGE:
Users that are using SSR with JIT mode will now need to add  `import to @angular/compiler` before bootstrapping the application.

**NOTE:** this does not effect users using the Angular CLI.

PR Close #50064
2023-05-01 07:50:03 -07:00
Jessica Janiuk
1090bf870f refactor(core): improve error message when dom node is not found (#49977)
This adds context to the error message in the case that a DOM node is not found during the hydration process. It outputs the expected DOM structure based on the lView and tNode rather than an unhelpful text message.

PR Close #49977
2023-04-25 09:29:47 -07:00
Andrew Kushnir
3bcbfecb78 refactor(platform-browser): log a warning when a custom or a noop ZoneJS is used with hydration (#49944)
Hydration relies on a signal from ZoneJS when it becomes stable inside an application, so that Angular can start serialization process on the server or post-hydration cleanup on the client (to remove DOM nodes that remained unclaimed).

Providing a custom or a "noop" ZoneJS implementation may lead to a different timing of the "stable" event, thus triggering the serialization or the cleanup too early or too late. This is not yet a fully supported configuration.

This commit adds a warning (non-blocking) for those cases.

PR Close #49944
2023-04-23 18:23:28 -07:00
Andrew Kushnir
bbc2efcda2 refactor(core): hydrate components of the same type used with and without ngSkipHydration (#49943)
This commit updates hydration logic to hanlde a case when the same component is used multiple times in a template and in some of those cases, component is opted-out of hydration, for example:

```
<cmp ngSkipHydration />
<cmp />
```

Previously, the first occurrence of the `<cmp>` would result in storing the `ssrId` on a TView as `null` (since hydration is disabled for the component) and the second component instance reused the `null` as a value, thus also skipping hydration.

With the changes from this commit, the `ssrId` would be set when we come across a hydratable instance. We also make sure that the `ssrId` value never changes after we first set it to a non-`null` value.

PR Close #49943
2023-04-20 14:50:32 -07:00
Andrew Kushnir
338c7d9125 test(core): adding extra tests for hydration of view containers located after <ng-content> slots (#49920)
This commit adds extra tests to verify a couple additional use-cases related to view containers located after <ng-content> slots.

PR Close #49920
2023-04-19 14:26:43 +00:00
Andrew Kushnir
81ef9c327d refactor(core): handle empty projection slots within <ng-container> during hydration (#49920)
This commit updates hydration logic to handle cases when there are projection slots present in a template inside of an `<ng-container>` and when there are regular elements follow an <ng-content> slot (see tests for additional information). With this combination, the logic that annotates regular element locations should fallback to calculating a path from a reference node to that node. In case of an <ng-container>, the comment node is located *after* the node that needs an annotation. An existing logic was mistakenly returning an empty path, which was represented as a pointer to teh reference node. This commit fixes that and triggers a fallback to using a component host node as a reference in this case.

Resolves #49918.

PR Close #49920
2023-04-19 14:26:43 +00:00
Andrew Kushnir
5efd4fff57 refactor(core): insert special marker only when text node content is an empty string (#49877)
Empty text nodes are not present in the server-rendered HTML output, thus we inject a special marker
at a text node location to later restore an empty text node at the client. Currently, we treat text nodes with spaces as "empty" as well, however those spaces are present in the HTML and text nodes are created in a browser. Adding extra annotation in this case results in extra text nodes created on the client and may trigger hydration issues. This commit updates the code to avoid treating text nodes with spaces as "empty".

PR Close #49877
2023-04-18 19:04:28 +00:00
Alan Agius
3659e035f7 test: refactor platform-server tests to use async/await (#49855)
This commit changes the platform-server integration tests to use async/await instead of waitForAsync.

PR Close #49855
2023-04-17 14:07:34 +00:00
Andrew Kushnir
d994f8520c fix(core): include inner ViewContainerRef anchor nodes into ViewRef.rootNodes output (#49867)
Currently, the `ViewRef.rootNodes` output is missing anchor (comment) nodes for inner `ViewContainerRef`s,
when an achor node was created for that instance of a `ViewContainerRef` (which happens in all cases except
when an <ng-container> was used as a host for a view container).

This issue affects hydration logic, which relies on the number of root nodes within a view to properly determine
segments in DOM that belong to a particular view.

Resolves #49849.

PR Close #49867
2023-04-17 13:35:58 +00:00
Alan Agius
8c3b92cfb3 refactor(platform-server): simplify _render method (#49840)
This commits simplifies the `_render` method by using async/await.

PR Close #49840
2023-04-14 15:28:41 -04:00
Andrew Kushnir
7ee542d263 refactor(platform-server): include info about enabled features into ng-server-context (#49773)
This commit updates the logic that adds the "ng-server-context" attribute to the root elements to also include information about SSR feature enabled got an application.

PR Close #49773
2023-04-11 12:46:09 -07:00
Andrew Kushnir
83262dc0f9 refactor(core): do not enable hydration when server response was incorrect (#49750)
This commit updates the logic to avoid enabling hydration in case server response doesn't contain hydration-related info serialized. It can happen when `provideClientHydration()` call only happens on the client, but not on the server.

PR Close #49750
2023-04-10 09:03:20 -07:00
Andrew Kushnir
fe34de47bf refactor(core): add a warning when hydration annotation is missing in server response (#49743)
This commit updates the logic to detect a situation when hydration support was enabled only on the client. If that happens, Angular produces a warning in a console with a link to the error guide.

PR Close #49743
2023-04-07 09:41:55 -07:00
Andrew Kushnir
e08d6797ad refactor(core): skip hydration for components that use ShadowDom encapsulation (#49722)
The Domino DOM emulation library doesn't support shadow DOM. For such components we can not guarantee that client and server representations would match perfectly. To avoid hydration mismatch errors, such components are opted out of hydration.

PR Close #49722
2023-04-06 10:59:26 -07:00
Andrew Kushnir
5bf2b7da6f refactor(core): skip hydration for components that use i18n (instead of throwing an error) (#49722)
Currently, non-destructive hydration for i18n blocks is not supported (but support is coming!).
This commit updates the serialization logic from throwing an error when it comes across an i18n
block to annotating a component with a skip hydration flag.

PR Close #49722
2023-04-06 10:59:26 -07:00
Alan Agius
4f3abbcf93 refactor(platform-server): remove ServerRendererFactory2 and EmulatedEncapsulationServerRenderer2 (#49630)
These methods are no longer required following the fixes in https://github.com/angular/domino/pull/14/

PR Close #49630
2023-04-05 11:42:57 -07:00
Alan Agius
81e7d15ef6 feat(platform-browser): enable HTTP request caching when using provideClientHydration (#49699)
This commit adds support by default for HTTP caching when using `provideClientHydration`. Users can opt-out of this behaviour by using the `withoutHttpTransferCache` feature.

```ts
import {
  bootstrapApplication,
  provideClientHydration,
  withNoHttpTransferCache,
} from '@angular/platform-browser';
// ...
bootstrapApplication(RootCmp, {
  providers: [provideClientHydration(withNoHttpTransferCache())]
});
```

PR Close #49699
2023-04-04 15:04:03 -07:00
Andrew Kushnir
761e02d912 feat(platform-browser): add a public API function to enable non-destructive hydration (#49666)
This commit adds the `provideClientHydration` function to the public API. This function can be used to enable the non-destructive Angular hydration.

Important note: the non-destructive hydration feature is in Developer Preview mode, learn more about it at https://angular.io/guide/releases#developer-preview.

Before you can get started with hydration, you must have a server side rendered (SSR) application. Follow the [Angular Universal Guide](https://angular.io/guide/universal) to enable server side rendering first. Once you have SSR working with your application, you can enable hydration by visiting your main app component or module and importing `provideClientHydration` from `@angular/platform-browser`. You'll then add that provider to your app's bootstrapping providers list.

```typescript
import {
  bootstrapApplication,
  provideClientHydration,
} from '@angular/platform-browser';
// ...
bootstrapApplication(RootCmp, {
  providers: [provideClientHydration()]
});
```

Alternatively if you are using NgModules, you would add `provideClientHydration` to your root app module's provider list.

```typescript
import {provideClientHydration} from '@angular/platform-browser';
import {NgModule} from '@angular/core';

@NgModule({
  declarations: [RootCmp],
  exports: [RootCmp],
  bootstrap: [RootCmp],
  providers: [provideClientHydration()],
})
export class AppModule {}
```

You can confirm hydration is enabled by opening Developer Tools in your browser and viewing the console. You should see a message that includes hydration-related stats, such as the number of components and nodes hydrated.

Co-authored-by: jessicajaniuk <72768744+jessicajaniuk@users.noreply.github.com>
Co-authored-by: alan-agius4 <17563226+alan-agius4@users.noreply.github.com>

PR Close #49666
2023-04-03 22:13:47 -07:00
Andrew Kushnir
61bedaf930 refactor(core): handle a case when ngSkipHydration is applied to the root node of an application (#49675)
This commit updates the logic to handle a case when the `ngSkipHydration` attribute is applied to the root node of an app. In this case, the hydration info should not be serialized and the contents of the app on the client should be cleared up before initial rendering.

PR Close #49675
2023-04-03 19:11:47 -07:00
Alan Agius
7870fb07fe feat(platform-server): rename provideServerSupport to provideServerRendering (#49678)
This commit renames `provideServerSupport` to `provideServerRendering`.

PR Close #49678
2023-04-03 15:00:13 -07:00
Andrew Kushnir
d786856c46 refactor(core): output hydration stats into a console in dev mode (#49617)
This commit adds a logic to output basic hydration stats into a console. This is also helpful to ensure that hydration is enabled and works.

PR Close #49617
2023-03-30 09:42:05 -07:00
Alan Agius
427b5fc2a2 test: update platform-server integration test expected CSS (#49461)
This commit update the expected output due to changes in Domino.

PR Close #49461
2023-03-30 09:40:31 -07:00
Alan Agius
c024574f46 feat(core): expose makeStateKey, StateKey and TransferState (#49563)
This commits adds `makeStateKey`, `StateKey` and  `TransferState` methods in `@angular/core` as public API and deprecated the same exported symbols in `@angular/platform-browser`.

DEPRECATED:  `makeStateKey`, `StateKey` and  `TransferState` exports have been moved from `@angular/platform-browser` to `@angular/core`. Please update the imports.

```diff
- import {makeStateKey, StateKey, TransferState} from '@angular/platform-browser';
+ import {makeStateKey, StateKey, TransferState} from '@angular/core';
```

PR Close #49563
2023-03-29 10:18:02 -07:00
Alan Agius
e99460865e refactor(platform-server): deprecate useAbsoluteUrl and baseUrl (#49546)
These two options where created for a feature which was never completed. https://github.com/angular/universal/pull/1860

Eventually these options should be added to `withTransferCache` HTTP logic.

DEPRECATED: `PlatformConfig.baseUrl` and `PlatformConfig.useAbsoluteUrl` platform-server config options  are deprecated as these were not used.

PR Close #49546
2023-03-29 09:13:41 -07:00
Alan Agius
45a6ac09fd fix(http): force macro task creation during HTTP request (#49546)
This commit adds a background macrotask when an XHR request is performed. The macrotask is started during `loadstart` and ended during `loadend` event.

The macrotask is needed so that the application is not stabilized during HTTP calls. This is important for server rendering, as the application is rendering when the application is stabilized.
The application is stabilized when there are no longer pending Macro and Micro tasks intercepted by Zone.js, Since an XHR request is none of these, we create a background macrotask so that Zone.js is
made aware that there is something pending.

Prior to this change, we patched the `HttpHandler` in `@angular/platform-server` but this is not enough, as there can be multiple `HttpHandler` in an application, example when importing `HttpClient` in a lazy loaded component/module.
Which causes a new unpatched instance of `HttpHandler` to be created in the child injector which is not intercepted by Zone.js and thus the application is stabalized and rendered before the XHR request is finalized.

NB: Zone.js is fundamental for SSR and currently, it's not possible to do SSR without it.

Closes: #49425

PR Close #49546
2023-03-29 09:13:41 -07:00
Andrew Kushnir
478c5ac150 refactor(core): internal tracker of pending tasks during initial rendering (#49576)
This commit implements a simple tracker of the pending tasks during initial rendering. The class allows adding and removing tasks from the set. The class also exposes a promise that gets resolved once the last task is removed.

This tracker is needed to keep track of ongoing processes like Router navigation (and potentially HTTP requests) and acts as a signaling mechanism to SSR and hydration that the application is in the "stable" state and a serialization can be performed.

This class would also act as a future replacement for the `ApplicationRef.isStable` for zoneless applications.

PR Close #49576
2023-03-28 16:19:31 -07:00
Andrew Kushnir
22688b8ff3 refactor(core): handle <ng-content> with *ngIf during hydration (#49590)
This commit updates the serialization logic to avoid serializing a path for a node that was content projected (based on template information), but is not present in the DOM. This can happen if a <ng-content> is used with the *ngIf="false", for example: `<ng-content *ngIf="false" />`.

PR Close #49590
2023-03-27 12:53:12 -07:00
Andrew Kushnir
f1d3be3dee refactor(core): only annotate disconnected nodes in content projection (#49549)
Previously, we've annotated all disconnected DOM nodes, even if they are not used in content projection. However, this situation is only possible in content projection and if it happens in other cases (for example, when a node was removed using direct DOM manipulations), this should be a mismatch error.

PR Close #49549
2023-03-23 13:55:38 -07:00
Jessica Janiuk
0851bd5283 refactor(core): Improve hydration error handling (#49502)
This adds user friendly error messages outlining exactly where hydration
mismatches occur and what was expected with easy to read stringified
DOM. It also includes a pointer to exactly where the mismatch happened
and lets the user know what was expected.

PR Close #49502
2023-03-22 11:47:41 -07:00
Andrew Kushnir
8ea1fb7396 refactor(core): exclude disconnected nodes from hydration (#49471)
This commit updates the hydration logic to handle situations where DOM nodes might end up
being disconnected from the DOM tree. We serialize ids of those nodes into the hydration
state transfer data and use the information to switch from hydration to the regular "creation
mode" at runtime.

This situation may happen during the content projection, when some nodes don't make it
into one of the content projection slots (for example, when there is no default
<ng-content /> slot in projector component's template).

Note: we leverage the fact that we have this information available in the DOM emulation
layer (in Domino) for now. Longer-term solution should not rely on the DOM emulation and
only use internal data structures and state to compute this information.

PR Close #49471
2023-03-22 10:04:56 -07:00
Alan Agius
41f27ad086 refactor(platform-server): remove renderApplication overload that accepts a component (#49463)
This commit removes the `renderApplication` overload that accepts a root component as the first parameter.

BREAKING CHANGE:

`renderApplication` method no longer accepts a root component as first argument. Instead, provide a bootstrapping function that returns a `Promise<ApplicationRef>`.

Before
```ts
const output: string = await renderApplication(RootComponent, options);
```

Now
```ts
const bootstrap = () => bootstrapApplication(RootComponent, appConfig);
const output: string = await renderApplication(bootstrap, options);
```

PR Close #49463
2023-03-22 16:40:31 +01:00
Andrew Kushnir
504bd992ce refactor(core): add a note that hydration for i18n blocks is not yet supported (#49497)
This commit updates the serialization logic to detect a situation when i18n was used for a template and throw an error to indicate that hydration for i18n blocks is not yet supported.

Hydration for i18n blocks will be added in follow up versions.

PR Close #49497
2023-03-21 19:28:41 +01:00
Andrew Kushnir
a94b66f432 refactor(core): avoid ngSkipHydration on nodes other than component host ones (#49500)
Angular Hydration uses Components as a hydration boundary, i.e. you can enable/disable hydration on per-component basis. This commit enforces that the `ngSkipHydration` can only be applied on component host nodes (an error if thrown otherwise).

PR Close #49500
2023-03-21 18:59:25 +01:00
Andrew Kushnir
a0c289cbac refactor(core): avoid repeated views in serialized data (#49475)
This commit updates the serialization logic to recognized similar repeated views and instead of including the same info over and over again, a special field is added to the serialized view object with a number of repetitions. The hydration logic also recognizes the flag and creates the necessary number of dehydrated views in a container.

This optimization should help minimize the amount of extra annotations required for cases like *ngFor with large number of items.

PR Close #49475
2023-03-21 18:40:29 +01:00
Andrew Kushnir
3ef5d87408 refactor(core): post-hydration cleanup of unclaimed views (#49455)
This commit adds a logic to remove all views that were not cleaimed during the hydration. The process is started once the ApplicationRef becomes stable on the client (which matches the timing of serialization on the server).

PR Close #49455
2023-03-21 18:17:41 +01:00
Andrew Kushnir
ced237693a refactor(core): adding hydration for content projection (#49454)
This commit adds serialization and hydration logic for content projection.

While hydration for regular elements relies on their location in the TNode tree, the content projection may move elements around, so in order to hydrate them correcty, the runtime needs some extra information. This commit adds a serialization logic that adds element locations (instructions on how to navigate to a particular element from another known location of other element) into the hydration state for the following cases:

- when a TNode is a first element in projection segment (other nodes are linked from that node)
- when a TNode's next sibling is different before and after projection (we serialize extra info about the template-based sibling)
- when a TNode's previous sibling was a content projection (i.e. `<ng-content>` slot), because we can not rely on the previous element in this case (projection happens at a later point)

PR Close #49454
2023-03-21 17:42:53 +01:00
Pawel Kozlowski
81b9e858a8 Revert "refactor(core): adding hydration for content projection (#49454)" (#49511)
This reverts commit 7885f35fd6.

PR Close #49511
2023-03-21 13:51:14 +01:00
Andrew Kushnir
7885f35fd6 refactor(core): adding hydration for content projection (#49454)
This commit adds serialization and hydration logic for content projection.

While hydration for regular elements relies on their location in the TNode tree, the content projection may move elements around, so in order to hydrate them correcty, the runtime needs some extra information. This commit adds a serialization logic that adds element locations (instructions on how to navigate to a particular element from another known location of other element) into the hydration state for the following cases:

- when a TNode is a first element in projection segment (other nodes are linked from that node)
- when a TNode's next sibling is different before and after projection (we serialize extra info about the template-based sibling)
- when a TNode's previous sibling was a content projection (i.e. `<ng-content>` slot), because we can not rely on the previous element in this case (projection happens at a later point)

PR Close #49454
2023-03-21 09:44:03 +01:00
Alan Agius
9636910c01 refactor(platform-browser): rename ng-app style attribute to ng-app-id (#49424)
`ng-app` is an AngularJS attribute, see https://docs.angularjs.org/api/ng/directive/ngApp. Using this attribute on a non AngularJS element can cause DI issues in AngularJS when running an AngularJS and Angular application on the same page.

As such, we avoid such problems the Angular `ng-app` attribute is renamed to `ng-app-id`.

PR Close #49424
2023-03-17 10:46:03 +01:00
Alan Agius
8cf1baee2a refactor(platform-server): remove ServerStylesHost (#49424)
With the recent changes and refactors of `dom_renderer` having a separate `ServerStylesHost` is redundant.

PR Close #49424
2023-03-17 10:46:03 +01:00
Jessica Janiuk
81e974a99d refactor(core): Handle lost adjacent text nodes during hydration (#49419)
This restores the separation between adjacent text nodes that is lost during server serialization when parsed by the browser. It adds a special comment node just prior to the serialization process that is then restored as a separated node during hydration.

PR Close #49419
2023-03-15 17:25:10 -07:00
Jessica Janiuk
1116c492fa refactor(core): Handle cases of lost empty text nodes during hydration (#49419)
During DOM serialization, empty text nodes are lost when the client parses the DOM. To solve this problem comment nodes are added where the empty nodes are located right before serialization. Those comments then get replaced during hydration with the proper empty text nodes.

PR Close #49419
2023-03-15 17:25:10 -07:00
Alan Agius
cf98777153 test: update tests to remove deprecated withServerTransition (#49422)
This commit removes the usages of `withServerTransition` form tests.

PR Close #49422
2023-03-15 17:08:18 -07:00
Andrew Kushnir
22b895a5b1 refactor(core): add hydration logic for view containers (#49382)
This commit implements hydration support for view containers, which should make `*ngIf`, `*ngFor` and other structural directive work with hydration.

The logic also respects the `ngSkipHydration` flag and skips hydration in such cases.

PR Close #49382
2023-03-14 14:22:09 -07:00
Alan Agius
056d68002f feat(platform-server): add provideServerSupport function to provide server capabilities to an application (#49380)
This commit adds the `provideServerSupport()` function that returns the `EnvironmentProviders` needed to setup server rendering without NgModules.

PR Close #49380
2023-03-14 09:23:13 -07:00
Alan Agius
9165ff2517 fix(platform-browser): reuse server generated component styles (#48253)
Prior to this change component styles generated on the server where removed prior to the client side component being rendered and attached it's own styles. In some cases this caused flickering. To mitigate this `initialNavigation: enabledBlocking'` was introduced which allowed the remove of server styles to be defer to a latter stage when the application has finished initialization.

This commit changes the need for this, by not removing the server generated component styles and reuse them for client side rendering.

PR Close #48253
2023-03-09 09:33:34 -08:00
Jessica Janiuk
5944f5d21e refactor(core): skip hydration annotation (#49345)
This adds the ngSkipHydration annotation, which allows users to
opt hydration boundaries out of hydration. This enables incremental
adoption of hydration by letting users skip hydration on components
that have implementation issues that conflict with hydration.

co-authored-by: AndrewKushnir <akushnir@google.com>

PR Close #49345
2023-03-08 17:56:43 +00:00
Andrew Kushnir
8e0a087674 refactor(core): hydration logic for <ng-container>s (#49303)
This commit incrementally builds on top of #49285 and adds the logic to hydrate <ng-container>s and their contents. This implementation supports simple <ng-container>s that don't have any Angular features (like *ngIf/*ngFor, etc) and are not content-projected.

The subsequent commits will extend the logic further to support more complex scenarios.

PR Close #49303
2023-03-07 23:56:45 +00:00
Andrew Kushnir
e48930454a refactor(core): hydration logic for simple element and text nodes (#49285)
This commit incrementally builds on top of https://github.com/angular/angular/pull/49271 and adds the logic to hydrate elements and text nodes that don't have any Angular features (like *ngIf/*ngFor, etc) and are not content-projected.

The subsequent commits will extend the logic further to support more complex scenarios.

Co-authored-by: Jessica Janiuk <jessicajaniuk@google.com>
Co-authored-by: Andrew Kushnir <akushnir@google.com>

PR Close #49285
2023-03-06 19:43:41 +00:00
Jessica Janiuk
4ae4090d3c refactor(platform-server): Implement hydration state transfer machinery (#49271)
**Important note**: this is a first commit in a series of commits that will be needed
to support non-destructive hydration. Stay tuned for further updates!

This commit lays the foundation on top of which more hydration logic will be
added in follow up PRs. This PR includes:

* Initial serialization of hydration data
* Data transfer of hydration annotations from server side to client
* Accessing hydration info and populating internal data structures
* Initial APIs (currently private) that enable hydration (in a tree-shakable manner)
* Cleanup of annotations post hydration
* Initial test infrastructure and basic test cases

This commit does **not** expose any public APIs. They'll be exposed later, when
more hydration logic is implemented to a state when it can cover most common
use-cases.

Co-authored-by: Jessica Janiuk <jessicajaniuk@google.com>
Co-authored-by: Andrew Kushnir <akushnir@google.com>

PR Close #49271
2023-03-06 16:53:37 +00:00