Build Next.js apps at the speed of thought - Kirimase generate command deep dive

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
today we're going to do a deep dive into K's generate function and we're going to do that by building a classic demo project to-do application so what I've got here is uh just a blank nextjs project I've also run kiras in it so if we look at our config file um I've installed Shad C Nui drizzle with postgres under the hood um and next off for authentication so why don't we start with our first uh well actually let's run the dev server just to make sure that we can log in and everything is okay so we've got the classic login screen I'm going to go here sign in with Google use this account here and you see that we've already run into an issue uh let's see oh of course because I haven't run the um the migrations yet so let's first get our local postgres server running create a new um a new t uh database we're going to call this to-dos exit here and then if we look actually at the package Json you can see that um kiras has added these uh scripts right here um so we're going to run generate first and then migrate um so let's run uh bun DB generate bun DB migrate great so now if we run the dev server again let's head back to the homepage awesome get out of the dev tools um sign in sign in with Google use this account now great this is what we expect everything good got light and dark mode set up this is all just the the classic kiras initial initializing um uh function and and adding packages so so let's jump in with our first uh generate function so we're going to run cure generate if you're using um a package manager or haven't installed it locally you can run bun Camas or bunx ciras at latest and then generate um we'll wait for this just quickly to to download um so this prompt gives us the option to add a model a controller and a view uh we're going to select all of them here um we are then going to use server actions with optimistic UI for this uh Deep dive but I may do another one with the trpc and react hook form um uh options installed as well if that's something you want um why don't we add the API route here uh we're going to call this uh the table name to-dos this has to be plural and in snate case so if it was multiple words you'd say to-do items like that um in this case let call it todos then we pick our first uh field or column type so this is going to be um let's call this content uh okay I'm going to make this field required because we want that to be a required field um and then I'm going to add another uh field and this is going to be our Boolean toggle for whether it's completed or not so I'm going to call this completed um this is also so uh going to be required but the default is going to be false um and I think that's it so no other fields uh no index for now but yes I do want it to belong to the user so you can see that quite a few files have been created for us um so let's just we'll look at things here first so we can see on a macro level and then we'll jump into each of the files so first we have a schema um this if you were using Prisma would add the model to your Prisma schema in this case it creates a new um a new file a new typescript file that describes our um our model in um for our for our um tral omm uh we then create two I'm calling these are called service functions or I've heard them called service functions but these are a handful of already done um queries and mutations to intera with your database uh we'll we'll see that more in a second um uh what do we have here then we've got uh our API route that's created so again if you wanted to interact with this on an API layer rather than with server actions you would do it there um we have our server actions that are created um we'll jump into the utils uh and and see what's been added there but these are that's just a um I I think it's one of the validation functions that's written into there um we then have a model that's created and this is a shared model that will be used across any other uh models that you create um we then have a well actually let's jump into these first we've got a to-dos page that's a route for your to-dos we've got a to-do list component and that is as it sounds is uh the list of your to-dos and rendering that um to-do form that's for creating your to-dos um and then we've got use validated form this is a hook a shared hook that will allow you for um nice client side value uh validations across your forums and then use optimistic to-dos and this uh leverages the new features in react Canary um which allows you to have um a very nice and simple optimistic UI across your application and then find finally we are installing shatan UI components for the the various views that we use so a dialogue for the model um a form for the the form and a checkbox for the Boolean value so why don't we just uh first run bun DB generate to generate the migration and then run bun DB migrate so we can just see that everything should uh work right away so if I run um buev and I jump over to Local Host 3000 toos and then we've got this nice UI ready to go first too and I can create it like that easy as that I can also update it so if I hit save say this is completed great that's you've got your crowd operations already done literally in one command um so let's jump into what's actually been created under the hood so um I I ran a g commit right before this so we could see what has been changed so why don't we jump first into the lib file and into everything that's been created alongside the model so if we jump into the schema you'll see that there's this new file too. TS and if we jump in here we remember that we wanted we had a field called content and then we had a Boolean field um C completed uh ciras generated these two and then added an ID um I prefer the random uu ID uh for IDs rather than serial IDs um and so that is done for you here um and then because this belongs to the user we um we reference the user's table in the off um in the off schema here which is this one right there um so again all of this referencing stuff is already done right right out of the bat already um ready to go for you um there are then uh we use drizzle Zod under the hood uh to create uh types and and schemas and this is used for validation both on the front end and the back end so in here the basic notation that I've come up with here is that schema is for the backend validation and then anything with um params is for the front-end validation that's why you'll see uh for example that there is ID and user ID that is emitted from that uh schema and so we've got it from for inserting uh we've got it for updating and then finally we've got um we've got this to-do ID schema which is used for for uh deleting um any of these to do and then we have uh types and this is also used on the front end uh just for better DX and in general a nicer um building experience and then finally this complete Todo we'll go into this in a second but this effectively gets the return type of one of the quiry so that if you do have joins which you're able to do with kiras as well um your this complete to-do type will include any of those joins right away so you don't have to mess around with any new types so with that why don't we jump right into the queries um so here the queries are as I sound these are functions that should be already done so that you can easily get all of your to-dos um as well as getting a too by its ID um so you'll see because this belongs to the user we first do a call to our authentication to get the session um and then it's a simple drizzle call where we get users or we get to-dos where the user ID is the same as the to-do um user ID and then we return it as simple as that um and then for the uh get Tod do by ID it's the same thing except this time we pull in an ID which we have um nicely typed here um which you can see there and then again we can run that through uh one of the uh schemas that we generate with dzlead um which is super helpful if we then jump into the mutations the to-do mutations this is for me one of the really helpful gener generated files because doing mutations properly and handling errors can be timec consuming and quite error prone particularly when you just want want to get an MVP or something to get into your user's hands you don't really want to be focusing on uh covering all of your balance for arrows so I love this so if you see we start we've got create too again this is going to be as simple as CR it's create update and delete here um so if you see here we get the user session we then pull in um we pull in the the to-do prams because this is creating we don't have an ID or um a user ID coming in so you can see that it's just um it's just content andc completed um we then do a call to to user off we run uh we run the uh parameters of the function through to um or the arguments I never remember that we run those through this um this insert Todo schema that was created in the in the the model file um and we pass in those parameters and then we also pass in the user ID that we took from this session here and then wrapped in a TR catch we've got the actual creation logic um and because this is assumed to be running on the server side um we uh we can do the DB calls right from here um so you'll see in this case uh we are inserting into the to-do table this new Todo that is effectively guaranteed um from from here um what and then we've got error handling here nicely in line as well um same with updating um as you can see and then finally we've got uh deleting as well so super helpful so that's the model side of things if we then jump into maybe we go to the API route first uh this is the to-do API route um and we got an error here which I will have to look at later um this is just a classic API route or route Handler in this case um you'll see again it's a it's quite redundant code and that's why it's very nice to put it through uh a generator because we're effectively taking the the the parameters putting the valid ating them with Zod and then running some logic um or some sort of DB logic here um so as you can see if we go up here we we're validating we're running the the to-do um sorry the the service function um if there's an error we we return an error otherwise we return the to-do is Json and then we revalidate the path as well um so the same with updating um and the same with deleting so if we go now into the server actions it's not called action sorry it's called action SL too so if we jump in here uh right off the bat you can see we've got a used server um uh notation at the top to ensure that this is uh working uh as a server action uh we'll jump over this handle errors uh quickly and revalidate TOD D so this is very similar to the API route we just have these server actions that take in our input uh again nicely typed uh we uh run the the input through our Zod schema like always I mean this is effectively identical to the API route just uh in a server action form so it's much easier to call on uh your front end in um in our components and then validate um and then in this case we've got a nice handle errors function which just uh Returns the error nicely to the front end so the same for update and for delete um so that's the controller layer if we now head over to Let's jump into the utils really quickly to show you what was created there um oh and it's just these um these five or six lines that talk about um that are a few types that we're going to use uh throughout the throughout the UI uh so if we jump into the UI itself we go to the to-dos folder and we head into page uh let's start from here so this was this page that you saw here um we have got a uh revalidate just to ensure that this is a dynamic page so every time you refresh um it will be uh revalidating cache um we first got a call to check off and this is very simple it it says um uh it checks if if there's a session if there's no session it redirects you to the uh login page um we then have one of these service functions that we call to get all of the to-dos um and then very simple markup that we then pass the to-dos into the to-do list component so if we jump into the to-do list component uh there's a lot going on here first of all this is a client component and this may change in the future with partial pre-rendering uh we may look at introducing a new component here so that we can leverage uh suspense um so that's that's ongoing but if we look if we start with the to-do list component itself let's go down um and maybe let's start with the markup first so we can just see what's going on we've got a uh div this is the list which is this here and um and we've got a model um and that is that um effectively that plus um this well actually it's it's not being rendered right now um as you can see it's it's closed by default um but we've got a to-do form nested inside of it so if we click the plus button we open the model and then the modal State um is effectively being passed down into it so in active Todo um this will become a bit clearer in a second um so we've then got optimistic to-dos um if it's equal to zero which actually let's run the dev server quickly so I can show you what we mean here great if I delete this you'll see that we've got no to-dos here um so that's this component here this empty State um very simple uh NH H3 saying no to-dos uh get started by creating a new to-do and then a button which sets the model to open that's this model that's right here um you can think of the the model is really simple it is literally just a just a popup um and then we are that's why it's a shared component and then we're able to render anything inside of it that we like so this modal here all it takes in is um uh an attribute of whether it's open a function to set whether it's open or not and then a title which we've got um here so it's create to-do when it's when uh when there is no to-do selected uh to-do test but if we were to open it here because we have a to-do selected it becomes edit to-do um so then there's a to-do form we'll look at this in a moment um we've already gone through that and then we've finally got the optimistic uh to-dos this sit within uh an unordered list our optimistic to-dos if you haven't looked at the optimistic uh the use optimistic hook um it is a lot like use State um except there is uh there are mechanisms built in when you add you effectively dispatch a new event uh to optimistic to change and update the optimistic to-dos if it doesn't complete it will revert back to the previous state so you can think about this as just to-dos do map um and we'll go into that implementation in a second so this is super simple uh react code here um we're just looping over the list and then we have a to-do component um if we jump down into the to-do component you'll see it takes in a um a to-do which is typed as that complete to-do um so if there were any joins happening you would have access to all of those attributes right away no issues on the type um we've got some helpful just code here so uh when we go into the the use optimistic to-dos implementation you'll see that while uh to-do is pending um it will either will update the state to either be optimistic to be called the ID to be called optimistic or for the ID to be delete when um optimistic is either when it's being added or updated and delete is when it's being deleted and this allows us to uh manipulate the uh UI in that interim phase while um the UI is optimistic uh so those are just helpful for making it the code more readable um so here just simple Tailwind class classes um and then we have the to-do content itself um so if we go here that's the to-do content there and then an edit button um and that edit button will then um pass in this uh open modal function which takes in a to-do and effectively if we go back to uh this function you can see uh where is it right here open modal so we just set the model to open and then we set the active to-do to the to-do that's passed in as an argument to that function um and so that will then be accessed in the to-do um in the to-do form that you see right here um so when you also exit out of the model that's no longer inactive to-do and so when you were to uh click the button again the model and therefore the form is empty and so it knows to create a to-do and this is a lot for some nice reable code um so you don't have a ton of different forms so that's that was quite a lot let's jump into the use optimistic to-dos um quickly because that's important here uh where are we now we're in the use optimistic to-do we have a few types in here um but this is the meat and potatoes here the use optimistic function um basically what you need to know coming out of this is that you pass in if we go back here we pass in our to-dos into this use optimistic to-dos function um and then out of that we effectively you can dive into this code on your own time uh but this is a lot like um what is it called like classic State Management where we'll we'll run a switch on on the actual action type um and then we will update the state optimistically based on which action is being done so as you can see um like I was saying before the optimistic to- do is uh the data that we take in I.E the optimistic data and then we update the ID to being um optimistic um and that will return that function for adding an optimistic to-do as well as the optimistic to-dos themselves so final Point Let's jump into the to-do form which is where a lot of um a lot of the work is is happening so in this uh component we pass in the active to-do um if there is an active to-do again this is um this active to-do can be null so uh this this may or may not exist and you'll see how that changes the 2u form um we have the add optimistic function uh the nice thing with this implementation as well with reusing just one form meant that there was no need for prop drilling um for that optimistic uh function and there was no need for context as well which was really really nice um so if we jump into this to-do for let's take a closer look so we've got um a lot of imports at the top as you can see we take in a to-do which is optional um could also uh be null uh opening and closing the modal functions um and the reason why all of this stuff is optional is because this component is meant to be reusable meaning that if you wanted to add this form anywhere else in your application it would work immediately without having to without having to have it in a certain context um it just might not necessarily if you're if you don't want to use the optimistic stuff or you want it in its own route you could do that so let's start with um errors this was a cool thing that I pulled together which is uh just a reusable hook again I wouldn't really dive into all of this because it it works um and it's a lot of typescript magic um but effectively you pass in your um to-do Zod schema as well as the to-do type um and then out it passes you uh errors um has errors which is just a nice quality of or DX effectively value for um using on the UI setting the errors as well as a handle change and we'll see how that's used in a second um we then we use shaten and and their toast uh for updates if you see that anytime we we change something you can see we get toasts that pop up there and it's also uh to do updated um if we were to create something created it's to do created um we can also see actually really quickly if we um she will do that later um we then have is deleting um just some State here to uh to handle UI changes um and then uh use transition hook for UI changes as well um we also have the uh router here um and I believe that's for a router. refr refesh um if we if we look at it uh yes it's for router. refresh in the on success function this most likely will no longer be necessary next has had some um some issues with caching in the last few months um and I know that they're working on that and it should be sorted soon so this probably won't be necessary um if we jump into this on success function this is a function that runs right after um an action has been successful and so you'll see it effectively um it takes in the action which was in that UIL function it's either create update or delete and then some data um the data being either uh the to-do values well actually we'll go into this in a sec but um if data is passed in it means that there was um an error um and so you'll see an error string as well as the values and that's what allows for if something doesn't go through and we can actually simulate that right now if we go to the to-do action and we go create and we throw an error here and we try and create something try and create maybe it has to be [Music] outside I have to remember why this wasn't working oh well that's a bug that I will have to look into um that was working a few days ago um but I will take a look so if we go back basically when when that was working if you threw an error in uh in the action it would uh also hand that that error back in into the um into the toast as well um and I think there's probably something I've done wrong here um and I will update that in the future so we then have a handle submit function um that's being run when um run when we submit here um as you can see there so if we were to um if we were to see we have errors set as um null and actually to see these errors a little bit better let's jump into the to-dos schema quickly um and one of the really nice things is because we're just extending the the schema everything is here so if we were to say um this is that this is the schema that the Zod schema that's been being used in that front end as you can see if we were to in that validated form you can see it's being passed in right there um if we then pass in add a comma and this is going to be content and we say that this has to be a z. string. Min let's say five um and we save this here and we jump back here if we start creating you can see automatically we've got client side Valu validation already done we can even pass in a message if we want here um oops message and we say kiras wants more letters five and we go back look at that um so this is one of like this is one of my favorite features I I I love how quick and easy this is and and keep in mind there's no form Library being used here this is all just plain react um and you get that amazing um validation just right right in line um without really having to do anything else so sorry let's go back uh where was I yeah so when you handle submit again this is this is blanked out so we actually can't uh with the client validation we can't submit it but what would happen here is that we would initially set errors as false um we then pull in the um maybe actually if we go to the markup first so we can see how it's being used uh so it's a simple form here we've got an action which is that handle submit action um and then onchange is that handle change function that we got out of the use validated form so that's not relevant here so if we jump back to that handle submit action you'll see that we get in form data um which we have no idea actually what's there so we run a quick object from entries to get the payload in an object format and then we run that through through our um our Zod schema our frontend insert Zod schema that we have here insert to do prams if it is not successful then we set the errors to uh the uh effectively we can pull in the error object from Zod and pull out the field errors and that's what we're getting uh when we get this here um and then uh we close the modal and or if if Clos modal exists I.E if it's passed into the component then we would close it there um and then we will uh pull out the values from the uh successful parsing um of the Zod schema and then we in a tri catch we have uh we start a mutation in there again if ad optimistic exists um and this is is that nice if if you don't pass in ad optimistic none of this um code is going to run uh but if it does exist then we pass in the um the values we pass in just a blank user ID because it's not relevant here and then if we are editing um the IE if if we're trying to update the to-do here we'll pass in the to-do ID otherwise we passing nothing um and then the action again if we're editing it's updating otherwise it's create um this is also all type Save which is really cool um if there is um well so we then run the appropriate action so if we're editing then we'll run the update to do action um otherwise if we are creating then we just pass in those values which are just the content incompleted um this will return an error or nothing um so if an error exists then uh it will pass in the error um otherwise it won't do anything um and then uh we run that on success function so if there is as you can see if there is an error it will pass in that formatted error otherwise it won't pass anything in and then finally just a catch um and this will set the errors uh on the form okay so that was a lot um and then this is just plain markup um for each um for each schema field you'll see that there is content um so that was one of our Fields um there's a label and uh an input and then you'll see if there's any errors that's an error object that's being return from the um from the use validated form if there are any errors uh then update the styles of ordinating so that's that ring that's around the side um and this was done to follow uh the way that react hook form uh handles errors but you can do this as as you like it's all available to you there um so yeah that's really the markup and then finally the delete button um which this shows up the delete button exists if you are editing I if uh if I think in this case I've done it if there's a to-do ID then you're editing otherwise there wouldn't be um so if we go back down there um I think we're right here yeah if we're editing then show the delete button you'll see that it doesn't exist when we're here but when we are in the edit it exists there um simple button again it's disabled if either we are in the process of deleting if we are pending or if any errors exist and so that is deleting is that um uh you state which you'll see uh just below here eight lines below um the pending is the uh used transition um hook basically the the attribute that's passed back from that hook and then has errors is passed back from us from the use validated form hook um very simple button here onclick set deleting is deleting to true if close model exist close the model um this similar to the handle submit above is just based trying to make things feel super Snappy so uh you can see that if we were to um head to the network tab uh disable cache and go and slow 3G and if we try and delete you'll see the the modal closes immediately before the action has completed and then once the action has completed um you'll see that the the um uh then it gets deleted um and so this just makes for a really Snappy experience something that feels more native like and you don't have to wait for things this caching is just happening on the the dev server um don't worry about that cool um so again this is like all the other things uh if ad optimistic exists run ad optimistic uh run the server action uh return the error um update it to not deleting anymore uh if there's an error format it um and then pass it to the own success function all right very last thing is the save button um and this is what allows us to get this um animation that's right there and changes to to saving it's really fast but um it it I think it really improves the experience this is using a simple use form status hook um it's in a separate component and it allows um it Taps into the form status and uh so if it's pending and we're editing uh set is creating otherwise set is updating and that will just change what this button says saving or you see we can't can't do this but you'll see this will change the creating nice so that is everything this was a lot longer than I had expected it to be um but I think that kind of proves that there's a lot going on here um so very last thing I want to do is I just want to show you how cool um all of this code was created for us in literally seconds um and it means that we don't have to focus on any of that that we can be happy with and get right to building features so if I for example want to have just a button rather than having edit here I'd like to just have a button to either um toggle the Todo is completed um and that's it like that usually if I was building a brand new application I would think okay I need to uh write the service functions I need to create a button I need to blah blah blah for me all I have to do here is know that I've already got the update service function so really all I need to do is and I I've got the action the update action already done I just need to jump into the list component and add button and when that button is clicked update the the button and and that's and that's it so if we go into the uh into the to-do itself let's go into the item let's uh in here let's add a new button and let's say uh com Mark complete and maybe in here we're going to just pull in the to-do do completed status so now we can see that um if to do completed then we want to say uh completed otherwise not completed Okay cool so that's not completed you'll see if we were to update this this would say completed cool uh let's just improve this button cuz it annoys me like this we again we're thinking on a UI level we're not necessarily thinking about all the boiler plate underneath it so let's say I want an outline here that looks good to me I think I want to actually remove the edit Button as well oops uh so that we don't have that in the way and then let's just make this um Flex Flex call um sorry no just regular flex and justify between nice okay so in theory when we click that we want to let actually rather than Mark complete let's say toggle toggle complete uh last thing that I want to do here I want to say that if um to-do do completed I want to say BG uh red BG green 300 let's say and then otherwise nothing uh nice so that looks really bad but it gives you it gives you an idea of uh what we're trying to do here let actually last thing let's add some padding of let's say four rounded uh medium and then then uh item Center just so everything is centered cool so that's a little bit better um maybe very last say outline primary foreground yeah okay fine that looks okay to me so when we click toggle complete we want that to change so all we really want to go in here is add an on click and in here we're going to say um update to-do action pass in the to-do um we want to give oops we want to spread the to-do in there and all we want to do is change completed to too to the opposite of to-do do completed this is also async so we're going to want to add um a sync in there uh let's just for a good measure wrap that in curly braces and now let's see if it works so it does work um but you'll see what happened here is that we didn't update the optimistic to-dos so all we're going to do in here I think we're going to have to pull in the optimistic to-dos in here um sorry the add optimistic add optimistic if I can spell Mystic to do in here I don't remember T add optimistic you see that type is already done for you which is amazing add optimistic to-dos uh we jump back down to the button head back down here uh and then let's say uh add optimistic to-dos see what we need to give it data is um this dot dot dot to do and then completed is uh not to do. completed and then we add in the action which is update all with type safety and now you'll see we've probably got one error because we haven't passed it to the to-do component and all we do here is now add that add optimistic to-do is ADD optimistic too and now with any luck look at that I mean to me this is just it's crazy how fast that is um yeah that's I mean it looks terrible it it's not great we'd probably want this to be ordered by the time it's created at things like that but it shows you we didn't have to think about boiler plate we didn't have to think about how does any of this work really under the hood we just think all right I I want to toggle my to-do and I'll make a button and the rest of it's done so yeah that this was a lot longer than I had expected but I hope this helps understand kiras and everything that it's doing under the hood I think it's insanely powerful um and I'm really enjoying building with it uh if you've got any questions jump into our Discord open an issue on GitHub um and yeah reach out to me on Twitter we love to talk to you about this kind of stuff and as you can see it's it's it's a service with a lot of rough it's very new and it's really me working on it um so uh please be patient with some of these bugs and errors um particularly as we're gluing together a lot of different pieces of infrastructure but um yeah I think you'll really enjoy
Info
Channel: Nico Albanese
Views: 2,448
Rating: undefined out of 5
Keywords:
Id: oVKEHJPcIRw
Channel Id: undefined
Length: 45min 14sec (2714 seconds)
Published: Thu Jan 11 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.