Ben Wishovich - Full Stack Rust - Building Rust Websites with Leptos

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Applause] uh first off I want to thank you all for being here um unless I'm mistaken this is the first conference talk related to leptos um that anyone has ever given so uh this will be an interesting experience for all of us uh for my own curiosity sake how many of you have heard of leptos before you came to the talk and the conference and all that stuff stuff interesting a pretty good number of you how many of you actually tried it again a pretty good number of you so um it's really been amazing how far this has come in the time that has existed and I feel very lucky to have contributed um at all right for those of you who don't know me uh my name is Ben was soich uh I am one of the core contributors of leptos lead maintainer we don't really have a formal structure um it's basically me and Greg Johnston the founder uh maintaining it Al along with the community so unlike some of our other Frameworks we don't have any money or funding so we're all volunteers you know which is fun I've been a web developer for about four years I started with react and JS and I'm still doing that but now I'm to rust when I can uh my first prpose was about 15 months ago um but lepos itself was only existed for about 16 and a half months so pretty early in the process right uh because everybody has one of these uh socials um I have a Blog that occasionally gets some views uh Mastadon LinkedIn I'm pretty easy to find on the internet so if you have any questions or just want to reach out you know please do so I want to shout out Greg as I mentioned he's the creator of lepop he built the uh reactive runtime and he remains our reactive runtime expert um without him the framework wouldn't exist as it is so shout out to Greg who is back in the United States so I have two goals with this presentation um one is to introduce leptos a bunch of you already know it but I'm assuming a bunch of other people don't uh and then we're going to talk about why you might want to choose it over uh for a front-end web application right and I think there are some compelling reasons for that that we'll we'll definitely get into here so leptos is a full stack web framework that lets you Leverage The Power of rust and fine grain reactivity to deliver interactive stable and Powerful web applications right it's like a dictionary you know description um and the short version is that it lets you build nicel looking websites right it does that performant uh the rest is all kind of buzzwords that we've all adopted in the web space right um lepos for sure I thought I would take the chance um the time to show you some of the examples of sites that people have built with leptos one of the questions that I always seem to keep that I keep getting is you know are there any commercial users right we're only a year plus some old and I'm thankful to say that we do actually have a few of them that I can show you today uh one of them is patter uh started by um rakish uh it is a kubernetes platform for deploying apps uh they built their control uh interface and their marketing page with leptos right oops I got to go back to my slides here rust Adventure if any of you met Chris biscardi or know about Chris biscardi from the community he rewrote his entire video Workshop platform oops in lepos with rust um very very lovely work with that um looks very modern right a little while ago um a Russ contributor put out a rusty tube site which is basically a custom frontend to YouTube built with with lepos right so you've got a lot of um Variety in here and then the California beach volleyball Association admittedly a little bit of a random uh site is also been ported to lepos and they seem fairly happy with it unless they're you know not telling me so whoops we'll go on through so I thought I'd take the chance I kind of had a debate here about whether to try to do a little tutorial via slides or try to do a little tutorial via um some kind of live demo and I've settled on a live demo so we're going to try to do that and learn a little bit about leptos while we're doing that um the question always comes up right what is fine grain reactivity if you remember from the definition that we gave leptos is a fine grained reactive framework um and a lot and that's become the trend in the industry usually by talking about signals um every framework except for react has either had signals is implementing signals or is doing something related to signals at this point uh it's the trait toour so I thought I always have a laugh with this um it's a little bit of a deep cut we'll get into it basically fine grain react ity is the idea that you can take certain bits of reactive elements um a bit of data an equation something like that and you can keep track of who is accessing it and you can update only the things in your view in your web app that or whatever that depend on it right that's what makes it fine grained a lot of the signals applications are not as fine grained you know they and they are looking at updating more than that at some boundary like maybe they update the component maybe they update the page you know whatever fine grain you have to update the specific thing you know that depends on it talked a little bit about signals uh here's an example of a signal from the leus framework uh it's basically a bit of data that we put into a wrapper type so that we can do things when you either access it via get secret or write to it with right Secret you can kind of see here this is a string type rust nation is the best um and that is a signal this is our first leptos component um I put this in here not so much to talk about components we'll talk about components in a bit but I put it in here to kind of demonstrate fine grain reactivity right so if we look at this thing we've got that same create signal thing in our component we've got our view macro that generates uh HTML from a combination of HTML CSS and those little bits of rust in the curly brackets uh and we have a form Handler that updates when you type in it and the thing that makes it fine grain reactive right and the way that this works is that we know that the call to dot get on this on that get secret item every time we do that we keep track of who depends on it so and then whenever we all uh right secret we know that we need to update this little bit of of the interface right only the little bit between the curly brackets there are a lot of closures in our framework precisely because we need to rerun little bits um unlike some of the other things that you might be used to components will only run once if I change the secret the static stuff in this uh example won't change right and that's always fun the difference between that kind of framework and a Dom framework is that basically say in react you update a bit of data they don't really know exactly what depends on it so they just render some version of the whole thing whether that's a page or a component uh depending on kind of how you set it up and that's fine it works pretty well but it's not nearly as efficient um as signals can be so let to will let you build almost any kind of site with almost any kind of method that you want right we have client side rendering support where almost all of the work happens on the client right page rendering and whatnot and we have server side rendering support with and without hydration so that you can do that as well CSR or client side rendering is about serving HTML JS and web assembly files um just just as files right so it can run on any place that'll let you serve files we send down the HTML and the JS like this sample here you can kind of see there's absolutely nothing in the body there and the JS and web assembly will fill that in dependent on you know what you want what route you're navigating to that's client side rendering we have an example of what that looks like with The Hacker News example over here it's one of our uh one of our examples in the left host repository um this one is doing client side rendering so you can kind of see here that we pull in all of the files we wait until they're loaded all the way and then we run it and you can see at the bottom that the there's a there's an API requests to news right so the disadvantage to this besides a larger bundle size from having to have all the HTML Generation stuff inside of it is that those data queries cannot occur until after right until after we've loaded the whole file this is artificially slowed down it does not take this long to load the files but it's easy to see kind of how that works SSR is basically the opposite we do most of the HTML rendering on the server and then we populate it later with little bits of data async stuff that we need to fetch to make the page load that's hydration uh in lepos specifically by default we then navigate on the clients so um after that it will generate the HTML on the clients and only fetch stuff from the server that it needs like uh from the API basically and this is what that looks like the same example in SSR if you notice here there is no data fetch at the end of the loading and that's because that is now stream down as a result of the basic page load so if you're doing a bunch of data fetching maybe that's something that you want to do all right so I thought um as I mentioned earlier that we could do a little demo uh I put together uh a really basic starter to build a counter app where you can get some data from the server and you can update it and you can kind of see how that works inside of lepos right so let me Wander over here to our uh to my laptop and see how this looks uh can everybody read that or do I need to make the font bigger bigger okay um let's try okay so I use lunar Vim for this which is fun um for most of our templates you have to install cargo leptos and then install the wasm 32 unknown un own Target um I've already done that so I'm not going to do that but it's pretty easy once you do that you can use cargo leptos new to get one of the templates that somebody has made somewhere right we've got a pretty broad uh set of those this one is a little bit more stri down just so that I can Implement stuff for youall so this is the basic structure of a lepos app and we'll turn on the side view here um this one this template is running on axom but we have a wide variety of backends that you could be running on um so for those of you who are familiar with axom for example if you were to look at the main here you'd be pretty basic right we've got our main function it runs the axom router um you know it serves it um the interesting part with this page is leptos routes and some of the setup that we do for that basically we set up a trait that lets you almost ignore this file for routing it will automatically render um and add routes for any leptos routes that you add so we're not going to be back here but I thought it would be fun to mention uh let's go look at app so as I said this is a basic leptos component um it's got a stylesheet that we load in from static link it's got a title tag components it is basically HTML and CSS with little bits of rust sprinkled in RSX maybe or rxm L we don't really have a name for that that I know of um so let's run this example oops not that let's run this example and see what we get uh we have pretty much cargo and cargol like commands right in our cargo leptos system you know you can do build you can do run um but today we're going to do watch and I'm going to add the hot reload flag here um for other reasons we'll talk about in a little bit so now it should be loaded in our browser that I will go to here and reload right white screen H1 that's all that we have in here so far um let's so if we're building a counter right we need to add a way to store the count and because I don't have a database and this is a very simplistic example um we're going to go back to main here and we're going to create a little mutable wrapper that we can pass in so I can do let count um Arc whoops yes RW lock uh I 64 say and we'll set that to the default so everything in main runs the first time you load it right it runs on Startup and then it goes into the event Loop down at the bottom with aim serve so we're going to create the default one up here and then we're going to pass it to leptos I'm going to modify the leptos routes a little bit to add some additional context is still looking good okay and basically the way we can do that is we can stick that count into whoops I'm not in not in that I need to do a closure here it's always closures with lepos closure provide context and count probably have to clone it um um because so many things in here are dependent on uh probably don't need these brackets either now I think about it see how that goes ah right we haven't imported our W lock or the other thing so we'll do use standard sync RW lock and Mar okay so it should be somewhat happy ah this is a very common issue as I said we we have problems with the need to Black screw no coming back all right with the need with how ownership Works inside of a UI system right it's pretty common I think amongst the UI Frameworks but we just need to add a little move here to say that it can keep that clock right and that compiles and nothing is going to change here because I haven't changed anything but that's all set up now so now we can go do something fun let's go to our app RS and let's create a server function and the reason I'm creating a server function here is that I want to return data from the server to the front end by default right nothing that lepos has on the back end is sent to the front end you have to do that explicitly right and one way to do that is to use a server function if you had an external API or something you could do a fetch request um something like that but we're not going to do that whoops they need to be async uh server functions are really neat they're one of my favorite features uh let's do get post they're one of my favorite features because they really make that process easy right when we call this we're just going to call it like a regular um rust function from the client code it doesn't take any arguments and it returns a result with some type in this case we'll say I64 and it Returns the server function error like so we'll do okay sorry about that I don't know why it's doing that but okay okay so I guess it's common for the room we'll we'll deal with it okay so we've got this um so from Context we can get the arc RW lock right uh what should I call that uh count wrapper the leptos context is nice because it's basically creates a tree of um items from that you can pass in at different levels and then extract out um so you can avoid prop drilling by using the context here um which is why I can get away with getting the count wrapper without actually adding it as an argument to the function right uh Arc AR W lock I64 the the context is keyed by the type so you can only have one Arc RW lock I64 in here unless um unless they're in separate parts of the graph if they ever get on the same level you can run into issues where one will replace the other uh which happens sometimes Okay so we've got expect context here if I look at this type it's still unknown why is it unknown well we'll come back to that it's still happy so oh canot right canot we got to import arcs again ah the fun of rest okay so if you look at this here now it's complaining about that but it's an arc RW lock I64 we can pull out um count wrapper. read right because it's an RW lock and that's how you get a read handle to the thing in the RW lock um let's count equals and let's I'm assuming this returns a lock result I don't think I need this question mark but we'll find out okay expected ah we do need that question mark right found enm result because that can fail right I'm not actually well versed enough in the RW or or lock crates to tell you why but and this needs to be dereferenced here all right so we're back to compiling we've got our serve function uh we've got the get and I don't know why I called it get post get count that makes more sense all right so we'll go back to the homepage Here and Now I want to get that bit of information out of um from my server function inside my component so the component right is regular rust it's a regular rust function and then the HTML goes in the view function so we've got our little H1 for the title and I I have a built-in formatter so I don't really know why I'm doing this but sure okay so the way to get data from a server function or some other thing on page load is to use a resource right so we can define a resource create resource right and the reason that we create this structure for a resource is that async functions in this kind of need to be managed right it might be loading it might be okay it might be error we need to be able to tell leptos what to do if those situations occur um and the create resource argument whoops takes a tuple of dependencies in this case we don't really have any right now and then we'll call the function I don't know why I keep doing that get count here as if as because it's a regular rust function right oh and this also needs to be a closure that takes a tupal argument that I don't care about and we're good to go with the resource so now remember how I said that the um we need manage that state and show different things dependent on what it is well uh we do that with either a suspense or transition component here the suspense will render the fall back if um if it is still loading and if it's not loading and return to result we can tell it what to do here the default fall back which I could Define but I'm going to leave blank is nothing um so maybe we'll Define a fallback that says you know loading sure why is that that's a weird font effect um anyway yeah few I don't know let's say that's a P tag and we'll put in loading uh the neat thing that we've done now is that you can either quote it or not quote things inside of tags um I usually end up quoting them but I'm not very consistent just so that rust analyzers a little bit happier right but it's up to user preference for that g to suspense and then because we have implemented um because we have implemented the types necessary we should just be able to call cter resources in here and we should get something um but before I do that let's let's label it let's make it a little nicer uh span count same and we'll close the span and maybe the formatter will kick in here okay so now if I look at the page um you can now see that it's got count zero right because the default of an arc RW Lo I64 is zero so we've basically accomplished our goal of showing the count on the page but we need to do a little bit more if we want to edit it right we need um to make it more interesting we need to be able to update that thing so to update that thing I like to create another rust function server function here has the same type basically because it's still going to return an I64 and a server function error which means I probably could have copy pasted it there you go and again we're going to return this um one way that you could get the value here is I could just say let count equals get count right the rust function above that we're getting the count from because it is a regular rest function there's nothing particularly special about it um we could do that but um I should point out that that can lead to law contention and somebody's probably going to say you know why didn't you just get it from the arrw luck right the answer is that you can I'm just going to do it this way uh expected function args and I forgot the parenthesis here um we need to add some items here we need to know how much to increment this by um when we do that so let's add an argument to our server function an I64 and then we can get we can update that value right let count equals count plus increment by and return the new count unless I need to put a question mark here again okay so we talked about resources as a thing that exists in lepos those are great for getting things when the page loads they'll start loading on the server and be streamed down when they're done um but sometimes you want a different thing sometimes you want an action right you want to be able to trigger a server function based on some principle and we call that an action uh and that's what we're going to do with this we're going to create you know that structure so let's do an action oops we do it up here server functions and actions are tightly coupled together to make our lives easier um we have a create server action that basically avoids most of the boilerplate of creating a regular action which you could use to call any regular R function but we're doing server functions here so we can just tell it that we want to use the get count server function sorry not get count um the name of the generated struct that the server generates oops um is the combination of this converted to not camel case the opposite of that um I forget what it's called but basically you capitalize the two words and remove the underscore and where's the server action here okay so put this in all right so it's still compiling I think it'll be happy but we need to add a method to trigger that and coupled with the action let's let's let's make this a little more descriptive let's say update count action sure I'm coupled with that tightly coupled is the action form which is basically a regular form where we have a little bit of boilerplate where we can just refer to the action that we created instead of having to worry about setting up the routing right the server function will create a rest endpoint that's publicly accessible and by doing this we will tell we it will automatically fill in what that route is no none of that and it works exactly how you would like how you would expect a form to work you've got inputs um the name is the argument to your rest function right so we our argument was called increment by and we can say this is a type number and yeah that should be pretty basic maybe I throw in a little H1 to delineate when that starts which probably is not what I should do but go with it anyway update count I'm realizing now that I forgot the trigger here so we do that with a basic button button type equals submit just like a regular form and we can say update and close button okay so assuming I did this right and didn't screw it up which is a pretty big assumption yeah it's automatically reloaded the page and now we have a form with a little update form and let's see if we what happens when I try to add to it that's I'm going to add three to zero update nothing happens but if I reload this page nothing happens that's annoying let's see if I hit update again what's gonna happen oh we don't get an error so that's pretty good uh let's see I'm not updating the you are absolutely right I didn't actually update the storage um so let's update the storage right uh writer equals what did I call that thing oh I need to get out of the context first you'd almost think that I wrote this once before almost uh count no I didn't when I did it earlier I defined a type Alias so I didn't have to write Arc RW lock all the time and I probably should have done that here but I didn't just know that you can't do that uh put that in let's do a question mark and then we can do writer. write for an RW lock and we'll say um I'm really good at naming things on St and so that's now writer 2 and then we can say writer 2 equals new count and we should have updated everything question mark operator all right because expect context actually doesn't return a wrapping type type standard oh but this needs a question mark and mutable okay looking promising right so if we go back here and we have count zero we have update count three hit update again that doesn't update but if I reload the page count is now three the reason that it didn't update right is that we didn't tell that resource that's doing the loading on the page that we are depend that we need to reload that item if the server function runs right so if you look at here as I mentioned the first thing is a list of dependents for get count but it is also a list of things that um trigger that to refetch so we can take that action that we defined update count action and we can say you know we want the version of it which will update every time it successfully runs or doesn't successfully run and and we want to get the value of that version is a signal like most of the things here and this needs to be above there because rust that's how rust Works closure May outlive oh need another move closure outlive is one of those things that you just you get used to okay so now if I look at this and I run it again you can now see that it updated itself not as elegantly as it could have but every time I run this it will automatically update the element in the page and that's basically what we were trying to do while I'm in here I thought it would be fun to kind of try to show you the um the functions of hot reload because one of the things that I hear a lot is that hey I can't iterate very fast this is going to be a little bit tricky because you know I got to keep switching windows but if I for example go to the CSS for this which is in here somewhere I hope style yes it's install okay if I go here and edit uh edit this style say background color or something now red I save if I look at that it already did it right you can see at the bottom here that it's yeah it it did instantly as long as you're doing changes to the HTML and CSS that don't require us to recompile which dependent on it it will instantly do those changes you know over here and that's basically my live demo [Applause] so so this is the starter that I started with if anyone wants to go back and actually try that um you've basically built one of our starter templates at that point most of them have the count in it just as something to go in there and for people to look at um now it's my job to tempt you we've gone through the what is leptos now we need to talk about why leptos right and I've heard a lot of things about leptos and web assembly that either aren't true or kind of true but not really in the day-to-day the first one is that the bundle size is too big uh we'll look at um one of the examples of benchmarks later but the bundle size is usually less than say react obviously we can't compare with a pure vanilla JS implementation but it's quite competitive the startup time is too slow um web assembly loads more efficiently than JS but as you'll see soon the startup time still manages to beat some of the JS Frameworks uh that we need direct om access to the JS provided by the browser um I mean it be nice to have that but we found that that's not actually a performance Benchmark either and the last one we've already covered a little bit is compiling takes too long right every framework that gets discussed has the JS framework Benchmark put out by somebody named kraid I don't know his actual name I'm attempting to pronounce his GitHub but the link is here um and it looks like this I'm hoping no one can read that okay um and no one can see that either well anyway the point of this slide right is that if you look on the second column to the right you can see react Hooks and they're they're scaled from fastest to slowest right so leptos is doing pretty well there vanilla GS beats us spelt beats us solid JS beats us but not view not angular not react right and this Benchmark kind of runs a bunch of examples that test rendering time different things that are all listed here but you can kind of see that we're we're doing pretty well with this right so that kind of throws out the window that web assembly is the limiting factor in performance right compile times wise if you remember the things that I showed you earlier patter took about 5 Seconds um for an incremental build uh cbva is about 5 Seconds as well rust Adventure took two um all of these things I mean I personally can live with a couple seconds to think about what I've just done but if you can't we do have that hot reload as I mentioned uh which is this right uh I set up my own performance test because I'm curious and a little bit of a masochist um I took my blog site and built it in both remix plus expressjs and lepos and axom as closely to identical as possible um the details are all kind of here and then I put it under a lot of load and tried to see if it would Buckle right the homepage fetches three requests from a database uh SQ light in this case and the HTML CSS logic are as Clos as I could get them you know with a variant we ran this on digital ocean with these specs you know a couple vcpus four gigs of RAM and the big pipe so hopefully that's not a problem this is one I mean I love these graphs right this is remix plus expressjs this looks like a little clear you might be able to see um on the bottom we've got requests per second latency on the side and the heat map tells you how common that is um in the distribution and you can kind of see here that it starts at about 20 milliseconds goes down a little bit because of the jit compiler and about 100 Mil 100 requests per second it kind of starts to fall down right that's that's not a great place to be in your curve right leptos did quite a bit better right uh it's flatter for longer the variance in the latency is less and you can kind of see that we're good all the way up to roughly a thousand requests per second you know which is a very substantial difference right it is a and that translates directly to infra costs if you have to run a server and your server can run 10x more requests you've saved money you can get a smaller server and that's the takeaway I took from this example I'm sure it's not perfect um but it it makes sense to me uh the other benefits you get is rust type system and tooling so if you remember from the demo we could take the rust types we generated on the back end and use them on the front end exactly the same we didn't have to write a parser we didn't have to use Zod we didn't have to worry about serializing and deserializing just did it right that's amazing uh we get types of compile time and runtime and Russ's famous tooling right cargo Cargo leptos Russ format all these things are usually a joy to use and then you compare that to some of the other options and I don't know I know which I prefer I should say I do have to wonder how we got to this stage I think it was us we did this did this to ourselves I'd like to not have to deal with that one of the more interesting things that we found when I was reaching out to our commercial users um is developer time we are finding that because our tools the rust tools and the leptos tools do more work um they keep more things in the type system that the complexity that you need to keep in your head is less and that basically means that you can produce more complex things with less people I debated how to show this because I don't have Google resources to do ab testing on a bunch of stuff um so I just got comments from these users right um the patter uh Reish from patter basically told us that the little bit more time you might spend dealing with the types in leptos is um more than offset by the need to do very little debugging and that it mostly Works which lets them focus on features and less on fixing bugs and putting out patches the other problem I have with the russ is slow to iterate item is that I don't think the first past the post is usually the diiminates it easier Chris biscardi as I mentioned uh he's doing one of the other talks in the other rooms right now uh basically says the same thing that it lets him develop more with less effort um Alex from the cbva California not from but the developer who wrote The cbva Association you know I really should get like I want to put that on a card it's like I'm Ben from the California beach volleyball Association that kind of fun anyway he was saying that the performance of it with almost no effort was enough to handle on beaches with poor LTE right the internet reception on beaches Is Not Great usually I want to shout out to the left host Discord we've got a lovely group of people working in there they help us with answering questions they generate Community crates you know it has been amazing to have them our next release is coming out sometime soonish probably not 6 months from now but not today um we've already got some fun things in the pipeline uh most interesting for this is for your the users at least is that we're going to take the reactive system that we Define with the signals and make it more generic we're going to improve async data loading a little bit and we're going to get even more performance out of it right hopefully I've succeeded attempt you to at least try it um if you we're not paying attention or going to sleep here are roughly the reasons that we suggest it right as I mentioned join us Discord uh our website GitHub all of these things are free and open source we'd love to have you and that comes that brings me to the end of the [Applause] talk
Info
Channel: Rust Nation UK
Views: 4,879
Rating: undefined out of 5
Keywords:
Id: JJV5crU405s
Channel Id: undefined
Length: 44min 53sec (2693 seconds)
Published: Thu Apr 11 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.