Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[Complete] RFC: Incremental Hydration#57664

Locked
thePunderWoman announced inRFCs
Sep 4, 2024· 17 comments· 44 replies
Discussion options

Authors:@thePunderWoman
Area: Angular Framework
Posted: September 4, 2024
Status: Open

In Angular version 16, we launched full application hydration in Angular to improve your Core Web Vitals, server side rendering performance, and improve the overall initial render experience when using server side rendering. Then, in version 17, we added deferrable views, which allowed you to easily defer less important code until it was needed later, which further improved core web vitals and reduced initial bundle size. We've since also added event replay, which means none of your users' actions will be lost before hydration kicks in.

Building on this functionality, we're excited to share more concrete plans for the next SSR improvement: incremental hydration. With incremental hydration, deferred content is rendered on the server side and skipped over during client-side hydration and bootstrapping - it's leftdehydrated. This allows Angular to bootstrap the initial page in less time, and keeps the code for those dehydrated components out of your initial bundle. Angular will leave those parts of the UI dehydrated until your declared hydration conditions are met, at which point it will download the necessary code and hydrate those components on demand. You already know the set of hydration triggers, as they're the same familiar@defer triggers:on viewport,on interaction, etc.

Incremental hydration allows you to apply these familiar client-side@defer optimizations to server-side rendered code, delaying the loading of less critical parts of your UI while avoiding negative effects like content layout shifts.

What kind of feedback are we looking for?

While we're excited to hear any and all comments on incremental hydration in Angular, we have additionally called out specific discussion points throughout the RFC for directed feedback. When you leave a comment, be sure to note the open question(s) to which you're responding.

As always, keep our code of conduct in mind. We know that a proposal of this scope significantly impacts Angular and the way you use it in your projects. We appreciate your commitment and investment in this project and ask to keep comments respectful.

Goals

  • Provide a predictable and ergonomic API for developers to leave content dehydrated.
  • Reduce initial page load time due to smaller initial bundle sizes.
  • Improve core web vitals performance, especially cumulative layout shift.
  • Ensure no user interaction is lost prior to fetching and hydration of content.

Discussion Question 1: Is it clear to you what is meant by "incremental hydration"?

Dehydrated Content

When Angular leaves content on the page in a dehydrated state, it behaves as static HTML:

  • No component or directive instances are created.
  • No lifecycle hooks for the content execute.
  • The content does not match view or content children queries.
  • The content is not change detected, even if bindings to those components or their contents would have changed.

In other words, the content appears exactly as it did during server-side rendering.

Only when your hydration condition is met does Angular download the code for the components/directives within the content and hydrate it: instances are created, lifecycle hooks execute, and change detection updates the content based on its bindings.

It's possible that users could interact with your dehydrated content before it can hydrate, especially since the hydration process requires fetching code and is therefore asynchronous. Angular addresses this using the Event Dispatch library, by adding event listeners to your dehydrated content and replaying events after hydration occurs (similar to thewithEventReplay() option for the main SSR'd application).

Syntax

Deferrable views, or defer blocks, are the building (defer) block and hydration boundary for incremental hydration in Angular. A defer block becomes a incremental hydration boundary by adding a hydrate on, hydrate when, or hydrate never condition. For example:

<example-cmp/>@defer (on immediate; hydrate on interaction) {<deferred-cmp/><another-deferred-cmp/>}

Similar to defer triggers and prefetch triggers, you can use multiple hydrate triggers at once, and hydration will occur when any of those triggers fire.

Hydration triggers apply when a@defer block is server-rendered, during the application'sinitial load. The standard defer block triggers apply only to client side rendered@defer blocks. Since any@defer block might also be client-side rendered, you will need to configure a regular defer condition in addition to any hydration conditions.

Discussion Question 2: Does this syntax make sense to you? Specifically consider the difference between regular triggers and hydrate triggers. Is there an alternative that might work better?

Discussion Question 3: Is the defer syntax becoming too hard to read or understand with multiple triggering paradigms and conditions?

Discussion Question 4: Do you see yourself commonly using the same triggers for defer and hydrate? Or different conditions? For example:@defer(on interaction; hydrate on interaction) vs@defer(on interaction; hydrate on immediate)

Trigger Types

The trigger types for incremental hydration are similar to the main@defer, with a few differences. Hydration triggers always apply to the actual rendered body of the@defer block and thus don't allow element references. They only apply to@defer blocks that are server-side rendered.

idle

idle triggers hydration once the browser has reached an idle state (seerequestIdleCallback).

interaction

hydrate on interaction instructs Angular to hydrate content when the user interacts with it (click, focus, touch, and input events like keydown, blur, etc).

immediate

hydrate on immediate triggers the deferred load and hydration immediately.

timer(x)

timer(x) triggers hydration after a specified duration.

hover

hover triggers deferred loading when the user hovers their mouse over the server rendered content. This condition is useful if hovering the mouse is a good indication that the user might soon interact with the content.

viewport

viewport triggers hydration when the server rendered content enters the viewport (detected using theIntersectionObserver API).

never

hydrate never tells Angular to leave your component dehydrated indefinitely, effectively treating it as static content. Note that this is not the same as a server-only component. When a@defer block is instantiated during normal client-side rendering, the content is still fetched and rendered normally.

when

Just like regular and prefetch deferrable view triggers, you can provide a custom condition which triggers hydration when it becomestrue. There are some caveats to this, which is outlined in the nesting section.

Nested Hydration

When multiple@defer blocks are in a dehydrated state, their conditions are applied simultaneously. For example, in the following structure:

@defer(hydrateonhover){  @defer(hydrateontimer(15s)){    ...}}

The outer block will hydrate if the mouse is hovered over any of the content inside of it. Even if the block is never hovered, the inner block's timer will trigger hydration after 15 seconds.

There is one exception to this behavior:hydrate when only works if the component which contains it is already hydrated. If awhen trigger for a block is nested inside a component which is itself dehydrated, it won't be evaluated until the parent component is triggered and hydrated independently. For example:

@defer(hydrateonhover){  @defer(hydratewhenuser()!==null){    ...}}

If the outer block has not triggered, then regardless of the value ofuser(), the inner block will not hydrate.

When hydration is triggered within a nested block, any parent block(s) are first hydrated if necessary, and then the triggered block is hydrated. Because each hydration step requires fetching the code for dependencies, this means that nested dehydrated blocks require a waterfall of code loading in order to hydrate.

Discussion Question 5: Do you have components you would like to use incremental hydration with but would be unable to due to the potential for stale data? Would that change if incremental hydration was triggered by inputs changing? Similarly would that change if hydration was triggered by signals changing?

Common Potential Pitfalls

Root text nodes

The hydration triggers ofinteraction,hover, andviewport do not work with plain text nodes at the top (root) level of the deferred content, as browsers do not support listening for events on text nodes or watching them withIntersectionObserver. Angular will therefore not allow such nodes in@defer blocks which use those triggers. Text must be wrapped in an element (such as<p>) in order to work correctly with incremental hydration.

Frequently Asked Questions

Q: I have a question, but it's not ready yet.

…ok

Q: When will this feature be available?

When it's fully hydrated.

Q: Islands?

We're thinking about them.

Q: Does this mean Angular has server components now?

No, it does not. Server components should always render on the server and never on the client. hydrate triggers only apply to first load.

Q: When hydration is triggered on nested blocks, each with hydrate triggers, will that result in cascading requests or waterfalls?

Yes, hydrate triggers on nested components will be a waterfall of requests, but this is something we plan to address.

Q: OK, my question is ready now. Does this new version of Angular Cereal also have marshmallows?

Ah I get it, this is a hydration trigger joke…and yes…marshmallows.

You must be logged in to vote

Replies: 17 comments 44 replies

Comment options

Answer Question 1: No 🫠 please explain and give us some use case

You must be logged in to vote
4 replies
@thePunderWoman
Comment options

thePunderWomanSep 4, 2024
Collaborator Author

Use case A:
You have a list of product items on a list page on an ecommerce platform. You don't know if a user will ever see or interact with that product. So you put it underneath a defer block with hydrate syntax for it to fetch and hydrate only once it's been interacted with, reducing your initial bundle size. In this case, the product still gets rendered, but the code for the component doesn't get fetched until it's needed.

Use case B:
You have a blog post that is mostly static content. You can use ahydrate never condition to avoid shipping any javascript for that post component.

Use case C:
You have a large component above the fold, like your header or carousel. Your heatmaps show that very few people click on those. So you can put them behind a hydrate trigger to render them, but avoid shipping the content until someone interacts with it.

@hheexx
Comment options

@thePunderWoman maybe deferred hydration is better name? It implies it's related to defer blocks......

@mgechev
Comment options

mgechevOct 8, 2024
Collaborator

We discussed deferred hydration as a potential name. It's possible to perform full-app hydration on idle, which makes it deferred, but not necessarily incremental. Calling it "incremental deferred hydration" will be accurate, but also too long without bringing too much value.

@naveedahmed1
Comment options

Incremental Hydration and Partial Hydration both seems natural and reflects exactly what the feature is about.

Comment options

Question (2): What would be the execution flow of the provided example with a mix of standard and hydration triggers? Syntax is not hard to read but how to reason about it (execution)

@defer (on immediate; hydrate on interaction) {  <deferred-cmp />  <another-deferred-cmp />}
You must be logged in to vote
7 replies
@thePunderWoman
Comment options

thePunderWomanSep 4, 2024
Collaborator Author

mutually exclusive is a good way to put it, yes. Hopefully that's clear and makes sense. We are also utilizing event replay for the content in the hydrate blocks. So if a user interacts with that content, the interaction will not be lost.

@zygarios
Comment options

So I understand that the 'Hydrate' syntax makes the 'dom' structure render without hydration. But what happens when I use@Placeholder or@Placeholder+@loader together with this function? Does that mean they will be skipped on the server side?

@thePunderWoman
Comment options

thePunderWomanSep 4, 2024
Collaborator Author

So I understand that the 'Hydrate' syntax makes the 'dom' structure render without hydration. But what happens when I use@Placeholder or@Placeholder+@loader together with this function? Does that mean they will be skipped on the server side?

This is correct. In the SSR / hydrate case, your defer main template contentIS your new placeholder. The@placeholder and@loading templates you provide will be used in the client side rendering cases, just like they do today.

@zygarios
Comment options

Ok, but if I don't use the word 'Hydrate', the placeholder will come from the server. I just want to be sure.

@thePunderWoman
Comment options

thePunderWomanSep 4, 2024
Collaborator Author

@zygarios If you don't use the wordhydrate, things will behave exactly as they do now with SSR. The@placeholder block gets rendered on the server and is hydrated eagerly with the rest of the full application.

Comment options

I'm super happy to see this RFC, everything here makes sense. I have just one feature request: please consider adding the “time” argument to “idle”.
Like:

@defer (on hover(container); on idle(2000)) {  <heavy-component/>}

That would load the HeavyComponent either on hover or after a 2s delay after “idle”.

There are just components that are far enough from the user’s path, and heavy enough to load them not on just “idle”, but with a small delay - because more important components will take a chance to be loaded on “idle”.

Overall, this RFC is awesome and I hope it will be implemented in v19.

You must be logged in to vote
3 replies
@crisz
Comment options

I'd adviseidleTimeout or something else that makes clear it's a timeout.idle(2000), with no context, may not convey enough information about the behaviour

@thePunderWoman
Comment options

thePunderWomanSep 5, 2024
Collaborator Author

@e-oz This is definitely more of a feature request for@defer as a whole, rather than anything specific to this hydration RFC. Could you create a issue / feature request with this instead?

@e-oz
Comment options

Could you create a issue / feature request with this instead?

Sure!#57814

Comment options

Will there be support for placeholder and loading blocks?

You must be logged in to vote
1 reply
@thePunderWoman
Comment options

thePunderWomanSep 4, 2024
Collaborator Author

This is additional syntax for@defer blocks. So@placeholder,@loading, and@error are all supported. However they wouldn't apply for hydrate cases as the placeholder is the server rendered content, and there's no need to display loading, as the actual content is already present. They'd still work as they normally would in a CSR situation though.

Comment options

Discussion Question 1: Yes, it's clear
Discussion Question 2: After reading the comments, it is clear to me. However, I think it would be helpful if there were aninfographic or well-described scenarios explaining what happens in different contexts. An example is how@Placeholder and@loader behave in combination with hydrate. I'm not just looking for an explanation of hydrate, but rather the entire flow and use cases for the defer functionality as a whole.

Discussion Question 3: The syntax doesn't seem to be overly complicated. However, it is important to clearly describe the dependencies between different states, as I mentioned in point 2.

Discussion Question 4: I don't have an opinion on this matter

Discussion Question 5: I don't have an opinion on this matter

You must be logged in to vote
0 replies
Comment options

The RFC is great, good job!

  • Question 1: Yes
  • Question 2: Yes
  • Question 3: A little verbose, bug gives full control. Would it make sense to provide defaults via config?
  • Question 4: It's possible. But this whole feature is about providing tooling to fit a variety of conditions, web apps are complex. The proposal can enable any use case and leave the developer optimize depending on use case.
  • Question 5: When using defer, it might not be obvious that, if the view depends on some external state, dehydrated views might be stale. Ideally the framework would solve that and force hydration if it detects that the view is stale because of a signal update, just as qwik does. If not, I feel some diagnostic errors to avoid the pitfall would be needed.

Additional feedback:

  • Hydration needs to fetch chunks of code, which come with a cost. Loading and parsing can impact user experience. Ideally a solution similar to qwik's could be provided: a Service Worker in the background preloads chunks in a separate thread, and when needed they are available for the main thread to hydrate without the network call or parsing time.
  • One of the biggest wins from this new feature is leaving content dehydrated. This can be much beneficial, since there are parts of a website that are just static. For example, sidenav, header, footer. Usually those parts of the app contain only links. However, a dehydrated link that usedrouterLink would not work in the SPA because it does not integrate well with the router. In order to enable apps have more dehydrated content, I'd like to recommend researching other solutions for router links. One realistic way would be that metadata for the link is left in the DOM, use a regularhref, and through event bubbling capture the event at a root component and handle navigation within Angular's router. This way we'd benefit from staying within the SPA routing, yet leaving links and their components dehydrated.
You must be logged in to vote
6 replies
@osnoser1
Comment options

When I read about this RFC, the first use case I imagined could be a potential win was routerLink handling in dehydratated content; I'd love this

@thePunderWoman
Comment options

thePunderWomanSep 5, 2024
Collaborator Author

As a quick follow up, the only real concern around routerLinks in dehydrated code would be when routerLinks exist inhydrate never blocks. Any interaction with a routerLink in any other case will trigger hydration, and that click will get replayed, resulting in the expected client side navigation. In ahydrate never case, as long as routerLink is used on an anchor tag, it would navigate, but as a hard navigation. Any other use of routerLink, though, wouldn't do anything inside ahydrate never block.

@samuelfernandez
Comment options

Exactly, that is why it'd be wonderful that in hydrate never it'd still trigger an SPA navigation without needing to hydrate. For simple use cases shouldn't be that complex. The event of a hard navigation could be intercepted in the root element, the url parsed, and router execution triggered. It's nice to see that it may be explored 😃. This way only m truly interactive regions would need to be hydrated,

@samuelfernandez
Comment options

@thePunderWoman One additional question on this statement:

Any interaction with a routerLink in any other case will trigger hydration, and that click will get replayed, resulting in the expected client side navigation.

routerLink implementation doesevent.preventDefault(), which cancels browser's hard navigation, and does a SPA navigation. When the component is not yet hydrated, what does exactly happen? Does the event replay library also callevent.preventDefault()? If not, the browser will synchronously execute a hard navigation, and hydration will just be lost. Asking without actually testing it... 😅 Thanks for helping me understand the deep waters of hydration 💧 (pun intended).

@thePunderWoman
Comment options

thePunderWomanSep 6, 2024
Collaborator Author

@samuelfernandez The event replay behavior makes sure the original click is not a hard navigation in this case. So it will behave as you would want, with the replay and the client side navigation.

Comment options

Discussion Question 1: Is it clear to you what is meant by "incremental hydration"?

A little bit mixed withprefetch, but it's ok.

Discussion Question 2: Does this syntax make sense to you? Specifically consider the difference between regular triggers and hydrate triggers. Is there an alternative that might work better?

Syntax makes complete sense.

Discussion Question 3: Is the defer syntax becoming too hard to read or understand with multiple triggering paradigms and conditions?

No. Especially if Angular warns us about non-usable combinations, as it does with@defer (on viewport) without an element ref and placeholder.

Discussion Question 4: Do you see yourself commonly using the same triggers for defer and hydrate? Or different conditions? For example:@defer(on interaction; hydrate on interaction) vs@defer(on interaction; hydrate on immediate)

No, but I do see common use withprefetch.

Discussion Question 5: Do you have components you would like to use incremental hydration with but would be unable to due to the potential for stale data? Would that change if incremental hydration was triggered by inputs changing? Similarly would that change if hydration was triggered by signals changing?

I don't think so.

You must be logged in to vote
2 replies
@thePunderWoman
Comment options

thePunderWomanSep 5, 2024
Collaborator Author

@e-oz Soprefetch just makes sure your chunk is prefetched, but your defer block still renders what's in the@Placeholder block until triggered.hydrate is a signal to the server side that you'd like to render your defer block main template on the server.hydrate changes what is rendered on the server server side, affecting what the user sees on first render.prefetch specifies how early the chunk is fetched on the client side. Does that help clarify?

@e-oz
Comment options

Sure. I meant thatprefetch is designed to run before the actual execution, just likehydrate. But I do realize thathydrate does much more thanprefetch. My point was - maybeprefetch already points to things we would like tohydrate. But it's merely an assumption; I wasn’t trying to say anything against the idea itself. The idea is awesome, and I hope to try it as soon as possible - before February 30, 2025. 😎

Comment options

  1. RegardingNested Hydration, is there any specific reason we need two different behaviors forhydrate when and otherhydrate triggers?

  2. What will happen in this case?

@defer (hydrate on hover) {.....  @defer (hydrate never) {    <ad-unit>  }......}

I'd want the outer component to be hydrated while keeping the ad-unit component unhydrated.

  1. Regarding theSyntax:

What if some of the hydration triggers could also be added to Component config, so that whenever we use the component it's default hydration settings is applied, with option to overwrite with@defer block.

@Component({  templateUrl: './enable-notifications.component.html',  standalone: true,hydrate: [interaction],prefetch:true})
You must be logged in to vote
1 reply
@thePunderWoman
Comment options

thePunderWomanSep 6, 2024
Collaborator Author

  1. Yes there is. The reason being that the rest of the triggers areevent based andhydrate when isexpression based.Event based triggers do not rely on logic in the component to trigger and can have shared logic for all of the instances across your page.Expressions rely on logic in your component that contains the defer block. We cannot evaluate an expression that does not exist yet. If the immediate parent is hydrated, theexpression will be present and can be evaluated. If the parent is dehydrated, that logic hasn't yet been fetched.

  2. Your expectation is correct and how things should behave on the initial SSR page load. Subsequent page loads would result in that logic being fetched, as subsequent page loads are client side rendered.

  3. We did consider components as hydration boundaries and also defer boundaries, but since the entire component is not what is being deferred, this sort of syntax wouldn't work, as you can have multiple defer blocks in a given component template. We're also actively trying to reduce the amount of configuration in the component decorator. So this would be moving us in the opposite direction of that goal.

Comment options

Q2: Any reasonhydrate can't be used as its own block, with the deferred behavior being implied?

@hydrate(onhover){<my-component/>}
You must be logged in to vote
6 replies
@brandonroberts
Comment options

Yes, I would assume Client Side Render could still use a@placeholder.

@thePunderWoman
Comment options

thePunderWomanSep 10, 2024
Collaborator Author

@brandonroberts but since it's called@hydrate, which is specifically a server side rendered behavior, does that not send a confusing message? You can't hydrate client side rendered content.

@brandonroberts
Comment options

Ok, I misunderstood the connection with CSR then. I was thinking of this in terms of shorthand syntax that works in both scenarios.

I thought if you happen to use@defer and hydrate without server-side rendering the page first, it would fall back to just being deferrable. Will it throw an error or warning if so?

@thePunderWoman
Comment options

thePunderWomanSep 10, 2024
Collaborator Author

It wouldn't make sense to use defer and hydrate conditions without SSR. Similarly it wouldn't make sense to use@hydrate in that scenario. What I'm getting at is these hydrate conditions apply to SSRed content, which means first load. It may be unclear to folks that they're affecting CSR situations when using@hydrate when by its naturehydration is an SSR thing.@defer with hydrate conditions may be clearer to people that it serves both cases.

@naveedahmed1
Comment options

I agree that@defer is more appropriate. In case of partial hydration we are in fact deferring the hydration to a more appropriate time.

Comment options

Discussion Question 4: Do you see yourself commonly using the same triggers for defer and hydrate? Or different conditions? For example:@defer(on interaction; hydrate on interaction) vs@defer(on interaction; hydrate on immediate)

I guess that I would generally use different triggers as in most cases, placeholders are short-lived as they don't make as much sense to the user as a dehydrated view which can often be hydrated way later.

You must be logged in to vote
4 replies
@naveedahmed1
Comment options

Could you please provide an example where you have a server-side rendered (SSR) page, and you'd like to hydrate a child component based on a specific trigger? Additionally, in the case where the user navigates to the same page via client-side navigation, you want that component to be defer-loaded using a different trigger. I almost always ended up using the same trigger for both cases.

@yjaaidi
Comment options

A heavy datepicker that users don't often interact with.
If SSRed, I'd want it to be hydrated on interaction as it is unnecessary to hydrate it if it's not used.
On the other hand, if it's CSRed, I would want to replace my placeholder on idle because the date it displays is relatively useful to the user even though they do not interact with it.

@naveedahmed1
Comment options

That’s an interesting use case, and while you might have specific requirements, I would generally avoid server-side rendering a datepicker. When a datepicker is rendered on the server, it might display the server's date and time, which could be confusing or inaccurate for users in different time zones. This could lead to errors if the displayed date doesn't match the user's local time. So, if you do SSR a datepicker, it’s crucial to hydrate it as soon as possible or during idle time to ensure the correct date is shown. However, I understand you may have unique needs.

@godhelpme1993
Comment options

I think about it alot. walking around not trusting anyone

Comment options

My gut feeling is that most users would prefer the default behavior to behydrate on idle instead of SSRing the placeholder.

Is there a reason whyhydrate on idle is not the default behavior set apart that it would be a breaking change?
This would require some syntax to skip SSR (skip-ssr?) and a migration to enable it on all existing@defers so that users can opt-in.

You must be logged in to vote
6 replies
@thePunderWoman
Comment options

thePunderWomanSep 11, 2024
Collaborator Author

Yes there is a reason we didn't makehydrate on idle the default. People may not want some blocks to use partial hydration, and if we have it default when omitted, there's no way to avoid it. We have considered a shorthand, though, which would be something like@defer(on idle; hydrate). Where essentially just sayinghydrate with no trigger indicates you want to use the same trigger as the regular defer. You could omiton idle in that case and it would just be@defer(hydrate). How do you feel about that concept?

@naveedahmed1
Comment options

@defer block doing hydrate on idle by default feels more natural to me 😀

@yjaaidi
Comment options

💯 for@defer(hydrate) shorthand.

People may not want some blocks to use partial hydration, and if we have it default when omitted, there's no way to avoid it.

There could be an instruction to opt-out from hydration, even though it will be tough to name 😅:hydrate disabled? it's going to be hard to find something that doesn't get confusing withhydrate never

@alxhub
Comment options

alxhubSep 18, 2024
Collaborator

Perhaps something like:

@defer (on idle; server placeholder) {...}

it doesn't need to be ahydrate condition specifically...

@naveedahmed1
Comment options

I am not sure whatserver placeholder would do in this case?

Comment options

Discussion Question 3: Is the defer syntax becoming too hard to read or understand with multiple triggering paradigms and conditions?

Yes. I am afraid that this can become quite confusing, especially for newcomers.
Good default values can help by moving the defer options further in the learning path.

Another thing that could help is something like reusable policies:

// defer-policies.tsconstlowPriorityPolicy=createDeferPolicy({defer:'idle',hydrate:'interaction'});// my-cmp@Component({template:`  @defer(policy lowPriorityPolicy) {    ...  }  `})classMyCmp{lowPriorityPolicy=lowPriorityPolicy}

or a better syntax if possible.

The policies would of course have to be static so that the compiler can understand them.

@thePunderWoman if you think this could be interesting, I can open an issue for this as it is not directly related to the RFC.

You must be logged in to vote
1 reply
@thePunderWoman
Comment options

thePunderWomanSep 11, 2024
Collaborator Author

Being able to create reusable policies is definitely a thing we've considered. So if there's enough interest, it could be a future feature add.

Comment options

What if I want the whole app to be set as hydrate never and then hydrate individual child components on demand e.g. hydrate some components on interaction and some on when they enter the view port. Something like an app wide confg that makes the whole app a static app with almost zero JavaScript unless a user starts interacting with the app.

You must be logged in to vote
1 reply
@thePunderWoman
Comment options

thePunderWomanSep 12, 2024
Collaborator Author

That concept is essentially what resumability is. We love this idea, but it is quite a bit more challenging and complicated to get to this point. Dependency injection, data dependencies, and a number of other complications all factor into making this a workable feature with Angular. We think incremental hydration is a step towards that possibility in the future. So stay tuned.

Comment options

I use an ngx-image-cropper component, that access window, and document objects right at the start.

In Angular SSR application this component throws an error: "ERROR RuntimeError: NG04002.

Two solutions helped me:

@defer (on immediate) {
<image-cropper...
}

or

<image-cropper ngSkipHydration

With incremental hydration, what solution should I choose?

You must be logged in to vote
1 reply
@thePunderWoman
Comment options

thePunderWomanSep 13, 2024
Collaborator Author

Ideally you would updatengx-image-cropper to useafterRender hooks to make them safe for hydration. In lieu of that, if you use a hydrate trigger, I'd go withngSkipHydration on this element, as it's no longer client side rendered. Alternatively if this is a component that only ever has the image cropper in it, just skip using a hydrate trigger and leave it like it is, as that's not going to change behavior.

Comment options

You must be logged in to vote
1 reply
@thePunderWoman
Comment options

thePunderWomanSep 16, 2024
Collaborator Author

Sorry. RFC conversations don't typically discuss expected timelines.

Comment options

Sounds like an amazing game 🤩 Loge to see the future of apps with Angular. This is very amazing chunk to even not load KB's of code until we interact.

You must be logged in to vote
0 replies
Comment options

thePunderWoman
Oct 23, 2024
Collaborator Author

tl;dr; thank you for all the feedback - our intention is to implement APIs described in this RFC and roll them out in developer preview for Angular v19!

Shipping it as a developer preview in Angular v19!

Thank you so much to all of you that left comments, questions, and feedback in this RFC. It was helpful in understanding people's impressions of this API and functionality.

Summary of the discussion questions:

  1. Is it clear to you what is meant by "incremental hydration"?

Mostly the answer here was "yes", but there were a few clarifying questions people asked.

  1. Does this syntax make sense to you? Specifically consider the difference between regular triggers and hydrate triggers. Is there an alternative that might work better?

The answer here is also largely "yes it makes sense", with some suggestions for a@hydrate block as an alternative. We had a few questions about execution between trigger types, which were clarified in the comments.

  1. Is the defer syntax becoming too hard to read or understand with multiple triggering paradigms and conditions?

The answer here is that the syntax is clear, but there might be confusion around the behavior between the two trigger types. We hope to address this with clear documentation.

  1. Do you see yourself commonly using the same triggers for defer and hydrate? Or different conditions?

There wasn't much response here to indicate there were concerns.

  1. Do you have components you would like to use incremental hydration with but would be unable to due to the potential for stale data? Would that change if incremental hydration was triggered by inputs changing? Similarly would that change if hydration was triggered by signals changing?

Similarly there wasn't much response to this question. I think we'll likely get more feedback as people try this feature out.

Wrap up

Based on all the comments and feedback we didn't find any use cases that were not covered in this design. There's some interest in a specific@hydrate block, but we felt that the hydrate syntax for defer blocks was a better step forward.
We've included this feature in v19 as a developer preview API. So we're looking forward to your usage and feedback of incremental hydration with the upcoming RCs, final release, and beyond.

Thanks everyone!

You must be logged in to vote
0 replies
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Category
RFCs
Labels
None yet
18 participants
@thePunderWoman@brandonroberts@hheexx@mgechev@e-oz@osnoser1@yjaaidi@alxhub@naveedahmed1@crisz@t1m4lc@samuelfernandez@muhammadawaisshaikh@ilirbeqirii@zygarios@YonatanZviLevy@godhelpme1993@mixi342

[8]ページ先頭

©2009-2025 Movatter.jp