One if the things I love about rust and the wasm frameworks compared to js frameworks is how everyone's on the same team. There's no politics between the different frameworks and everyone has the same goal of getting rust wasm to more users and make it better for everyone. I really hope this doesn't get lost when it gets more popular.
Hey Greg, love these videos! Was really cool to get a better look of how these work under the hood. I'm really excited about the future of Leptos and Rust WASM
It seems like the next logical step would be to somehow identify "completed" tags and (shallow) clone those. For example, a td with class="col-md-1" is created many times during this benchmark. If this were somehow constructed once and then clone_node used, it would bypass a ton of work for creating that tag. I do think this is a common situation in real apps and not just a benchmark like this, so a real app would benefit from such an optimization. I can think of a couple ways that I'd initially try to approach this, but this is just with a naïve understanding of how things work: 1. Track commonly created "complete" tags and count how often they've been seen. Use some kind of heuristic based on that to determine that it's worth caching the entire tag and then do so. 2. Create a mechanism for programmers to specify that they want a tag to be cached. This has the benefit of having no overhead unless the feature is used, but it also adds a large burden to the implementation. I'm not a huge fan of "secret sauce" like this, but I could also see it being the most frictionless way to provide this implementation. The next logical step after that would be to detect partially-completed tags and cache those. For example, you detect that a div with a specific class string is often used, but the id differs (contrived example, but I'm sure this happens a lot). The div could be partially created with that common class string, cached, and then anything extra added on top of the cached tag.
You’re completely right, and doing this at compile time is actually how most of the fastest implementations in this benchmark (things like SolidJS or blockdom in JS, Leptos and Dioxus in Rust) actually work!
I've seen a few of your interviews lately and your other videos, (btw, your camera presence is fantastic and you really excel at interviews and these kinds of informational videos, it's really a gift) and you've mentioned Dioxus comparisons in the past and obviously like yew it uses a full virtual dom diff and rather than fined grained reactivity but I was wondering if you've played with and what your thoughts are on the Liveview approach that avoids wasm entirely, updating the dom via a websocket and minimal js glue. For me, the main goal is mostly to be able to write rust code and not javascript and both approaches solve that problem so I'm happy either way. I'm just curious if there are implications I'm missing that makes one approach "better" than the other? Is including wasm in the mix actually better to enable a hybrid client/ssr feature set?
Node cloning is crucial and most hard part to achieve the performance of the top contenders in JS benchmark, after each clone you have to search e.g. for label node and set text to corresponding data value. if you re not careful this could lead up to a mess / hard to read and write user code. but if done right users would not even notice the difference.
Very important point and to be clear, this improvement was even just with *shallow* node cloning, ie creating individual elements with el.cloneNode() instead of document.createElement(). Cloning deeply and walking to set up reactivity is indeed quite hard!
@@gbjxc I know, I was assuming deep cloning btw. I have done the work btw to get there in the list of the bench purely in JS that is, but I am hoping Rust / better lang will get there too at the top some day.
Instead of interning String into a UTF-16 cache, is it possible to alter the String representation from UTF-8 to UTF-16 of any code (Rust, C, whatever...) compiled to WASM ? This way all String representation in WASM will already be in UTF-16 format, so no cache requirements anymore, and UTF-16 to UTF-8 conversion will be faster (only send the first 8 bits of each character in most cases...) for required use cases like communication with a database.
This changes semantics. Code that worked without issues before will suddenly fail, likely with runtime errors. There probably is an UTF-16 String crate that you would be able to use, if you really want to switch perhaps with some further abstraction thats likely to be compiled away. BUT, AFAIK, that won't solve the overhead entirely. IIRC wasm-bindgen does have 2 separate pools for Rust memory and shared memory right now so it would still need to be copied, just not validated anymore (which you might actually have to manually implement btw). But I could be wrong about the separate pools, it's been a while.
17:36 wouldn't it be practical to insert a counter into all strings shared and once a string appears a certain number of times it gets cached? It would have a small overhead compared to manual tuning like you did but it would work well with both unique and repeating strings.
Do you use same optimisation in leptos? If so, is it enabled for every create_element? Or maybe just in ? What do you think about moving this cache to js layer. For example instead of using intern function for tags, use array of tags (nodes or names) in js, and pass only its ids?
We use this same shallow node-cloning for every HTML element, that's right. We also have a more complicated optimization that can clone an entire template, in a way that wouldn't work as well in Yew. I've experimented with moving it to JS and it hasn't made a real difference. But the sledgehammer library now used by Dioxus does a lot more in terms of optimizing WASMJS stuff, you should check it out!
I'm really enjoying these general Rust gui videos! In another video you mentioned direct WASMDOM, but I see nobody mentioning direct WASMWebGPU. This could get 2d-renderers like Iced's iced_wgpu, Xilem's Vello and Slint/Flutter's Skia to near native performance on web. Why is WASMWebGPU not being considered or talked about? What is the ETA of WASMDOM? Also, how do you see the future of cross-platform gui frameworks targeting DOM vs renderer vs mixed?
Personally, I’m skeptical. There are some really hard problems related to shipping a whole native renderer to the browser in WASM: binary size, accessibility issues, and inability to do server side rendering come to mind. These aren’t an issue for every category of app (well, a11y should be but isn’t always front of mind) but there are a lot of sites that are better served by shipping HTML and adding some interactivity.
Could the renderer and framework not be cached as wasm modules? That would only leave a slow initial load. Are there technical limitations for accessibility or SSR (still with slow initial load)? Flutter claims to be accessible and Xilem also states it as a priority. I agree DOM will probably remain be the better choice if you don't need native apps, or if you need fast initial load, SSR or SEO.
23:00 shouldn't you probably remove the string interning? If you only ever create one element each, it seems unlikely to me that the respective string will be used more often. And the interning isn't without overhead, as you said. EDIT: NVM, you removed it a few seconds later.
What if we make an npm package, or put on a cdn or something, that hashmap, for all the common lookups... get that hashmap cached by a ton of browsers separately from the yew app; that way the hashmap can be reused across totally different sites and it doesn't need to be loaded by the browser every time the delivered wasm changes or the page is hard refreshed or something The startup for the app would load that hashmap into the wasm heap and would already exist before anything even gets rendered
2 things to clear up: 1) I get the impression that you think that the strings will be in the binary. They are not. They will be added at runtime. The added size is just because of the additional Code that gets added. 2) WASM has yet to stabilize an official module system. From my understanding, it is very unlikely that caching across multiple pages will be done without that. I actually vaguely remember that in many modern browsers even cross page caching for other assets is disabled for security reasons, so perhaps it might never happen.
You're correct but the wording of the chart is incorrect or misleading in this case... Just checked and I can confirm the WASM binaries are not served compressed in these numbers. Current Yew binary uncompressed is 183kb, with interning it's 188kb, with node cloning 192kb. Those gzip to 67kb, 69kb, and 71kb or so.
I learned from this video and prev one is performance isnt that big deal unless you are going for react or angular , i think its time for startups to rly consider anything other than react or angular.
@@CottidaeSEA yeah add to that the support for such frameworks is packed up by names( FB and Google ) We can safely say we are being held hostage by these frameworks and we need something drastic to change this
One if the things I love about rust and the wasm frameworks compared to js frameworks is how everyone's on the same team. There's no politics between the different frameworks and everyone has the same goal of getting rust wasm to more users and make it better for everyone. I really hope this doesn't get lost when it gets more popular.
aside from remix, I've generally observed the same thing with the js framework maintainers
so positive to see yew and leptos devs helping each other out ♥
It's so nice to see somebody who actually knows what they're talking about and also so willing to share knowledge.
This indirectly gives a nice, practical overview of performance testing for the web. Thank you very much
You’re very welcome!
Hey Greg, love these videos! Was really cool to get a better look of how these work under the hood. I'm really excited about the future of Leptos and Rust WASM
you are the man! I started to love Rust a couple days ago and now I'm starting to love the community too!
Very useful and necessary videos. I'm currently writing a webassembly chat room. This information is just in time! Keep it up
Glad it was helpful!
Amazing video, loved previous one. Love this one. Keep the content coming!
It seems like the next logical step would be to somehow identify "completed" tags and (shallow) clone those. For example, a td with class="col-md-1" is created many times during this benchmark. If this were somehow constructed once and then clone_node used, it would bypass a ton of work for creating that tag. I do think this is a common situation in real apps and not just a benchmark like this, so a real app would benefit from such an optimization.
I can think of a couple ways that I'd initially try to approach this, but this is just with a naïve understanding of how things work:
1. Track commonly created "complete" tags and count how often they've been seen. Use some kind of heuristic based on that to determine that it's worth caching the entire tag and then do so.
2. Create a mechanism for programmers to specify that they want a tag to be cached. This has the benefit of having no overhead unless the feature is used, but it also adds a large burden to the implementation. I'm not a huge fan of "secret sauce" like this, but I could also see it being the most frictionless way to provide this implementation.
The next logical step after that would be to detect partially-completed tags and cache those. For example, you detect that a div with a specific class string is often used, but the id differs (contrived example, but I'm sure this happens a lot). The div could be partially created with that common class string, cached, and then anything extra added on top of the cached tag.
You’re completely right, and doing this at compile time is actually how most of the fastest implementations in this benchmark (things like SolidJS or blockdom in JS, Leptos and Dioxus in Rust) actually work!
Loving all the videos on this channel, very informative and each topic is engaging. Thanks Greg!
Thanks so much!
I've seen a few of your interviews lately and your other videos, (btw, your camera presence is fantastic and you really excel at interviews and these kinds of informational videos, it's really a gift) and you've mentioned Dioxus comparisons in the past and obviously like yew it uses a full virtual dom diff and rather than fined grained reactivity but I was wondering if you've played with and what your thoughts are on the Liveview approach that avoids wasm entirely, updating the dom via a websocket and minimal js glue.
For me, the main goal is mostly to be able to write rust code and not javascript and both approaches solve that problem so I'm happy either way. I'm just curious if there are implications I'm missing that makes one approach "better" than the other? Is including wasm in the mix actually better to enable a hybrid client/ssr feature set?
Node cloning is crucial and most hard part to achieve the performance of the top contenders in JS benchmark, after each clone you have to search e.g. for label node and set text to corresponding data value. if you re not careful this could lead up to a mess / hard to read and write user code. but if done right users would not even notice the difference.
Very important point and to be clear, this improvement was even just with *shallow* node cloning, ie creating individual elements with el.cloneNode() instead of document.createElement(). Cloning deeply and walking to set up reactivity is indeed quite hard!
@@gbjxc I know, I was assuming deep cloning btw. I have done the work btw to get there in the list of the bench purely in JS that is, but I am hoping Rust / better lang will get there too at the top some day.
Instead of interning String into a UTF-16 cache, is it possible to alter the String representation from UTF-8 to UTF-16 of any code (Rust, C, whatever...) compiled to WASM ?
This way all String representation in WASM will already be in UTF-16 format, so no cache requirements anymore, and UTF-16 to UTF-8 conversion will be faster (only send the first 8 bits of each character in most cases...) for required use cases like communication with a database.
This changes semantics. Code that worked without issues before will suddenly fail, likely with runtime errors.
There probably is an UTF-16 String crate that you would be able to use, if you really want to switch perhaps with some further abstraction thats likely to be compiled away.
BUT, AFAIK, that won't solve the overhead entirely. IIRC wasm-bindgen does have 2 separate pools for Rust memory and shared memory right now so it would still need to be copied, just not validated anymore (which you might actually have to manually implement btw). But I could be wrong about the separate pools, it's been a while.
17:36 wouldn't it be practical to insert a counter into all strings shared and once a string appears a certain number of times it gets cached? It would have a small overhead compared to manual tuning like you did but it would work well with both unique and repeating strings.
You make such great videos! Keep them coming.
Glad you like them!
More of these please, thank you
Great video. I’ve seen some videos on optimizing the hashmap hashing function. I wonder if that could be another optimization to help yew along.
Do you use same optimisation in leptos?
If so, is it enabled for every create_element? Or maybe just in ?
What do you think about moving this cache to js layer. For example instead of using intern function for tags, use array of tags (nodes or names) in js, and pass only its ids?
We use this same shallow node-cloning for every HTML element, that's right. We also have a more complicated optimization that can clone an entire template, in a way that wouldn't work as well in Yew.
I've experimented with moving it to JS and it hasn't made a real difference. But the sledgehammer library now used by Dioxus does a lot more in terms of optimizing WASMJS stuff, you should check it out!
@@gbjxc Is leptos going to move to sledgehammer? Or would leptos not gain as much / any value from it?
Leptos Merch when???!!!
Haha maybe we need a website first 😅
@@gbjxc The website will use React I assume 😂
We need that merch
This was amazing! Thanks for making great educational content ❤
I'm really enjoying these general Rust gui videos! In another video you mentioned direct WASMDOM, but I see nobody mentioning direct WASMWebGPU. This could get 2d-renderers like Iced's iced_wgpu, Xilem's Vello and Slint/Flutter's Skia to near native performance on web.
Why is WASMWebGPU not being considered or talked about?
What is the ETA of WASMDOM?
Also, how do you see the future of cross-platform gui frameworks targeting DOM vs renderer vs mixed?
Personally, I’m skeptical. There are some really hard problems related to shipping a whole native renderer to the browser in WASM: binary size, accessibility issues, and inability to do server side rendering come to mind. These aren’t an issue for every category of app (well, a11y should be but isn’t always front of mind) but there are a lot of sites that are better served by shipping HTML and adding some interactivity.
Could the renderer and framework not be cached as wasm modules? That would only leave a slow initial load. Are there technical limitations for accessibility or SSR (still with slow initial load)? Flutter claims to be accessible and Xilem also states it as a priority.
I agree DOM will probably remain be the better choice if you don't need native apps, or if you need fast initial load, SSR or SEO.
I'm not a frontend guy (tho I know a thing or two), but after hearing so much about Leptos and seeing your videos I want to try it :P
23:00 shouldn't you probably remove the string interning? If you only ever create one element each, it seems unlikely to me that the respective string will be used more often. And the interning isn't without overhead, as you said.
EDIT: NVM, you removed it a few seconds later.
Good eye! :-) seriously impressive to see that in real time.
Where can I get that dazzling Leptos Hoodie!?
Hey I want to try the rust ecosystem . Can you help me ?
What colour scheme are you using in nvim please?
github.com/dikiaap/minimalist
@@gbjxc Hey, do you also mind sharing the font you were using?
What if we make an npm package, or put on a cdn or something, that hashmap, for all the common lookups... get that hashmap cached by a ton of browsers separately from the yew app; that way the hashmap can be reused across totally different sites and it doesn't need to be loaded by the browser every time the delivered wasm changes or the page is hard refreshed or something
The startup for the app would load that hashmap into the wasm heap and would already exist before anything even gets rendered
2 things to clear up:
1) I get the impression that you think that the strings will be in the binary. They are not. They will be added at runtime. The added size is just because of the additional Code that gets added.
2) WASM has yet to stabilize an official module system. From my understanding, it is very unlikely that caching across multiple pages will be done without that. I actually vaguely remember that in many modern browsers even cross page caching for other assets is disabled for security reasons, so perhaps it might never happen.
For the increase in size, the chart says it's the post compression size, while you seemed to say it was the pre compression size.
You're correct but the wording of the chart is incorrect or misleading in this case... Just checked and I can confirm the WASM binaries are not served compressed in these numbers. Current Yew binary uncompressed is 183kb, with interning it's 188kb, with node cloning 192kb. Those gzip to 67kb, 69kb, and 71kb or so.
whats the benefit of using yew over preact, besides one is js and the other is rust?
I learned from this video and prev one is performance isnt that big deal unless you are going for react or angular , i think its time for startups to rly consider anything other than react or angular.
The problem is primarily in competence. Angular and React have more devs, which means easier to hire and more community devs.
@@CottidaeSEA yeah add to that the support for such frameworks is packed up by names( FB and Google )
We can safely say we are being held hostage by these frameworks and we need something drastic to change this
@@lMINERl Absolutely, it is an oligopoly which really shouldn't exist. I think Preact is good as it taps into the React community.
Sounds like the kids are having some fun!
Not even my kids! The best part about living in a city.
TIL: CloneNode is faster than createNode 😲Btw nice hoodie, where can we get one of those? Asking for a friend.
you have stuff in your nose
love you doe, just you know... FYI