Commit graph

217 commits

Author SHA1 Message Date
Kristiyan Kostadinov
cf059979d7 refactor(core): support let declarations during hydration (#56527)
Updates the hydration logic to account for the fact that let declarations don't create a DOM node.

PR Close #56527
2024-06-26 08:48:32 -07:00
Gerald Monaco
be9e4892f9 fix(core): improve support for i18n hydration of projected content (#56192)
When collecting nodes from the DOM for hydration, we need to treat nodes with paths (e.g. content projection) as the new root for all subsequent elements, not just the next one.

Additionally, when using content projection it's possible for translated content to become disconnected, e.g. when it doesn't match a selector and there isn't a default. We need to handle such cases by manipulating the disconnected node data associated with hydration as usual.

PR Close #56192
2024-06-20 14:59:58 -07:00
Andrew Kushnir
83ffa94783 fix(core): do not activate event replay when no events are registered (#56509)
This commit adds extra checks to handle a situation when an application has no events configured, but the Event Replay feature was enabled. This situation can happen when some routes in an application are mostly static, when other routes are more interactive.

Resolves #56423.

PR Close #56509
2024-06-20 08:53:19 -07:00
Thomas Nguyen
dbf1d9361e refactor(core): Refactor parts of event_replay into a shared library that will be used with global event delegation. (#56172)
This also moves the code that stashes the jsaction more closely to the code that actually sets the event listener.

PR Close #56172
2024-06-05 16:35:23 +00:00
Andrew Kushnir
290a47d842 fix(core): handle missing withI18nSupport() call for components that use i18n blocks (#56175)
This commit updates hydration serialization logic to handle a case when the `withI18nSupport()` call is not present for an application that has a component that uses i18n blocks. Note: the issue is only reproducible for components that also inject `ViewContainerRef`, since it triggers a special serialization code path.

Resolves #56074.

PR Close #56175
2024-05-30 18:36:58 +00:00
Thomas Nguyen
4fdc93bcd5 refactor(core): Use event_dispatcher in event_replay code. (#56036)
This makes events bubble! This change also contains changes to
dispatcher and event_dispatcher to make replay synchronous,
so that we avoid odd timing issues. This can be split out though.

Lastly, we have one cleanup change to move the mapping from
event type to functions on the element itself.

PR Close #56036
2024-05-29 12:59:23 +02:00
Andrew Kushnir
4e6ea0e19c fix(core): handle elements with local refs in event replay serialization logic (#56076)
Previously, the event replay serialization logic was located before we verify that a `TNode` exists. `TNode`s may not exist in `tView.data` array in several cases, including cases when there is a local ref used on an element: in this case an extra slot in `LView` contains a reference to the same element and `TNode` is not needed. This commit moves the event replay serialization logic a bit lower, after we check for TNode presence.

Resolves #56073.

PR Close #56076
2024-05-27 13:50:10 +02:00
Thomas Nguyen
88fb94693a refactor(core): Add a test case for content projection. (#55801)
This test actually used to fail until our recent improvements :))

PR Close #55801
2024-05-15 08:57:48 -07:00
Thomas Nguyen
89e860cc30 refactor(core): Add four tests and fix code to make tests pass. (#55747)
The first test asserts that bubbling does not work right now.

The second asserts that stopPropagation works, which should pass when test #1 passes too.

The third test asserts properties about the events passed to the event handler.

THe fourth test asserts that mouse events do not translate to jsaction nor help emit the jsaction binary. This required a change in code to make this pass.

PR Close #55747
2024-05-14 09:38:43 -07:00
iteriani
72b107b2a7 refactor(core): Use early event contract instead of the event contract in bootstrap. (#55587)
This also fixes an existing bug where we erase the jsaction attribute too early.

Now the event contract binary is 608 bytes :D.

PR Close #55587
2024-05-09 14:34:10 -07:00
Alan Agius
a916047a83 test: add Integration tests for hydration and event reply (#55708)
This commit introduces integration tests for hydration and event reply functionalities. Additionally, it implements a payload size check for the `event-dispatch-contract.min.js`.

PR Close #55708
2024-05-07 13:39:56 -07:00
Alan Agius
e71e869112 fix(platform-server): remove event dispatch script from HTML when hydration is disabled (#55681)
Prior to this commit, the included event dispatcher remained in the HTML even when hydration was disabled.

PR Close #55681
2024-05-06 12:33:09 -07:00
iteriani
8432d75b9a refactor(core): Remove jsaction from element after handling the event. (#55549)
This also adds a test to make sure that the event contract is still listening to other events, especially in the case where we may want partial hydration in the future.

PR Close #55549
2024-05-02 11:04:59 -07:00
iteriani
7a976784c0 refactor(platform-server): Update event_replay_spec to more match production code. (#55517)
Notably, do evals where in SSR we evaluate a contract binary and evaluate scripts.

PR Close #55517
2024-04-25 14:58:12 -07:00
Kristiyan Kostadinov
a5c57c7484 fix(core): resolve error for multiple component instances that use fallback content (#55478)
Currently fallback content for `ng-content` gets declared and rendered out in one go. This breaks down if multiple instances of the same component are used where one doesn't render the fallback content while the other one does, because the `TNode` for the content has to be created during the first creation pass.

These changes resolve the issue by always _declaring_ the template, but only rendering it if the slot is empty.

Fixes #55466.

PR Close #55478
2024-04-25 09:04:01 -07:00
Andrew Kushnir
307bc1d6b6 refactor(platform-server): event contract script should follow event dispatch script (#55502)
This commit fixes an issue where event contract init script was injected into the page before the inlined event dispatch script. That resulted in runtime exceptions, since event contract relies on some code being present on a page already.

PR Close #55502
2024-04-24 10:32:36 -07:00
iteriani
811fe001c9 refactor(core): Replay events from the event contract using the dispatcher. (#55467)
This should accomplish event replay during full page hydration.

PR Close #55467
2024-04-23 16:08:36 -07:00
Alan Agius
5674c644ab fix(platform-server): add nonce attribute to event record script (#55495)
This commit fixes an issue where the nonce attribute was not added when `CSP_NONCE` token was provided.

PR Close #55495
2024-04-23 13:12:47 -07:00
Andrew Kushnir
ba0036c5c3 refactor(platform-server): remove inlined JSAction script when no events to replay (#55428)
JSAction script is inlined into the HTML by the build process to avoid extra blocking request. The script looks like this:

```
<script type="text/javascript" id="ng-event-dispatch-contract">...</script>
```

This commit updates the logic to remove JSAction if event replay feature is disabled or if there are no events to replay.

PR Close #55428
2024-04-22 11:36:21 -07:00
Joey Perrott
b1dffa4abe refactor: migrate platform-* to prettier formatting (#55423)
Migrate formatting to prettier for platform-* from clang-format

PR Close #55423
2024-04-19 13:49:24 -07:00
Thomas Nguyen
a730f09ae9 feat(core): Add a public API to establish events to be replayed and an attribute to mark an element with an event handler. (#55356)
These will be consumed by the event-dispatch contract to replay events. The contract and the dispatcher inclusion will be in followups.

PR Close #55356
2024-04-19 13:12:21 -07:00
Gerald Monaco
45ae7a6b60 feat(platform-browser): add withI18nSupport() in developer preview (#55130)
Expose withI18nSupport() as a hydration feature to enable i18n hydration

PR Close #55130
2024-04-03 15:27:24 +00:00
Gerald Monaco
a5fa279b6e fix(core): prevent i18n hydration from cleaning projected nodes (#54823)
Rework the i18n cleanup behavior to more closely match that of containers. Specifically, we assume that nodes are going to be claimed unless they are part of a branching ICU block.

During hydration, we then track which ICU case was active at serialization time, and which was active during hydration. Any remaining cases that weren't used during hydration are then cleaned up.

PR Close #54823
2024-03-29 09:35:43 -07:00
Gerald Monaco
f44a5e4604 fix(core): support content projection and VCRs in i18n (#54823)
Modifies the i18n pre-hydration logic to correctly support content projection and elements that act as view containers.

PR Close #54823
2024-03-29 09:35:43 -07:00
Gerald Monaco
146306a141 feat(core): add support for i18n hydration (#54823)
Add support for hydrating i18n blocks. This is accomplished by serializing information about selected ICU cases for a block during server-side rendering.

During hydration, this data is read and is used to traverse both an AST of the translated message and the DOM, in parallel, to map each LView with an RNode.

Finally, this mapping is used while nodes are being created (either via i18n or their respective instructions) to locate existing nodes.

PR Close #54823
2024-03-29 09:35:43 -07:00
Kristiyan Kostadinov
a600a39d0c feat(core): add support for fallback content in ng-content (#54854)
Adds the ability to specify content that Angular should fall back to if nothing is projected into an `ng-content` slot. For example, if we have the following setup

```
@Component({
  selector: 'my-comp',
  template: `
    <ng-content select="header">Default header</ng-content>
    <ng-content select="footer">Default footer</ng-content>
  `
})
class MyComp {}

@Component({
  template: `
    <my-comp>
      <footer>New footer</footer>
    </my-comp>
  `
})
class MyApp {}
```

The instance of `my-comp` in the app will have the default header and the new footer.

**Note:** Angular's content projection happens during creation time. This means that dynamically changing the contents of the slot will not cause the default content to show up, e.g. if a `if` block goes from `true` to `false`.

Fixes #12530.

PR Close #54854
2024-03-26 09:17:59 -07:00
Matthieu Riegler
55c3932f5e refactor(core): Add hydration missmatch on the component rather than the node. (#54671)
In some cases the hydration mismatch is nested within a component.

As the devTool only reports issues on the component level, we need to mark the component node rather than the actual mismatched node.

PR Close #54671
2024-03-18 16:52:19 -07:00
Alan Agius
2357d3566c refactor(platform-server): remove legacy URL handling logic (#54874)
BREAKING CHANGE:

Legacy handling or Node.js URL parsing has been removed from `ServerPlatformLocation`.

The main differences are;
  - `pathname` is always suffixed with a `/`.
  - `port` is empty when `http:` protocol and port in url is `80`
 - `port` is empty when `https:` protocol and port in url is `443`

PR Close #54874
2024-03-18 16:37:07 -07:00
Gerald Monaco
456f18be2e refactor(core): add internal API to enable i18n hydration (#54784)
Add an internal API to enable and use i18n hydration for testing and development. This helps ensure that we don't accidentally break the current behavior until we are completely ready to roll out i18n support.

PR Close #54784
2024-03-12 11:38:59 -07:00
Matthieu Riegler
b560e02cdf refactor(devtools): Add hydration informations (#53910)
This commit adds hydration informations to the devtools.
* List of hydrated/hydrated components
* Shows hydration overlays
* Shows hydration errors for NG0500, 501 & 502

PR Close #53910
2024-01-30 20:03:14 +00:00
Andrew Scott
6c8faaa769 refactor(core): Rename InitialRenderPendingTasks and restructure isStable observable (#53534)
The InitialRenderPendingTasks currently attempts to only contribute to
ApplicationRef stableness one time to support SSR. This isn't actually
how the switchMap works in reality. This commit updates
the isStable observable to be more clear that it's always a combination
of the zone stableness and pending tasks.

In addition, this commit renames the service to just be PendingTasks
because it doesn't directly relate to rendering. While the purpose is
to track things that might cause rendering to happen, we don't know if the
tasks will affect rendering at all.

PR Close #53534
2023-12-19 08:36:28 -08:00
Andrew Kushnir
596b43d631 refactor(core): skip disconnected nodes while computing node path for hydration (#53317)
In certain cases Angular hydration logic can not rely on the order in which elements are present in a template (for example, in content-projection use-cases) and there is a need to serialize a path from one node to another, so that hydration can locate an element on a page. The logic attempts to use an immediate parent element as an anchor and compute the path from it. If it fails - the path is computed starting from the <body> (this is a fallback).

This commit updates the logic to walk up the parents tree if an immediate parent (from a template) is disconnected from the DOM. This helps to shorten the lookup path and make it more stable.

PR Close #53317
2023-12-04 21:44:08 -08:00
Andrew Kushnir
82609d471c fix(core): support swapping hydrated views in @for loops (#53274)
This commit fixes an issue where swapping hydrated views was not possible in the new control flow repeater. The problem was caused by the fact that an internal representation of a view had no indication that hydration is completed and further detaching/attaching should work in a regular (non-hydration) mode. This commit adds a logic that resets a pointer to a dehydrated content and we use this as an indication that the view is swtiched to a regular mode.

Resolves #53163.

PR Close #53274
2023-12-01 10:35:36 -08:00
Andrew Kushnir
4b23221b4e fix(core): support hydration for cases when content is re-projected using ng-template (#53304)
This commit fixes an issue with hydration, which happens when a content is projected in a certain way, leaving host elements non-projected, but the child content projected.

The fix is to detect such situations and add extra annotations to help runtime logic locate those elements at the right locations.

Resolves #53276.

PR Close #53304
2023-12-01 09:12:54 -08:00
Andrew Kushnir
899f6c4a12 fix(core): handle hydration of multiple nodes projected in a single slot (#53270)
This commit updates the logic to handle hydration of multiple nodes projected in a single slot. Currently, in case component nodes are content-projected and their order is changed during the projection, hydration can not find the correct element. With this fix, extra annotation info would be included for such nodes and hydration logic at runtime will use it to locate the right element.

Resolves #53246.

PR Close #53270
2023-11-30 09:16:23 -08:00
Andrea Canciani
fc9ba3978c refactor: fix a number of typos throughout the codebase (#52249)
Fix some typos such as `boostrap`, `propery` and more, both in
documentation and in code (comments, identifiers).

PR Close #52249
2023-10-25 16:51:24 -07:00
Alan Agius
405ec8c796 fix(platform-server): resolve relative requests URL (#52326)
Prior to this commit relative HTTP requests were not being resolved to absolute even thought the behaviour is documented in https://angular.io/guide/universal#using-absolute-urls-for-http-data-requests-on-the-server.

This caused relative HTTP requests to fail when done on the server because of missing request context. This change is also required to eventually support HTTP requests handled during prerendering (SSG).

Closes #51626

PR Close #52326
2023-10-23 12:02:21 -07:00
Andrew Kushnir
d10f2b29d7 refactor(core): use performance API for hydration-related features (#52288)
This commit adds a standard performance marker that can be viewed in Chrome dev tools and other tooling. See more info at https://developer.mozilla.org/en-US/docs/Web/API/Performance/mark

PR Close #52288
2023-10-23 09:29:36 -07:00
Andrew Kushnir
666853f7c2 refactor(core): avoid invoking IntersectionObserver in defer triggers on the server (#52306)
This commit updates the logic to make sure that DOM-specific triggers do not produce errors on the server.

Resolves #52304.

PR Close #52306
2023-10-23 09:28:15 -07:00
Alan Agius
7978b408df refactor(platform-server): replace Node.js URL API usage (#52231)
This commit replace the usage of URL node API to WHATWG URL API.

See: https://nodejs.org/api/url.html#the-whatwg-url-api

PR Close #52231
2023-10-19 09:26:44 -07:00
Andrew Kushnir
4e4ad5ab2e refactor(core): simplify hydration annotation key (#52207)
This commit drops the `ɵ` symbol from hydration annotation key: `__ɵnghData__` -> `__nghData__`. This helps ensure that there are no UTF8 symbols that might be damaged in case a web server is misconfigured.

Noticed while working on https://github.com/angular/angular/pull/52206.

PR Close #52207
2023-10-16 11:25:57 +02:00
Andrew Kushnir
dbc14eb41d refactor(platform-browser): remove withNoDomReuse function (#52057)
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.

PR Close #52057
2023-10-09 13:36:16 -07:00
Kristiyan Kostadinov
43e6fb0606 feat(core): enable block syntax (#51994)
Enables the new `@` block syntax by default by removing the `enabledBlockTypes` flags. There are still some internal flags that allow special use cases to opt out of the block syntax, like during XML parsing and when compiling older libraries (see #51979).

PR Close #51994
2023-10-03 15:26:05 -07:00
Andrew Kushnir
6b6a44c473 refactor(core): add hydration support for built-in for (#51920)
This commit adds hydration support for repeaters (for loops) and empty blocks. The logic looks up a dehydrated view and use this information for hydration. Otherwise, DOM elements for a view are created from scratch.

PR Close #51920
2023-09-29 15:21:21 -07:00
Alan Agius
8413b64a6b refactor(core): add whenStable private API (#51807)
Prior to this change `this.isStable.pipe(first((isStable) => isStable)).toPromise()` had to be done in multiple places across the framework and the Angular CLI see https://github.com/angular/angular-cli/pull/25856#discussion_r1328158846. In the majority of cases an Observable based `isStable` API is not needed. This also removes the need for RXJS operator imports.

PR Close #51807
2023-09-27 10:31:56 -07:00
Andrew Kushnir
7a731c9536 refactor(core): add hydration support for built-in if and switch (#51915)
This commit updates the `if` and `switch` logic to support hydration. The logic attempts to find dehydrated views in containers while processing `if` and `switch` instructions. If a dehydrated is found, its used to further match elements. Otherwise, DOM elements for a view are created from scratch.

PR Close #51915
2023-09-27 10:29:07 -07:00
Kristiyan Kostadinov
8be2c48b7c feat(core): implement new block syntax (#51891)
Switches the syntax for blocks from `{#block}{/block}` to `@block {}` based on the feedback from the community.

Read more about the decision-making process in our blog: https://blog.angular.io/meet-angulars-new-control-flow-a02c6eee7843

The existing block types changed in the following ways:

**Conditional blocks:**
```html
<!-- Before -->
{#if cond}
  Main content
  {:else if otherCond}
    Else if content
  {:else}
    Else content
{/if}

<!-- After -->
@if (cond) {
  Main content
} @else if (otherCond) {
  Else if content
} @else {
  Else content
}
```

**Deferred blocks**
```html
<!-- Before -->
{#defer when isLoaded}
  Main content
  {:loading} Loading...
  {:placeholder} <icon>pending</icon>
  {:error} Failed to load
{/defer}

<!-- After -->
@defer (when isLoaded) {
  Main content
} @loading {
  Loading...
} @placeholder {
  <icon>pending</icon>
} @error {
  Failed to load
}
```

**Switch blocks:**
```html
<!-- Before -->
{#switch value}
  {:case 1}
    One
  {:case 2}
    Two
  {:default}
    Default
{/switch}

<!-- After -->
@switch (value) {
  @case (1) {
    One
  }

  @case (2) {
    Two
  }

  @default {
    Default
  }
}
```

**For loops**
```html
<!-- Before -->
{#for item of items; track item}
  {{item.name}}
  {:empty} No items
{/for}

<!-- After -->
@for (item of items; track item) {
  {{item.name}}
} @empty {
  No items
}
```

PR Close #51891
2023-09-26 09:10:04 -07:00
Andrew Kushnir
1aff106a87 refactor(core): adjust defer block behavior on the server (#51530)
This commit updates the runtime implementation of defer blocks to avoid their triggering on the server. This behavior was described in the RFC (https://github.com/angular/angular/discussions/50716, see "Server Side Rendering Behavior" section): only a placeholder is rendered on the server at this moment. This commit also updates the logic to make sure that the placeholder content is hydrated after SSR.

PR Close #51530
2023-09-01 19:15:16 +00:00
Andrew Kushnir
006577f39c fix(core): handle hydration of view containers that use component hosts as anchors (#51456)
This commit fixes an issue where serialization of a view container fails in case it uses a component host as an anchor. This fix is similar to the fix from #51247, but for cases when we insert a component (that acts as a host for a view container) deeper in a hierarchy.

Resolves #51318.

PR Close #51456
2023-08-29 16:37:50 +00:00
Andrew Kushnir
55965cbf8c fix(core): handle hydration of view containers for root components (#51247)
For cases when a root component also acts as an anchor node for a ViewContainerRef (for example, when ViewContainerRef is injected in a root component), there is a need to serialize information about the component itself, as well as an LContainer that represents this ViewContainerRef. Effectively, we need to serialize 2 pieces of info: (1) hydration info for the root component itself and (2) hydration info for the ViewContainerRef instance (an LContainer). Each piece of information is included into the hydration data (in the TransferState object) separately, thus we end up with 2 ids. Since we only have 1 root element, we encode both bits of info into a single string: ids are separated by the `|` char (e.g. `10|25`, where `10` is the ngh for a component view and 25 is the `ngh` for a root view which holds LContainer).

Previously, we were only including component-related information, thus all the views in the view container remained dehydrated and duplicated (client-rendered from scratch) on the client.

Resolves #51157.

PR Close #51247
2023-08-07 09:24:26 -07:00