-
Notifications
You must be signed in to change notification settings - Fork 25.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(DomRenderer): allow partial DOM hydration from pre-rendered content #13446
Comments
Ad wipeout on client bootstrap is a real world issue for us using universal and this hydration proposal should solve it. Our current workaround gets us partway there, moving server DOM into the same position in client rendered DOM but does not outsmart ad verification services that watch for DOM mutations, hiding the ad upon client bootstrap. Big thumbs up for opt-in hydration. |
LGTM, Keep in mind this is a huge problem with all js frameworks so for Angular to have a solution is a great win for when comparing different SSR solutions. The real solution is having Ads actually work together with js frameworks but that will never happen, other than AMP. I can see how it would be implemented by rewriting selecting root element and providing a different render path. For the |async you definitely have that problem with Promises due to the microtask while Observables do return synchronously. On the client, we can assume there will be batched data sent from the server to the client which gives us all of the results immediately. For Universal, we need to have the data available to the client synchronously anyways to reuse the server Http responses var res = {data: 'ok'};
var api = Rx.Observable.of(res);
var api2 = Promise.resolve(res);
var vm = {};
var vm2 = {};
api.subscribe(function(data) { vm = data; });
api2.then(function(data) { vm2 = data; });
console.log(vm); // {data: 'ok'}
console.log(vm2); // {} |
An alternative design would be to provide an alternate renderer that would extend @NgModule({
providers: [{
provide: Renderer, useClass: DomHydrationRenderer
}]
}) |
+1 for DomHydrationRenderer |
Two things:
|
+1 either solution will be beneficial and vital for us to move forward. |
We can still make the work generically, when using auto generated ids based on the place in the element hierarchy (and not based on the creation order). I think we should think this through as well before we decide. |
is HydrateDomConfig part of @angular/core? I get error when I try to compile the application. error TS2305: Module '"/home/fahad/Workspace/siteCuriouss/node_modules/@angular/core/index"' has no exported member 'HydrateDomConfig'. |
@FahadMullaji it's only a proposal. |
This proposal is super exciting! Has any thought been given to pre-rendered lazy routes? We can achieve pre rendered lazy routes via https://github.com/angular/universal/blob/master/modules/ng-module-map-ngfactory-loader/README.md Is it possible for the hydration to occur after lazy route is fetched and then rendering begins? Just curious on thoughts here. Universal has been great and straightforward to use so far; thanks to everyone involved! |
What couples the ComponentRef obj to the Dom string (cmpref.changeDetectorRef.rootNodes[0] & cmpref.hostView.rootNodes[0] ect)? Is there an explicit reference(i.e. dom string selector) or does this binding live in memory? Is there a possibility of calling createComponent with an existing dom node as an argument? |
Any updates on this - i have big issue with this as everybody here :( |
I quit working in Angular JS a year ago. I just got tired of all the
problems and false promises.
…On Sat, Aug 18, 2018 at 11:37 AM Vytautas Pranskunas < ***@***.***> wrote:
Any updates on this - i have big issue with this as everybody here :(
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#13446 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABU4JqXoyDHyfxps21n2DGm0jYang4h6ks5uSEK0gaJpZM4LMcBh>
.
--
Regards
Fahad Mullaji
|
Is there dom hydration problem solved in ather spa libraries?
On Mon, Aug 20, 2018, 9:26 PM Fahad Mullaji <notifications@github.com>
wrote:
… I quit working in Angular JS a year ago. I just got tired of all the
problems and false promises.
On Sat, Aug 18, 2018 at 11:37 AM Vytautas Pranskunas <
***@***.***> wrote:
> Any updates on this - i have big issue with this as everybody here :(
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <#13446 (comment)
>,
> or mute the thread
> <
https://github.com/notifications/unsubscribe-auth/ABU4JqXoyDHyfxps21n2DGm0jYang4h6ks5uSEK0gaJpZM4LMcBh
>
> .
>
--
Regards
Fahad Mullaji
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#13446 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADvMl2WKIU4PSv84mXBXAe-33WD-jbmAks5uSw1ggaJpZM4LMcBh>
.
|
@vytautas-pranskunas- |
gdi2290 What makes you think that ivy renderer will solve this sunce i have not found any mentions of solving this or introducing virtual doms in ivy?
I wonder why Angular team is silent about this forcing more people to be dissapointed...
…On Tue, Aug 21, 2018, 1:40 AM PatrickJS ***@***.***> wrote:
@vytautas-pranskunas- <https://github.com/vytautas-pranskunas->
Every framework, other than angular, has solved this problem. With that
said the problem might not be a one with the new ivy renderer
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#13446 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADvMl-LwoyJmtroffUkIvEGkXDtsMjm3ks5uS0jjgaJpZM4LMcBh>
.
|
For the ads, I think the ad code shouldn't initialize on sever, if it does I think it would be a policy issue for most of the ad networks/advertisers including Google Adsense. For this we can check and include ad code only when in browser. You can check if its running in browser
Adding ad code to SPA is little tricky, if your page is making an ajax request and main content of the page depends on completion of that request you should also wait for that request to complete before you add ad code to the page. Otherwise, if ad code is initialized before ajax request completes (and contents are populated) it would also cause ad network policy issue. |
yeah the issue isn't rendering ads on the server so much as trying to make sure angular doesn't remove/edit/change the ssr element. There was a solution which reattach the ad dom from the server to the new dom created by the client. Again the problem with that is the ad detecting dom manipulation. So the only reason why people want hydration is for ads since it's always faster just to replace the ssr view with csr view. There were solutions made to also keep the element in the dom and insert/remove around that element but would require some rewriting of the renderer to keep track of the elements. Ivy render will likely solve this since you can choose which elements you want to boot angular into and ignore the ad elements. |
Adds are not only reason why people want hydration. Hydration needed for prerendering because in scenario when page content is fetched after bootstrapping SSR has no flashing but prerendered. So hydrations needed for prerendered pages also and not sure if ignoring will solve this problem or you will have to ignore whole body because content is everywhere. I think best solution would be something simmilar like React Virtual DOM which checks what parts where changed and update only those one. |
Good stuff. Although the guide says the app must use SSR and points to a Universal guide. Does it mean it's not gonna work with SSG solutions like Scully? |
@BlindDespair hydration can be enabled in other systems that uses Angular APIs such as renderModule or renderApplication for server-side rendering. However each system may require some extra configuration (and extra code) to enable the feature, depending on a specific implementation of the system. // cc @SanderElias |
By default, Scully uses Puppeteer to prerender the app meaning there's no server involved. It just takes a snapshot of a page when it becomes idle. The DOM is rendered by Angular in this case, but naturally none of the APIs you mention get called, so hydration is not gonna work. Scully does have the option to prerender using platform server, but the puppeteer way makes development much more simple. Is there a chance to make it possible to generate the ngh data in the browser, serialize it and then provide it separately when pre-rendered app starts? Just curious if it's a dead end for snapshot-based pre-rendering or if there's still hope. |
@AndrewKushnir When we are using the PlatfromServerRenderer, it does work, but it comes with the known issues that are there for Angular Universal. Would it be possible to support that? |
@SanderElias The hydration logic is integrated with platform-server and requires it to provide the necessary annotation functionality during application serialization. Puppeteer is essentially no different than client side rendering from the perspective of the framework since puppeteer is just a headless chrome instance. Hydration is not supported outside of server rendering environments that depend on platform-server. |
@jessicajaniuk Would it be possible to get what is needed there? If I know what to add during serialization, I can do this inside our renderer(s). Is this serialization format going to be documented? |
Hey, this is great news. I'm wondering is this the reason for dropping support for preboot? If so, I can see how this would remove most of the functionality preboot provided, but how is a form submission attempt handled prior to bootstrapping on the client side? Will this just be something provided by the ServerModule? If there's been previous discussion on this then please point me to it. I haven't been able to find much information around dropping support for preboot. Thanks. |
I have played with the new feature and I see a few missing parts.
I have a page with dynamic components only and the whole page is recreating. In this case even the ngSkipHydration directive doesn't help @component({ |
@retry2z Hi thanks for your feedback, you should open a new issue on this to give it more visibility ! |
@retry2z thanks for the feedback.
Could you please provide some additional information on what the expected vs actual behavior is? As @JeanMeche mentioned, it'd be great if you could create a new ticket about it in the issue tracker (with a minimal repro), so that we can take a look and discuss further.
This behavior is intentional: the |
The yeah didn't provide the needed context what is the expected behavior here, so in a few days will try to provide repo. It seems to recreate the components, if they contains ng-container with componentOutlet it doesn't skips even if we apply the directive to the host. In the console count the component as skipped, but I can see the recreation of the template clearly. First thing first, will try to recreate it with a new project with clear guide, because this effect is from a pre update tests of a project. |
@SABRYX possibly related to FAST-SSR: #13446 (comment) |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
can we close this issue. there's no reason to keep this open |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
Thanks @bierzorutas and @denisyilmaz for your input. |
Closing as resolved :) Note that the original issue is not describing partial hydration, but a workaround for the issues with the destructive "hydration" that Angular had originally, to allow partial reuse of some of the DOM during the client-side bootstrapping. Partial hydration is indeed on our roadmap, but that's not what this issue tracks :) |
yes, the future merging with Wiz is amazing. Everything I wanted for Angular Universal is finally happening and it's exciting to see 🎉 There are more things, I'll share in the future, that are only possible with Resuming frameworks and Signals so I'm glad Angular can be part of that 🙌 I want to thank everyone who believed in me with Angular Universal and the vision I had for it. |
Wow, what a historic moment! Farewell, dear issue! 🎉 It feels like saying goodbye to an old friend we've been following since 2016. The bond we've formed over the years, the ups and downs, the anticipation... it's been quite the journey! 😄 Though I'll miss our regular updates, I'm excited for the next chapter in Angular's evolution. Cheers to the closure and onwards to partial hydration! 🚀 #Goodbye2016Issue #HelloPartialHydration |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
I'm recapping a discussion I just had with @alxhub and @tbosch. This is mostly Tobias' design.
I'm submitting a ... (check one with "x")
Current behavior
Typically when a page is pre-rendered, such as with Universal, the Angular application bootstraps in the browser, then blows away the pre-rendered content, and replaces it with newly created nodes. The DOM tree that is pre-rendered is often very similar, or identical to the DOM tree created on the front end, but there are issues that make it difficult for Angular to take over the existing DOM tree (otherwise referred to as DOM hydration).
The actual handoff of destroying the old DOM and showing the new DOM is pretty fast and seamless, so it's not necessarily a major UX issue in and of itself. Where it becomes problematic is in cases like ads that load in iframes (which is pretty much all display ads). If these ad iframes are pre-rendered -- which is a business requirement for many publishers -- and the iframe gets moved in the DOM, the iframe will refresh. This causes some ad networks to suspect abuse, as if publishers are trying to sneak more ad views.
Why Not Use the Already-Rendered DOM?
One issue is that with asynchronicity+conditional DOM (i.e.
*ngIf="data | async"
), the tree in the client may be rendered before the condition is truthy, whereas the pre-rendered version may have the full tree with async data resolved.Another challenge is that text nodes are not able to be selected by CSS selectors, which would mean the renderer would have to rely on child ordering in order to associate pre-rendered nodes with client-rendered nodes (which is not always correct). Similar challenge goes for elements in an
*ngFor
, the order must be assumed to be identical.The renderer would also be responsible for cleaning up pre-rendered orphan nodes. i.e. if 30 items in an
*ngFor
were pre-rendered, but only 20 were rendered in the client, the additional 10 nodes would need to be removed to prevent unexpected behavior.Proposal: Optional, explicit, partial DOM Hydration
Allow setting a user-specified attribute on elements to associate the pre-rendered version with client-rendered version. If the renderer comes to a node that it can't associate with an existing node, it will blow away the node and re-create it. The developer would be responsible for setting these ids on the elements they care about. Example:
Component:
This design allows the
DomRenderer
to traverse the DOM tree and match elements for each branch starting at the root until it can't go any deeper, at which point it would blow away the descendants and re-create them.Text nodes would all be destroyed and re-created with this design, as well as any node that doesn't have the set attribute,
pid
.I don't expect that the rendering would be user-perceivable, other than if there are discrepancies between pre-rendered and client-rendered DOM, but that's a concern even without this feature.
CC @gdi2290 @pxwise
@tbosch & @alxhub please feel free to add anything I missed (or misrepresented).
The text was updated successfully, but these errors were encountered: