Introduction to SvelteKit | FREE 5 HOUR SVELTE WORKSHOP 2023 | Lessons + Coding Exercises

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome to delightful web development with spel kit where we are going to learn how to build applications using spelt kit and spelt which is delightful to use uh this is an interactive Workshop so I encourage you to follow along do the exercises all the code is up at github.com thissel kit-shop um I'll even show you that it's up here like this uh all the modules are sort of broken out into branches there's Solutions on there in case you want to learn at your own pace and I encourage you to definitely try the exercises As you move through this uh who am I I am Adam Elber I am a senior developer here at this. laabs and I am a spelt Enthusiast so I really love using spelt so what are we doing today uh We've sort of got these six modules uh they're not equal in time but they're probably of equal in importance uh as we move through them each module will have a lecture section where I'll be like talking about the features uh live coding for you and then an exercise section where I will give give you a problem you will attempt to solve that problem and using your own time then after that you'll come back and I will show one of many possible solutions to the problem uh just in case you get stuck or just to show an example but I do encourage you to try the exercises it's a good way to learn so let's get started with module one spelt and spel kit so what is spelt and what is spel kit and what's the difference so spelt is a component framework for building you know web compon or we components for building web applications or websites and spelt kit is a meta framework built on top of spelt so it's there to help make building applications and websites Easier by adding some new features that maybe aren't complete with just spelt alone it's similar to if you're familiar with react and nextjs spelt is to spelt kit as react is to nextjs yes it's a meta framework sometimes called a render framework um due to the SSR thing um so why spell kit what does it bring to the table if I if I'm already developing this well well it adds some features uh for example SSR server side rendering uh all the benefits come with that so that's why they call it a render framework sometimes um it also has routing and that's actually a major part of this whole Workshop is the deep and Rich file based routing system that spel kit brings you included in that routing system is a way to handle forms and data mutations and uh that we'll get into as we get into that and of course it also offers deployments so spelit makes deployments easier with something called adapters and they are basically little special plugins that turn your Dev source code into code that is specifically tailored to the deployment environment that you want to deploy to we'll get into that later and although it may be hard to understand before you actually see how this all works the combination of these features SSR routing and deployment allow for a staggering amount of flexibility in what you build you could build a fully serice side rendered site or an SBA or even a fully static MPA multipage app or something in between and you don't need to compromise on one because you can set this per page so you could have a pre-rendered static site for all your marketing pages but your application guts are all rendered on demand server side per request or inversely you could do something like if you had a very popular blog you could have all the latest blog posts statically rendered so you get all the speed and stability that with uh static pages but then maybe your longtail your old blog post that maybe nobody visits much you could server render those on demand when needed with that kind of control combined with the flexibility of deployment if you want to develop with spelt which you should cuz spelt is amazing spel kit is really the best op option for building apps no matter what you're doing and that's not all um if you use the felt CLI to generate your application uh it includes a lot of stuff for you it includes uh typescript es lint prer uh playright for NN testing vest all sort of configured for you and set up for you just by using the generator and it's got some options and we'll go through that so there are some Concepts in spelt that you will need to understand as we get into learning about spel kit so if you haven't checked out spelt please I encourage you go to learn. spelt dodev uh go through the tutorial spelt is amazing um but I am going to do a little quick recap of some of the important features uh of spelt just so we we're on the same page as we're moving forward so with that one of the tenants of spelt and spel kit is that they don't even have to learn a lot of spelt specific Concepts or syntax so most of the time they try and stick with the languages of the web you know HTML JavaScript CSS and apis that you would be familiar with as a web developer so each spelt component is a do spelt file that's the extension do spelt and that just sort of tells well actually uh spelt kit is on top of v and it tells V that if I see a DOT spelt extension this is a spelt component I need to run that through the spelt compiler to get out something that can actually run in the web you know JavaScript CSS and so this dot spel dot spelt files are how we Define spelt components um you can sort of see here they're very HTML first uh kind of like vue.js they're they're uh single file components at least uh you've got your scripts you've got your templating um this kind of templating with the little curly brackets uh scripts for like State and behavior and styles you can actually add Styles just by adding a style tag to a spell component and these styles are actually scoped too so they're only going to affect other the elements that are defined in this component and we can sort of show that uh later but for now let's just add uh some button styles to demonstrate that um so in here we could do you know the font family what's the funnest font comic Sands maybe I'm probably losing people by using Comics s um you know and we could do font size 2em and maybe color a little splash of color Rebecca purple my favorite one um so yeah you can add Styles just by adding a style tag and you add behaviors just by adding some JavaScript in a script tag um and sort of the convention is script to top style at the bottom and the templates in between uh with these sort of templating things which we'll get into a little bit um and you should definitely check out but the adding behaviors is really easy here you know this doesn't do anything right now but if we wanted it to we could uh we could Define a handle click function here uh and you can write whatever JavaScript you want in here and this handle click is sort of a quick introduction to the spelt reactivity system so reassigning a variable in spelt is enough to tell spelt that hey this needs to rerender something has changed in this component so go through the process of rendering so all I have to do is say count equals you know count plus one in this case just to increment it whoops and now I add this as a listener as a as an event handler sorry so on on colon is how you do uh adding event handlers onclick and then you sort of give it the function now we would get an event uh as a argument here but I'm just not using it so throwing that away and here we go count equals count plus one click and there you go you can sort of see that is sort of the base reactivity system of spell just by re assigning the variable and you can even do you know you can do assignment like that even this will work as well or you know plus equals 1 you know all these kind of things it doesn't matter how you assign it but reassigning a variable is basically going to trigger spell to render and kind of go through its whole process so that's the basics of spelt templates um there are some uh what would you call that logical flow flow logic um so in this case let's let's just go through the if else block so you can sort of find in these little curries these are sort of the directives these blocks um so in this case else or sorry if uh let's do X is greater than 10 then we want to and we can throw some HTML in here so let's do a paragraph oops got some formatting Auto formatting happening there um and in this case I would just say uh count is greater than let's just do X is greater than 10 sure and the way we close the if blocks is with this little slash uh and then if and that's kind of like the spell convention you can sort of see all these sort of block based templating things opening with a hash or a number sign whatever you call that and closing it with a slash um and so this is how this works you can see it's not greater than 10 so it's not rendering anything oh it is there we go and you can even do an else in here too now an else so in the middle of these things else doesn't really close it um you use a colon so it's open open hash colon in the middle and close it off with a slash uh and so in this case we can do an else and we could just put you know it's not or whatever and now we can sort of say oh hey if it's below if x is below 10 it's not um whoops and we can do else if too uh just by adding if here we can say if x is greater than or sorry let's do less than five less than five we could say x is less than five and you can even add another else in here because we need you know uh some sort of default Behavior we could say else and then we could just say you know in this case X's between five and 10 this is kind of a funny example but you sort of get what I'm picking up doing here uh unexpected token on line seven whoops if x is less than five so if x is greater than 10 we've got you know 15 x is greater than 10 if it's less than five you know if we go down to three here it says X is less than five and of course if it's in between 'll say x is so that's kind of how if else flow logic Works in these felt component components importing modules so importing modules uh importing other Spell components at least is just like importing modules in JavaScript and so the way you would do that is we have two components here we've got the nested component and the app. spelt uh and app doel is just that's nothing whatever component you can name it whatever you like as long as it ends in doel um and the way you do that is just using JavaScript so it's the default export of the felt component so in this case I'll say nested from and then the path here is slash nested um and you want to do do spelt because again you need to able to tell V hey this is a spell component so transform it into something that'll work in the web and now with this nested here we can just use it like uh if you're familiar with react kind of like react we just use it here uh as an element in itself and it doesn't necessarily draw an element when it's fully rendered but uh if we just add this there we go I am the child component and this could be a you know a self- closing tag too and one thing I wanted to show here is so the nested is a a p tag it's a paragraph tag but we can add our own paragraph tag here and it'll say you know the Styles and I'll add a style tag let's do the old same ones I did before we'll just do it on a P tag here so P tag we'll do the font family comic Sands oops comic sanss uh cursive and we'll do the font size big and color of course Rebeca purple and you'll note even though there are P tags styled here they're not styled here and this is what I'm talking about with the scoping you can sort of see how this works by seeing if we open up the inspector here spelt has added to this P tile so where the styles are sort of uh defined this ptag gets a little special class and the other one doesn't have it because it's in this file and so that's how we scope our styles to the components without worrying about all the problems with the Cascade and how it's going to break so Props so one of the things you can do with props sorry one of the things is you can pass props to spelt components now the way we would pass props is we have to sort of Define that this component takes prop so I'm going to go into the nested component here and I'm going to say you know let's say let answer equal what's it good at 42 the answer to you know life and everything and we'll say the answer is and then we'll just interpolate here you can put whatever JavaScript you want in here but we'll just put the variable here to be interpolated the answer so the answer is 42 so this is not a prop this is just a variable inside of this component but I can turn this into a prop by exporting this variable so you can do export and now it's exporting the variable answer and it's let so it can be changed so this is a prop now um we can sort of take this away you can see oh it's undefined and I could Define this out here so the answer is equal to 42 I can pass it as a string here oops did I answer o just spelled answer wrong all right the answer is 42 so that's how you can pass props and you could have default props so if I wanted to make this you know 42 is the default prop and I wanted to say oh let's let's pass this nothing well this will work oh it's still 42 even though we passed nothing and I could make you know this a variable too I could say let my answer equal something else and now I can pass the answer here right I could say answer equals and I can just use the variable you know this is the interpolation for attributes as well and I can say my answer and now because it is passed it doesn't use the default value this is something else so that's how props props are basically exported variables in uh Spell components uh reactivity so we already started talked about the basic reactivity anytime you reassign a variable inside to find inside the component here it's going to render it's going to like oh figure out what it needs to change and then change it um there are a couple other options too so spelt has this cool little syntax it's this dollar sign colon and you're like dollar sign colon that's weird and it is it's particular to spelt but it's actually valid JavaScript um this comes from something called labels labels are used for escaping out of Loops uh you can sort of look into it labels are generally you know you name it and then you use it to break out of Loops in this case spelt has sort of co-opted the one label dollar sign so dollar sign colon spelt said we're going to take that you can you can have all your other labels still but we're going to take that nobody really uses labels anyway as far as I know so it's kind of an obscure feature of JavaScript that they've sort of co-opted Now by saying dollar Cent colon here I'm saying this part is reactive so I can define a variable here I could say doubled and I can say doubled is always going to be count time two so in this case now if count changes s immediately knows oh doubled has to be recalculated and recalculates doubled and then we can sort of display this you know the way they do P tag and I could say doubled uh you know I could say count whatever it is currently times 2 equals and then whatever doubled is so in this case you know 2 4 68 immediately doubled is updated and you can even you know know the the dependencies can be based on other uh derived values so we could say quadrupled could be uh doubled times two and now we just need the same kind of like P tag down here we'll just say quadrupled quadrupled and we'll say doubled times two equals quadrupled oops got quadrupled wrong quadrupled I'm missing an A and now you can see this is working and so this is basically quadrupled is depending on doubled which is depending on count and whenever count changes these will update as well and that's sort of how spelt does its reactivity there's another thing that spel can do with reactivity which is using blocks so you can sort of Define reactive blocks so this whole block will re run whenever one of its like dependencies inside here something it's using it sort of keeps track of what values it's using whenever one of those changes uh when props change that might trigger you know these changes depending on if they're used as de uh as uh dependencies and there's a whole other thing called stores which we'll get into a bit but that's sort of the basics of spelts reactivity slot so this is an important concept for understanding uh spel kit uh slots so slots are basically like uh the same as they are in HTML so in HTML you can have slots uh they're mostly used for web components uh and basically allow you to put child components somewhere else or put it in things and I'll sort of show how that is so we've got this box component and the Box component is just a style div uh you know it's got a little Shadow and stuff little border and we're importing box so now if I were to wrap this little H2 in this box we get nothing because box doesn't do anything with this children it's like oh hey I am just going to completely replace that but by using a slot we can say hey take whatever the children are of this of of of you know children defined in this template and sort of project it where we want it in this template so now I can say when I use box sort of wraps this hello up and you get this border and everything and you can do of course more in here too it's not just like one element uh whatever I want and you can even do default content so if you were to say use this slot and give this slot children this will sort of be what is used if there is no content provided so uh no content provided will be my default and so if I come in here and I add another box but I don't give it any oops capital B box because you get a match the component it'll say no content provider which is the default and as soon as I add some content here it uses my content instead and you can even do this with you know a self-closing tag no content provided and then another aspect of slots is you can use name slots which is sort of like oh hey we can we can specifically design spots in our component where if you want to put stuff in those spots uh you can use name slots and let's just show you how so if we were to add let's add a footer here and the footer Styles will just be like background color light gray and you know some padding uh oh yeah and it's so you can see here saying oh you haven't used a footer right so I need to add the footer so I'm going to add a footer to these boxes it's just an element just a footer and I'm just styling that footer here but in this footer you know if I were to put some content here let's just put I am a footer you can see how it's going to render I'm going to use a slot but I'm going to give it a name attribute and in here I'm just going to name it footer and now you can see oh hey the footer isn't rendering but if I were to say oh hey let's add you know well let's add a div here and I'll put this whatever I want inside there and I will say this div this element you know whatever element it is it doesn't matter um if I say it's using the slot so slot attribute and then I match the names up oh hey this is how you projected inside there so you can see here that it's taking anything that isn't and it's kind of leaving it out where the non-n names slot is but projecting the slot footer into exactly where we want it which is in this footer slot so that's how you can do sort of better templating uh using named slots and sort of have more control over what your children are doing you could even add another you know span here um and you can sort of see like oh hey it's because the main slot is up here and it's not within this footer all the content that isn't in this named bit is going to just be added where the default slot is so that's slots and that's that'll be important as we talk about layouts which we'll get into later and then one more important aspect of spelt uh that you'll need to understand for spel Kit is stores so spelt has this concept of reactivity um sort of built in and it's got this very small um Library uh called spelt stores and sort of included in felt you can see how they work right here so if we were to make a you can sort of see this component how it's working right now is we you know as I hit refresh here um it sort of this is the current time and it's sort of updating but it doesn't change after I hate refresh I need to fully refresh to have this happen again it's just using date now and the form matter here um but if I were to make a store so I'm going to call this store.js doesn't matter what you name it you can name this whatever you want whatever file you want I'm just doing this I'm going to export well actually first I'm going to import uh a readable store from spelt stores spelt stores or SP store sorry and I'm going to export a Time store that's what we'll call this and so you create a Time store here by calling readable and you pass it a function actually first you pass it a default value so you can think of a store as like a value that's going to change over time and so it's going to have a default value initially and then if anything changes it's just going to sort of notify spelt and be like oh hey something has changed and I'll show you how that works so in this case we're just going to start with the default uh date because this is going to be you know what's the current time and then we get this function we pass this function and this is sort of like oh what are you going to do in this store and you get a set you also get an update too but for now we're just going to use set a set function and this is for setting the store so in my case I'm going to do uh an interval here interval and it's basically set interval and so interval kind of set interval works like this you basically give it a function and a time and so we're going to call this every one second and what it's going to do is I'm going to call the set function passed by the store so this is setting a new value for the store and I'm just going to set it to the you know whatever the current new date is again just make a brand new date so now what we've got here is a store where every one second the date is going to change to whatever the current time is now important in stores is you need to return a value to sort of clean up what you've done so we've started this interval here so as good you know spel Citizens We're going to return a function that will clear that interval clear interval and clear interval and set interval are just uh part of the browser apis um and this takes the interval to cancel it so now uh when something subscribes to this store and I'll show you how to do that um it'll start this process off and then uh it'll change and then if we were to unsubscribe from the store it'll clear that interval and this updating will stop happening so how do you use it so we're going to import from here import our time from store JS I guess we just do store oh got a little got a little something what do we got here set interval that looks all right little errors here but hey that's what makes it special right rle ends here um it says import is not defined but that's not correct from spel store oh you know what we didn't do export time here I got to make this a variable so this can be a con or it can be a let um I always do conss for some reason when I am always when I'm doing uh exports but yeah so you would export the variable not the actual value I mean you could do a default expert but this is how JavaScript works that's just me making a little mistake there and so now so we've got this time store so one thing we can do here is we could say you know let current time equal and we'll just start it off with the new date and then we could say time subscribe and then you pass the Subscribe a function that's going to get whatever you know as it changes it's going to get the new value and then you can do something with the new value so in this case we could just say current time is equal to uh whatever value this changes so this is the value of the store current value and now if we use current time here we can sort of see what's going to happen now we've got time updating we've got oh hey look at the seconds going because every second that store is having a new value that new value is triggering here but this isn't the best part so now spelt this is how stores work but spelt has a syntax for just using this directly using the store directly and all that syntax is is if we were to do this instead we could say current time um is the time and then we add a dollar sign here now you can see it's doing the same thing so spelt is handling the subscribing and the under unsubscribing of the store um Right Here Right In the template uh just by adding that dollar sign that's sort of the convention that it's like oh hey I know this is a store it follows the store contract I can just add a dollar sign and start using it directly um and it doesn't have to be here either you could also uh you know I could take the dollar sign off here and put it here instead in the JavaScript and this is doing the same thing it's essentially saying uh when this changes this is now just a reactive variable and it's assigning to current time and current time is updating um right there H hold on and it's not excuse me what's going on here uh so in this case I'm is immediately getting this time but current time is only set once because I'm using let here but if I were to change this into a reactive variable uh now it knows Hey whenever time changes I need to change current time and now you can see it's updating and we could take this a step further so all this formatting here we can actually put you know as part of this reactive statement so we can get time out of here call the form matter right in there and then just make this current time and now this will be updating as well and this is nice because this allows you to sort of move a lot of that uh formatting or a lot of you know code out of your template so your template is clean and easier to read and sort of into your JavaScript um whether that's in a file or whether that's out here so that is stores and there will be stores in spel kit um for you to use so now that was sort of our rundown of the concepts you'll need from spel to understand spel kit so I think you're ready for your first exercise so now we've hit the exercise portion of our module so after each of these modules after the lecture part where I talk and Live code then we're going to ask you to do something based on the skills that we've already learned and and then after that I'll move through one of the many possible solutions just to show you how I would do it in this particular case our first exercise is to set up a spelt kit Dev environment and once we have that set up we can use that for all the exercises going forward or of course you can check out the repo you can switch to branches and just use a basic setup if you get stuck or you just need you know a better setup uh so for now we're just going to use the npm create spelt command to kind of scaffold out a little spelt Kit app for us and let's get started start so I am going to open up vs code here and I'm just going to open up the terminal and the command is mpm create spelt and then I like to add the latest tag here at latest just to make sure that npm is grabbing the the latest version of everything and then you can add you know my directory it's just basically a directory name sorry my application whatever you want to call it um or you can leave this blank and you it'll ask you do you want to use the current directory or you can type it in after this I'm am going to use the current directory and then you get this choice of uh which template you want to use the spel kit demo app the uh skeleton project which is basically just it's all set up for you but there's nothing in it and then there's the library project which if you were like developing a spelt UI Library you might want to use this this is a nice setup for you for easy creation and deployment of that kind of thing um but we are going to use the demo app because it's got some cool demos that we can check out uh then it's going to ask you if you want to use typescript not yes for this Workshop we will be using typescript so might as well go ahead and select yes typescript syntax and then it's got these options so I was I was talking about before uh es lint prettier playright v test um we're not going to do any testing in this Workshop so I'm just going to go ahead and hit space for ES lint down and hit space for prettier and we'll just get those installed and set up for us as well hitting enter there it is it's all scaffolded out for us it's got some commands to run here mpm install uh so we run npm install oops that'll install the uh dependencies that we need and then it's got this second command here which we can just copy and paste what this is basically doing is it's going to set up a git project and then add all the files to one commit and it's just going to call that commit initial commit and then lastly we just run npm Dev sorry npm runev which is the npm package Json script and to just add one more argument to that you do add dash dash that'll add you know extra arguments and then you can say open which should open browser for you so there we go it has opened a browser um you can't actually see it but let me bring it in here there we go and this is our demo app so yeah it's basically three pages it's got a home here which has a really nice you know classic counter uh example example and then it's got this about page the about page is neat uh if you sort of build this like actually do a npm run build and see the final production version of this this won't load any JavaScript because it doesn't need any there's nothing interactive on this page it's just static um in Dev mode it will have JavaScript running but that's a whole different thing and then it's got a sperle example this is basically implementation of the Wordle game um but in spelt here and you can sort of see uh you know played along check out the demo to see how this is made it's actually very cool uh neat little demo um so let's just make this smaller you can check out the demo on your own what we really want to check out here is the directory structure so let's just open this up so you can see what what got scaffolded out for us first a bunch of uh config files we've got like a V config TS config felt config there's a readme package Json a prettier setup es lint setup and uh all that for us kind of done for us so check that out then we've got uh this static directory so the static directory is basically you know this is going to be a served node app in Dev and it'll export to different things based on where you're deploying but static is for those files that you basically want to serve but as is no no doing any processing no touching this is where you might put you know your robots text which I think is included there by yeah robots text favicon uh any PDFs basically any files that you just want to exist and be served but with no processing whatsoever as is and then our source file this is where we will be programming this is our application code um and so the demo app sort of generates for us uh this is app HTML which we can actually check out uh some uh types just for our typescript and then our routes directory which is where we'll spend most of our time this is about that file based routing that I was talking about uh we'll check out how this is done in the future and then there's this lib folder and this lib folder is basically you know spell kits trying to be a little opinionated on like oh if you want reusable pieces of code but you want to import them easier this lib folder sort of allows you to import these libraries using a dollar lib uh shortcut which we can uh check out later on so for now let's look at this uh app. HTML so this I never changed this just sort of exists by itself but you can sort of see here it's got the dock type it's got all the HTML set up it's got these tags or tokens whatever you want to call them this is where the uh spel kit assets library is going to live uh and then anything that you put in the head using the spelt head component uh is going to go here this little guy data spel kit preload data hover this is a performance Improvement where it's going to preload Pages just by hovering over links to those pages so in your app if you have links to you know very around it's going to as soon as they hover it's going to like pull over as soon as they touch on a on a mobile now now this is super useful and great little polish um it's really nice to see this kind of like dedication to Performance but just for our purposes of learning it can be a little confusing when you're looking at the network tab sometimes to see like oh why is it fetching so much we're just going to delete that and hit save and then this is where our spel kit body will go to this is basically we're going to have spelt components defined in those route folders and they're going to all end up in here so yeah I take that away on the body but other than that I never really touched that file so this is our uh spel kit Dev environment we can use this going forward and uh check it out and we'll be see you in the next module so with our Dev environment all set up now it's time to learn about routing so one of the major offerings of spelit is its directory driven file system based router um it handles a lot of different things including layouts nested layouts uh loading data uh SSR that kind of thing uh it's a really powerful and deep routing engine um directory driven file system based routing what does that mean exactly well it's similar to file based routing but the directory structure is what determines the path and these special files these special plus sign files signs that are prefixed by a plus sign sort of determine what is served at those routes so what are these special route files uh there is a plus page plus layout plus error and plus server files and there's different variations in within those two we are going to get into each of them but for now we're just going to take a look at plus page so we're going to start with some live coding uh see this in action with just a very simple route so when you generate an app with spell kit uh it's you know we use the demo app we're going to get a lot of the routing stuff now I think we're just going to delete everything here but first let's take the Styles out of routes and just put it in the source just move it out there because we're going to come back to those Styles later that is going to cause an error but that's okay we're deleting a bunch of stuff right now anyway so let's delete everything in routes and we'll just start a new with our own and we might as well just delete everything in lib as well let's just delete the whole lib folder now inside our routes let's make a plus sign page. spelt file and this will be our root spelt component um and so in this file oops let's just put an H1 for now and it'll just say uh welcome spelt kit students and I'm going to hit refresh in there and there we've got our first route route now it's just a a spelt component uh it's pretty cool so we can do things like uh you know make this use this like a scrub spell component so let's do script Lang equals TS so that's how we can get types script in Spell components um and we're just going to Define a variable let's just call it subject and our subject is you know who we're saying welcome to so in this case let's just say the Learners and then we can change students here to just be interpolated and we'll just do the subject here and then add a little exclamation point and there we've got welcome spelt kit Learners and uh you know just to continue on we'll add some a style tag in here and we'll just add some style so we'll do like H1 and we'll do the color uh Rebecca purple because you know it's my favorite and you know one thing we can do here is you notice the title in the in the browser here say says Local Host 51 some3 well we can we can get rid of that now this isn't anything special this is just a spelt thing but spelt has a component called spelt head which lets you add things to the the HTML head and so in this case we'll just put a title element in there and we will call this uh you know uh home I guess because this will be sort of our route so now you can see here that immediately updated and we've got home in our title so so far this is just a regular spell component we haven't done anything so putting spel components in these directories is really what's causing it to serve those spel components as your pages um so now if we add another directory here so in our routes we're going to create a new folder and we're going to make an about page so we're going to make an about directory so that's the route that's the path uh you know slab and then in there we will make another Page Plus page. spelt component it's the plus sign that lets it know this is special like this isn't you know not just any spell component this is specifically for the router here um and so in here we will just add another H1 I guess and we will say the about uh and we'll add oh let's just copy from the other one here we take the head and we'll say about and I guess we're going to need to navigate around here so why don't we add a h sorry an anchor tag with a rough this is just a regular anchor tag it's just uh you know this will go home just like co-pilot's finishing off for me here and on our homepage we might as well also put uh a link to the about page so again our Ru and our about page so here we have it we can click on the about page you can see in the in the URL bar there well we go to slash about we can go back home if we're on about and I hit refresh it loads because this isn't an Spa again this is this is a full-on server side rendered in in Dev at least and then depending on where you deploy whether this would be static or server side rendered is decided at the time but currently working um that is how easy simple routing can be just throwing spel components with the little plus page. felt so you can see the back button works as well you know because it's just sort of using regular uh navigation but now uh let's do something a little more interesting I guess uh let's load some data from an API so have you ever seen Bob's Burgers is this cartoon it's funny doesn't matter if you have or not we're going to we're going to use an API that I already have set up at spelt thatf fun uh to get bobsburger character so in our home component here let's make another route and let's call it characters characters and just name it here characters and now we need to go ahead and create another route here um one thing you can do if you have the vs code extension installed is I can sort of go oh from routes here I'll go these spell kit files and there's this create route uh you choose this and I can just say oh I want and there's a bunch of different options here but you don't know many about these but I'll select this page. spell for now and uh oops I kind of messed that up don't worry about that um I need to type in here so characters and then I'll just add another I won't use the fancy thing yet because I must have messed it up so in here in our characters we'll kind of do the same thing as the other ones we'll put a you know an H1 here with uh characters and the title let's just close on characters and we do want to link home as well and you can see that's already automatically working now um you'll note that we've got a lot of these plus page files and so that can in your editor kind of get a little wonky right if they're all named the same thing so I have the extension that lets you sort of see or I have this setting there's not an extension s it's just part of the setting that sort of lets you see this is the page. belt for characters this is the plus page that's felt in routes and yada y y um just something you probably want to turn on because because with all the files being exactly named plus page dust value can get a little obnoxious so now to load data we add a different file here so in our characters directory we're going to add a new file and we're going to call this one Plus page. Ts so it's not a spelt component this is a Javascript file a typescript file sorry from this typescript file we can export a load function uh and the way you do that is pretty much just like it sounds so we're going to export you know a const load so we just name a function load and you could write this you know with like function load but I like doing const and an arrow function and this can be an async function um which is good and what we return here is going to get get is it's going to be an object and it's going to get passed into our character's component as props so let's just continue making this load function so we're going to load some characters now um let's let's do a type let's make sure it's right so we've got a character type and oops need equal on there and it's going to have an ID which we can make number sure and it's going to have a name yes absolutely um maybe not a descript so if we check out a uh sp. fundi bobsburgers we have a API sort of set up here already if this isn't working for whatever reason and you're watching this video um there is an API Branch inside the repo which you can check out and you can serve and that is does have this API too just in case felt that fun isn't working as expected um but here we are so we can see here that uh We've get ID name image and occupation so we'll go with uh image which is a string and occupation which is a string as well so now with our characters we just need let's just return for right now uh sort of mock characters I guess uh so we need just something with an ID oops oh there we go uh C pilot is really helping me out here it's got something with an ID and an occupation already um wrong show co-pilot but still good enough for what we're about to use it for so now from our load function all we have to do and it can be an Asing function is return an object and that object can have properties and so the properties on this object I'm just going to return characters uh as they are here so we've got these characters we'll return that and now if we open up our uh our characters component which is page dovel here now we can set this up to accept a prop so we need the script tag typescript yes of course and now if you remember how we do props so it's export let and now this prop has to be named data that is the sort of the thing the way it passes from the load function to the component is by a prop called Data but you can see here if I hover over this it knows already that data is an object that has characters which has this character type so spelt kit has done some magic with some you know generating some files in the background that you don't know why while the dev is on to allow you to sort of have this type safe from the backend load or not the back end in this case but the load function all the way to the component um so yeah now that we have data here uh we can sort of make this you know work work out a little more so we know that on here there is a characters property so we could say maybe you know we could do a reactive characters equals data characters and then we can uh sort of list these out so let's make a ul and each you know we'll do in each characters as and we'll just pull this stuff right off of here rather than doing it this way we'll just do uh name and ID I guess actually we only really need name well I guess we could use ID for the what they're using it for here co-pilot to the rescue and now we get a list of characters loaded for us and then render to the screen so now let's actually let's not use this let's actually fetch these characters so in our async load function we're going to do uh you know const response and we're going to fetch await a fetch now we're not going to do Rick and Morty I don't know why co-pilot really wants to do Rick and Morty but we are actually going to do https um sp. fun and API character or sorry bobsburgers with a hyphen slash characters so let's take this API endpoint and just push it out here you a const just to make keep it nice and clean uh we'll get rid of the Rick Sanchez stuff there and now this fetch function we could use fetch here it is available but sometimes on a server fetch isn't available and spel kit provides uh a fetch of its own that has a little a few little enhancements so the load function is going to be past an event and in that event it's going to have fetch which we can then use and it's encouraged that you use this fetch uh just to make sure things are consistent on the server and it does have some benefits which we can talk about later so I'm going to use this fetch we're going to fetch from we're going to change this into uh you know a template string with the API whoops and then we're just going to add the slash characters and now that'll get us you know how fetch works it gets us a response so from the response we can await uh Json so then it's going to take that Json you can convert it into our characters which now we have to type this but I think this is just as easy as saying this is a character character and then we want to make it a list or uh an array of character characters so now this should know that's characters that knows that's characters I hit save here all the way out here this knows this is characters and bang Zoom you can already see this is working we have a response from our API um except it's rendering just the name at this point so with our type safety working now type safety working here now we can sort of create the template for this list so I am just going to copy and paste because it's a little easier than me typing this all out so I'm going to pop that in there we'll let uh prettier sorted out and we just need to pull off image and occupation here and now oh closer warmer we've got some pictures showing up uh now we just need a little bit of style a little bit of Style again I am just going to copy and paste this from my notes but if we add to the style down here let prettier sorted out well now we've got a really nice little oh sort of logging a list of characters that we have fetched from our load function which is really just a simple you know we've got a type here and a very simple fetch uh fetching these so now each of these has a if we sort of hover over it you can see it up here at the bottom it has a link to a detail and you can see in our uh API here if I were to go to slash one um we get a little more data a little more detail so this is sort of the you know the list details kind of thing um and so we are going to make a page for each of the characters which offers a little more uh data and so the way we're going to do that is we're going to use params now we're going to start here we're going to say in our characters we now have a new segment a new um segment of the route so we need again directory based routing so we need a new directory and if we put the little boxes on here and we're going to say ID now this is means it's Dynamic so this is going to oh this is a dynamic parameter of the route so whatever's in this route segment is going to come in to our load function we'll be able to use it so in here let's let's make our plus page file uh our cell component and uh we will just sort of copy from the other one I think a little bit and we'll just okay so we'll get rid of some of these Styles because they will no longer matter and we will get rid of some of this because that will not run or matter and now our data is going to probably just be the Single Character so we'll change this to character instead of characters and then we'll probably do you know the title being like character name and uh this is probably going to be like oh hey so I so kit doesn't like this yet yeah that's true we haven't actually made this working yet but we'll get there in just a sec so also in here we will need a load function so we'll do our plus page. TX again so that's how we like run some JavaScript here um and so in here we're going to do actually a very similar thing to the other so let's open that one up so we can sort of copy paste there copy this but we're not going to yeah we are going to fetch so never mind so now we just need this character type to be just a little bit different because it's got a little more so we've got ID name image we've got gender here now uh and we've got hair color hair hair color and occupation first episode voiced by and then we we've got URL and Weeki URL and relatives which I believe though we can't see on here is uh basically just an array of objects that have name I don't even think they have URL thank you copilot though and it's just an array of those so that's going to be our detailed character type we can even sort of write character detailed character type here so we'll use the same API thing we'll add this little thing to the templates room where we're going to pass ID now where are we getting ID from whoops ID well we're going to get that from the event again so the event which provides us fet fetch also provides us with pams so these pams are decided by the routing um and you can already see here co-pilot knows that we're plucking off ID from here and so this knows we've got ID as a string here we're going to throw it into here we're going to wait for the response the response is no longer a list though here it's just character and character A Single Character um oh but we called it detailed character and then that character is being passed out again to the individual so if we go to our individual uh character here now we've got character we've got name let's just make sure that's working so this should say Doty oh it does excellent excellent whoops Adam here we go we don't want to go all the way home just want to go back so maybe we'll make this instead of home we'll just say this is characters and we'll go to the characters that's a little more feels a little more right we go from Mabel back to characters Okay so we've used fretch we've used the pram idas uh we can sort of see this working now I'm going to uh again I'm going to copy and paste something that already exists in my notes but we have this uh component essentially oops and it is a character component okay so I'm going to create a component here let's just close these keep everything nice and clean so in our characters here in our uh individ idual we will create a new file called character. spelt now this doesn't have a plus sign so that sort of indicates to spelt that it is not special this has nothing to do with a routing this is just a regular old spell component I'm going to paste my spell component in here um you can sort of look at this uh it's just a bunch of styling um it takes in the same properties that we kind of already had uh it's got sort of a default image for anything if it was unknown and uh yeah now let's plug this in so from our page component we can import that character component character from you know it's just right here character. spell we can use it instead of the name here whoops character and now we basically just uh character takes all the individual props so we can basically just use the spelt spread here to spread the character props across this component so now we should have a little bit nicer there we go a little bit nicer um for the individual here we go individual detailed view now this is fine and this is great and this absolutely works but another thing whoops we might want to do is we might want to move this to that Li folder CU maybe we could reuse this around maybe this is something we just want to have uh you know as a library of its own or part of a component Library so if we add that lib directory back in um as a child of source and we maybe we'll do components you know we'll say oh there's a UI components that we're going to share across different things and in the components we will put the character component so now you can see here oh it's already sort of updated for me up up up but um you might not like that right it might not uh it might not be fun to always use this like oh up up up out of the routing thing but spelt has this sort of uh spelt kit sorry has this little shortcut this little Alias dollar lib will always go to that lib folder so I can just use dollar lib components and the characters component and now that's just a little bit easier still works everything looks nice typescript is Happy everything working great so um yeah we've got our uh list of working we've got our home back and forth here we've got our about we've loaded data from a remote API uh sp. fun Bob Spurs so now I think we can move on talk about more things that was a simple route so by default spelt will render any page components and their children first on the server and then send it to the client as HTML JavaScript and CSS then when the JavaScript loads it will render the page component again in the browser to make it interactive in a process called hydration for this reason you need to ensure that your components can run in both places on the server and the client so then spelt kit will initialize after hydration spel kit will initialize a router that takes over subsequent navigations anytime you're clicking around you it'll be acting more like an SBA at that point with JavaScript fully controlling it um this hydration sort of offers that Best Best of Both Worlds approach it's got that fast initial load of service side rendering but then the interactive client side behaviors and we and you won't lose State as it sort of navigates around often the ideal example of this is a website with like a media player you don't want to lose the media player state or have it like restart every time you like click to a new page or navigate around but you still want that like SEO and performance boost that you get from SSR so now Best of Both Worlds might be contentious as there are newer approaches you know with Island architecture partial hydration and and quicks even uh resum ability which offers some interesting ways to really lower that down now spelt still does a full page hydration uh maybe that'll change in the future that doesn't really matter but as for now that's the way spel is chosen and I honestly can say I think it's really good and and really is like The Best of Both Worlds right now but admittedly maybe there'll be changes in the future depending on how this resum ability or uh you know partial hydration sort of ideas kind of shake out so those load functions we made in those P Plus page. Ts files they are also going to need to Lo run on both the client and the server that's why you use that fetch in the load function because it's best to use the one provided by the event argument so you know it's available on the server you don't have to import like a polyfill or whatever and it's on the client but there's also some additions that we can talk about later that fetch function as well so you do want to make sure those loaders are universally in that page TS so what if we wanted navigation that is shared on all the pages so a common feature of these meta Frameworks and rendering Frameworks is layouts the ability to have these wrapping components around the pages which you can then use for you know UI components you want to appear across multiple pages so remember those special route files well this is another one of those uh instead of plus page this is plus layout so what if we want wanted for example a navigation that is shared on all the pages so by adding a plus layout. spelt component to a directory we get this like wrapping layout uh and we can and use spelt slots like a slot component or a slot element uh to control where the page content will actually end up so something like this uh with the nav sort of outside that slot and then the individual about and characters pages are going to show up where the slot is essentially so let's talk about when something goes wrong in those load functions or in rendering um there's another special file the plus error files uh so one thing we're going to need to understand for the error Pages if you may to call them or the error components is the page store and it's worth stopping and taking a second to understand what the page store is all about about so you can import page which is a store from dollar sign appstores which is a generated module that spelt kit provides to you and so spel kit is smart enough to figure out that that dollar sign app stores based on what routes you have and how it's configured what page what properties will be in that page store here's some of the properties available page though uh you'll always have the URL prams routes uh status error the data that's normally passed to the page component is available in the page store as well as well as another thing called form which we won't get into until later so let's see some of these Concepts the the layouts the the error pages in action so I'm going to back to this example and I'm going to add add a layout to the route so let's close these up so in our routes going to create a new file plus layout. spelt I'll go back to the rout here just uh so there's no problems now you can see here immediately there's nothing it's a blank page and that is because just like in the example from before if you don't have a slot it can't put the content of that slot in here and so the page content is sort of a child of the template if you would think about it like so by adding the slot slot it's all I added everything comes back uh the pages work again so what we want to do is we kind of want to take these links of about and character and we want to move them into that uh layout instead of where they are so we will add a nav element here and in our nav we'll put put these uh links and now we've got uh about and characters and you can see here as I navigate to about and the characters the page content is added but these uh these links stick around these home links are still from uh the page content but these top ones here they're just from our layout. spelt now interesting thing here that we can do is we can turn JavaScript off so if we go to the uh preferences here go all the way to disable JavaScript and hit refresh here you can see that all this still works because again we're server side rendering this you know that that load of the characters takes a little bit longer um unless it's cached there um but essentially everything is still working without JavaScript because that's uh serice side rendering essentially provided to to you one thing we might want to do is import the stylesheet so right now we've got this sort of in this page uh the stylesheet or actually Sor we didn't load it anywhere uh so we pulled the stylesheet out now I am going to make some changes to the style Fe sheet again just because I have them in the notes whoops but uh you don't really have to worry about these changes I'm just doing them to make things look a little bit nicer but in our layout since it is again just a spell component we can also add our script tags uh we can add an import and in this case we can import and we can sort of put a relative path outside of our routes even to this style.css and because this is V and V and spelt understand each other just just adding styles. CSS here is enough that it knows oh hey I know where to get that and it loads these Styles whoops oh that's that is some interesting stuff uh I think this might be worthy of hitting restart I'm just going to stop this hit restart here and see what is going on well it's pretty good but it's just got some Styles up there for some reason so we're importing if I take this away it's all still there okay so something weird um in my layout I've never actually had this happen before so not entirely sure what is happening we've got our script our language here and I didn't import this anymore and it's still there so it's definitely something let's see got our layout our app HTML looks pretty normal our root layout here it's got these Rebecca purple styles from somewhere okay I just hit refresh and they all went away so that was a bit odd but sorry about that things are a little bit odd sometimes um yeah so where was I we've got a slot uh I wanted to add back in uh the Styles and that is not what I was expecting again ah I pasted in the wrong thing right so when pasting stuff in make sure you are pasting in the right thing so I must have grabbed that from the wrong file so now let me paste in the CSS not a felt component okay sorry about that so now we have welcome spell kid Learners it's all styled uh we have nicer sort of fonts happening here um and everything still works about the same we've got the links kind of you know with the link on Hover um and everything is working now we could put these Styles in our lib folder as well um and just import from you know li. Styles um but in this particular case with the global Styles I kind of like it being out here with the HTML that's just me doesn't really matter though you can do things however you like another thing you can do because again this is uh very similar to the pages in layouts is you can load data from a layout so in our uh directory here in our root directory here let's close these off we can add a new file here and we will call this uh well actually let's not do this in the root let's do this in oh yeah let's do this in the root yeah um we will do a Plus layout. Ts file and in our characters here open up our page file this is where our fetch for all the characters is we're just going to copy and paste that into our layout file so now when the root is loaded up at all it's going to fetch those characters and might not be exactly what you want maybe we do want to put this back in the characters but we we can talk about this in a sec um if I delete this page. TSA right now and I move go to characters do you think this will work and the answer is yeah it does so why is that that's because when you fetch data in the layouts whoops sorry when you fetch data in the the layouts whatever you return here is passed down to child pages so if you sort of see what we have here this is loaded in the root under this layout and then it's passed down to our characters which is then passed down to this page felt which is our current page uh and it's available as characters for uh well this page felt actually data. characters fascinating he so yeah you can load data right in your smelt file so one thing though if we were to say let's do this if we were to say go into one of these characters and just add something random here you know not an ID well I mean that's not bad it's just kind of empty um sort of a silent error though it doesn't really tell us what happened it's just like oh this is a Bob's Burger character it's not the best but what we can do is we can have a real error here we're not really dealing with errors here this is just sort of the result of not dealing with anything um and so if we come whoops if we come back in here I keep accidentally opening this bookmarks because that's also the command to open the Side Explorer here we can add an error component so we're going to new file and this is plus error. spelt and actually just to show you we can do this other thing if you go to the route here and you have that uh spelt VSS code extension installed you can do spel kit create Plus error spelt and then you say the path of your Roes but in this case we're doing it at the root and now it created an error. spelt for us with just a little extra stuff in here already so you can see here we're importing that page store from app. stores that special dollar sign app. stores which is sort of generated for us by spel kit uh while you're building things and it it knows what these particular things are so in this case we've got the page status a colon and then what if message the page error gives us so now we just need to see what happens first let's go back and oh doesn't really look any different we go in here add some random data and we've got the same thing and that's because we're not really dealing with the error where it's fetched so in our characters ID page TS we've actually is going to make some changes here so in here we could do you know a try catch but that's really not actually the way you're supposed to do it um and it really won't work in the end what we really want to check is whether this response was okay so there is on the response object and this is just like the response object you can look that up on mdn this is not a spelt kit thing per se this is a fetch thing um there's an okay property and so we want to say like if the response is not okay and that's a Boolean we want to do some sort of thing we want to throw an error you know a new error um whatever this is and now you can start of see oh we're getting a 500 internal error and that's not right it's not a 500 internal error this is supposed to be more like a a 404 this just doesn't exist oops and maybe it's because I spelled it wrong but no we're still getting it and it's just I think how we're pulling the error out so the error happens here we've thrown this error and because spelit sort of basic page thing can't decide oh I don't know what's causing this air it just says it's something on the server I don't really know what but if the API is responding telling us hey this is more than just like a server or there's something on here we can take that data out so in this case what we want to do is actually spelit provides us with an error function so we're going to import that so import uh and it's a named function or a named module from and this will be at sp. JS kit so that's sort of the spelt kit module name and now with error you can sort of see maybe if I hover over this typescript will tell us error takes like a status and then the body of what the error essentially so in our case what we can do is if the response is not okay we're still going to throw but we're going to throw an error and we're going to get the status off the response and then we're also going to get the uh message off the response now I know that the API responds with Jason even when it errors so because of that I can say well let's actually await the response but not text well this will be um Jason because it's ajacent response and we'll just call this like er so I don't want to use the word error I used it and from ER I know we can get a description of what the actual error was you know a sort of a user description so now we've got the response status and the response error and I think we'll get a much better message now for this error so I'm going to hit return here and uh we [Music] don't and this doesn't look like the right kind of error page anyway so back to debugging so I don't want to bore you with all the debugging but essentially what happened was all I did was stopped the dev server restarted and everything started working as expected so as you can see here with the plus error spell page in the root uh we are catching it and displaying this as a custom error page rather than the default error page we've got access to the page data the status and in this case the error as well and so that is custom error pages and custom error handling so now let's talk about nesting and grouping um so an interesting thing you can do with a layout file or a plus layout file is you can put it in any of your route directories and what this does is it has a nesting effect so for the route you were on it'll render the page wrapped inside the layout which in turn is wrapped inside the layout from its p Parent Directory which in turn is WRA inside the layout from its Parent Directory and so on and so on until the root directory so like this picture kind of indicates uh maybe the header and the footer are from the root directory plus layout file but the dashboard route also has a plus layout file in that directory um which provides the dashboard sidebar and then the children of of of you know SL dashboard are analytics and uh settings and they decide the content that is then passed into the slot in the dashboard layout and that might look something like this you'd have the dashboard it has a layout uh there's a root layout do spell component and then the analytics and settings pages are child components of the dashboard route so let's talk about groups so sometimes especially as your routing grows uh you just want to be able to group routes together sometimes it's a logical grouping sometimes it's because they all share uh the same layout um and perhaps you have some routes that are maybe like app routes and some that are you know oh these are website routes and they have a totally different layout totally different look totally different styles sheets but you want to keep them all in the same app and you you just want to have uh URLs that aren't affected by these groupings and so you can do that with these parentheses these groups by using parenthesis as the directory name the directory names it basically takes it out of the path takes it out of the route doesn't affect the URL path essentially and this allows you to sort of group certain things you can also put like plus page do spelt files directly as a group child and that just sort of indicates that oh this route this the the root here of this route the root of this route uh belongs into one of these groups and therefore shares a layout so we'll see how groups work with the live coding portion but let's also talk about errors so like layouts error Pages can be nested as well um and what this allows you to do is basically it catches the errors wherever they're loaded so if your error occurred in a uh a load a load. TS loading function um or sorry a uh page. TS loading function what it'll do is it'll look for the error after it errors it'll look for an error. spelt file a plus error. spell file in the same directory as the load if it doesn't find one it goes up the oh up a directory it basically climbs the the directory tree uh looking for one there if it's not there it goes up it's up until it hits the root if there's nothing no error dos felt in the in the root file it displays the default error if it's if your error is thrown in a layout load function though layout. TS load function it'll actually sort of skip the sibl error page and just go up it'll look up first and so if you're in the root and you've got that error. spelt page in the root it'll skip that and actually go right directly to the default error page Now the default error page can be customized by putting an error. HTML file where you have that app. HTML file but we're not going to be doing that in this particular module um so the common use case of the error boundaries like this is basically if you have you know a very nested route and it's only sort of showing the content of a section of the page and it errors there maybe the load errors there you can sort of confine the error to that little spot rather than blowing away the whole page which is what we were sort of seeing uh when I was doing it before so I am just going to show you this with live coding now so I am going to switch branches and we'll go in here so what we have here is kind of a a similar idea to what we were showing before uh we have home and about and these are marketing Pages these are designed to like bring people to the app but then we can link into the app itself and so in this case we've got the app dashboard and it's got a totally different layout totally different feel in this case we don't want what's happening right now which is that Universal nav that top nav to be showing in the dashboard because this is something you log into this is like an app you use it's not about the marketing of the website it shouldn't be included in the app itself so we basically can solve this with routes or sorry with groups so to make a group we just use the parentheses oops so to make a group we just use the parentheses we say marketing and now we have a Marketing Group and so what we can do is we can take the uh layout we can sort of drag that in there and now once we're in here we're going to have to adjust this because it's you know the the pathing is no longer correct if we were using the lib this actually wouldn't be a problem but the pathing has to go up one more level now just to keep that style right um if we go back home here uh we'll need the page content so we'll also need to drag that in there so now our root is under the marketing and then our app uh is sort of its own thing so it's slapp dashboard and they're like oh wait wait wait we actually need about in there as well right because about is a is all part of the marketing website so our about page works our homepage works but we don't want slash app dashboard in the routes we want to have it just be slash dashboard it will go to the dashboard we just don't want it uh that extra segment essentially again no problem we can use groups to solve that uh so if we make you know the app directory here if we turn this into a group by renaming it with the parenthesis um now it's a a group called app and so our our uh link working there anymore and we'll have to go into that main page you know this is where they would link you know log in or something uh and we need to change this because this no longer has the slash app because that's ignored when dealing with the URL and so now we have uh at SL dashboard the dashboard and the about page and they're sharing different layouts different styles so oops so now let's talk about nesting a little bit let's go into the about directory here uh let's close some of these off so in our about page here we are going to add a little layout so we're going to add a new file here would be a plus layout. spell directory and in our about layout now um we're going to add a little you know this is going to be the about sidebar let's call it so we'll do sort of like a a section and in our section we'll do an aside and in our aside we'll have a li a nav and in the nav will'll have a list I'm hoping uh prettier will come clean this up and then uh I guess this is where we would do UL sorry and L and this is where we would do sort of our different links so we're going to have different sections that all sort of belong in about here um and so we will just have let's just do a we'll have a section that is about Slash team and we'll say this is the team trying to think of common things from the about section um and then in another one we will have about um maybe we'll do about story our story uh yeah our story I see that you know something is not light here uh oh it's rough and lastly we'll do about a mission maybe this is our mission now each of these are going to just have some extra page stuff so this is in the about page you can sort of see it's not in the homepage it's obviously not in the dashboard or Le maybe that should be obvious um but this is sort of just extra sections to the about page so now we need to actually add those sections in uh so oops in our about here we're going to need new folders so we will have our team so this is again the routing so you're going to control the routing just with these directories uh we'll do another folder which is um was it again uh story and uh a new folder that is Mission and now in these we just need our page so we'll say okay we need a Page Plus page. so this is the actual content and I think we'll just keep these really simple um we will just say you know H1 the team and maybe a paragraph that just says this page this is about our team and maybe we'll do another so story we'll do kind of the same thing uh I'll even copy and paste this just for a little bit of share time this will be our story the story of our story and lastly our mission our mission this is is about the mission um okay so with our little uh nesting Happening Here We realize that oh nothing's actually showing up for these and that is because I didn't put a slot in our layout so you always need to remember to put a slot in your layout so I'm just going to add a main file here maybe uh I'll just add class main so that it's not the actual Main and I'll throw my slot in here slot and now we can sort of see oh hey this is showing up uh our story but I wanted this to be a sidebar so I need some Styles style and I am actually just going to copy and paste these Styles even though there's not very many we're basically just doing a little bit of a flex okay um maybe this just isn't widen enough we widen this out oh no it's still not quite affected here so we're in our layout we have our this is our class main um right I guess this needs to go inside the section there we go so as you can see here if you go to the about page you get the about page content and and if you click team or our story or our mission the whole page doesn't change it's really just this little section that's changing over here oh and I see I've got a typo on the team page no problem we can fix that this is about RT so now what would happen if we you know we're loading data this was this was done Dynamic content this wasn't just our static stuff we're loading data for the mission here so we're going to make a uh Plus page. Ts file we're going to add our load function export oops export uh load function and I think what we're just going to do in this load function is we are going to immediately throw the error so now we're going to have to import error from spelt .js kit and it needs a status so in this case we'll do uh maybe a 500 or yeah five let's do a four or4 and say uh you know there was no Mission so what's going to happen here now is going to try and demonstrate this is we're going to look at the about page we're going to look at the team page we're look at the story and as I hit this for the loading oh we've got that pre-rendering thing uh let me just quickly knock that out I forgot I changed um branches but I didn't get rid of this in this this Branch I guess so get rid of that again that's going to just confuse things so we're going to hit this Mission and oh it blows away the whole page this is the error page showing again 404 there was no Mission but what we can do is we can add you know an error Handler here an error boundary so here's our error dosf uh we put this specifically in here actually I'm even going to use no no this is fine um yeah I'm actually going to use the uh the plugin again the vs code plugin to create this air page because then it just starts out with a little bit of extra stuff already in there and so now with this air page just by where it's positioned close this off we can see I just want to pull this open if I go to about our team I'm going to go to our mission oh it doesn't blow away the whole page again because this is where the error happens in this load and this error exists so it limits the error to here now we are still seeing the error page but it's confined to the section that actually eror rather than blowing away the whole page and you can sort of see the difference as this moves up now in this particular case just by the way uh Mission and team don't have their own layouts moving this up one layer actually won't make a difference at all if we move this to about this is going to be exactly the same because that's where the error happens our about content is good our mission content is where it airs so it's caught by this airor and it's confined to this section where the slot is but if we move it up yet another section into the Marketing Group here well this is a little closer to the root this is you know the the error happens and it's caught by this error so you still get the the global nav here the the top nav um but when you go to here oh the whole about page content is is blown away and of course lastly if you were to move this up to the root now it will just pretty much behave like it was yeah essentially you're going to hit here and it's going to blow away the whole page and just have the entire error and if you took it away entirely well you would just have the default error page showing so when I go to here we get the default error page which looks kind of the same so now we get to talk about something called parallel loading so when you go to a route in spelt um it sort of synchronously figures out which load functions are going to be needed and then calls them all together at the same time so this is good because this helps to avoid waterfalls uh all the load functions may not depend on each other there is a way if you do depend on sort of like a layouts you know a parent layout or somewhere in your trees you can await parent there's a a parent that gets past as the event a parent function you can await the result of that function and depend on it so that you can you know maybe get some data that you depend on before you need to fetch something if you do do that you are reintroducing waterfalls and so there's kind of this uh thing you have to take in mind you need to uh know that it CS all the load functions at the same time which reduces waterfalls and you have to be careful not to reintroduce them by what you're doing so just to check out what this looks like I'm just going to whoops I'm going to switch branches again to look at something a little bit different okay so this is our page Advanced server techniques um I'm about to click on this theme picker and when I do we're going to see what we got now uh one two 3 four five oh there we go so that was a long load from when I clicked to when it showed up and the reason is I've artificially load some apis so we've got some apis here I won't go into the Crux of these we'll get to building apis later but the idea here is I've set some artificial delays here of two seconds on these API responses so each API both colors and config are going to wait two seconds before they actually respond which is just kind of delay that response um we've got in our theme picker here we've got uh a regular layout uh which just adds some Styles uh in our theme picker though we have have uh a layout which does a fetch for some config let me just get rid of this layout which does fetch for some config and passes that and then also in our page we've got a load function that Waits For That config then also fetches for some colors and then uses the config theme passes that up and then in our actual component we're basically figuring out we we wait for the data we figure out which theme is sort of the default selected theme and then we display and so that's where sort of this delay is coming from um and this is what we get one two three four there we go so now I just want to show you something to make a point if I were to take this line here where we're waiting the parent and uh to get the config here because that's from the layout and I just move it under colors just moved it everything's still the same everything still what do you think's going to happen well I'll show you let's hit refresh here just to make sure I'm getting ready to click and click one two boom no longer a 4 second weight it's 2 second weight why is that it's because just by changing the order here you can sort of see oh how these promises operate this await is awaiting for colors but this await hasn't been hit yet the code is sort of suspended here meanwhile though like I said it collects all the load functions that needs to run and then calls them all together all at once so this load P function from the layout this has already been called so This Promise is already running this fetch is already happening and so since they both are delayed about two seconds they both happen at about 2 seconds seconds and then this returns so that's why you can see such a uh drastic change from the 4 second to the 2C here just by moving that now this is sort of to demonstrate if you don't need to depend on a parent for whatever data you're fetching don't wait for it um so in this case we actually don't even need to await this config we don't depend on it at all and the config even though we get theme out here the config is already loaded in the layout and since the layout passes the data loader to all the pages like to all directly into the page component we don't even need this here we just need to change our component a little bit so if we go to our component now and wherever we're getting theme from here uh right here instead of just pulling theme off there we actually just get the config which is available from the layout and get the theme like that well then we don't even need that and this is all still going to work so we're going to get in here we're going to you know click this one two boom still going to work and we didn't even need that and another thing um just because of how spel kit does things is we don't even need to await in our load functions really because if you're awaiting um sorry if if the thing you return the object you return the properties that are sort of the top level properties so not a you Nest them but the top level properties are promises like if the values of this object are promises spel kid is smart enough to know to await those already so if I were to just take away this await and take away this other weight um this will work exactly the same so we've taken away the parent we've taken away the we simplify this a lot and there is going to be no noticeable difference one two it's going to load because smell kit again waits for those top level promises if the promises are nested it does something different but we'll get to that later [Music] um yeah just something to be aware of uh it's important to understand how the parallel loading Works uh and not get confused with it so that you don't accidentally cause your own sort of uh problems essentially your own sort of waterfalls so that was the routing module it's a little bit long uh had a little bit of debugging going on there but what we saw was we saw how to use uh plus layout files and Slots uh we loaded data for the page T from page TS uh load functions uh we loaded data in layout TS functions we saw how to use prams and the Dynamics you know with the Box uh route segments to you know load we Ed them in a load function to load the details for the from the API uh we saw how nested layouts worked with the you know the little team about page with the different nested layouts uh we saw how grouping sort of changes the directory structure but doesn't affect the routing and how you can use that to sort of group things logically and have similar layouts for different things and we saw how to catch errors and how to display those errors either you know confined to the space they want or globally and how to customize those errors so that's the routing module let's move to the exercise so now we're into the exercise portion of the module so for this exercise I want you to use the skills you've learned to build a simple blog now we're going to provide you with the data for that blog and you can change the data if you like of course but we're going to give it to a you in a package which you can put in your Live slost directory and it's going to export two functions get post summaries and get post by slug you can use these functions to then create a blog index page we just basically on the we want a page that lists all the all the blog posts with their title and excerpt and then you can click on the title and it goes to a you know navigates to a blog post page with the slug and shows all the blog post title and the content simple enough um you can find the library at sp. funpost doz it's a zip file unzip it and then you can just put the contents into your lip if you have any questions you can have to text me I guess because this is a video and of course I am going to be going through the exercise what I would do but I encourage you to pause the video try for about 20 minutes first and then come back and see how you did have you done that pause it now okay you're back so I'm just going to show you what I would do with this challenge okay so this is what we want all right so starting with the project that we already spun up before um so let's we've got the example here let's just do what we did earlier and kind of delete everything except that style we'll keep that move everything else to trash and I'll move the Styles up to the source because I like doing that and we'll get rid of everything in the lib as well here uh so just so we don't have these errors showing let's create our plus page. spelt and this is just our you know blog post page I guess we can call it uh felt kit blog and let's just make that go that Arrow go away and there we go uh so it's usually a good idea to start out with a layout so let's do that let's add a new file plus layout. oops try it again new file plus layout. spelt and in our layout here we will this is where we will import that stylesheet so import and we can just do the relative path and styles.css and there we go and now you can see there's no content here um because we haven't got a slot so we need to add a slot we'll just add a self closing one and then so we might as well add a few extra pages for that extra credit so let's just add a nav here and because I love it oh let's just use well let's let's just do a home and about all right so now we got home and an about page link we can quickly create a about I'll use the spelt kit vs code plugin here to create a route so we want an about route and I just want to put a page felt in there and I'll do something similar to the homepage I'll just you can get rid of all this uh this type data you might be wondering what is all that uh that is types you needed before but now can be completely inferred by spell kit because spell kit is always getting better and better all the time so in this case we'll just say this is is the about page and you our about page we might as well do the title thing as well so that's the spelt head and we'll put a title in there oops a about page not the and about page and there we go so back to our blog oh we might as well do that for the blog as well I guess so in the main page here we'll just add that title we'll just call this the spell get blog as well now we're going to want to do a list of all the blog posts and we'll get the blog post from that Library so like I mentioned before you can find that library at F.F funpost doz because it's a zip file and that'll show up here whoops let's get that back our downloads here okay so I've unzipped it already here and we've got this posts which we can actually just drag right into our vs code so let's see there just drag that right in and I'll put that in the lib there we go um you can check it out uh so there's an index you can just import from post this DB Json is just you can feel free to change the contents of that entirely and uh we've got our type post and our methods here so or our functions so yeah that's what we will be using so now we should I guess we'll start with a list probably a list of Articles seems like maybe the way to do it in my head let me know if you think otherwise uh article seems to be a good you know this seems to be the natural use for a article tag um and in here we will do yeah basically a link inside the title and then the slug will be the link there and then we'll add the content so now let's change this to actually use the data so it'll look something like that and actually let's add some Styles because let's get rid of that little uh list style there so if I add here let's go with h H1 let's style it with my favorite color Rebecca purple and we will do a margin bottom just to add a little spacing uh between each of the blog posts we'll do three rim and let's get rid of that list style like I said list style none and and yeah um what are we doing here H2 so we'll do H2 and we'll say I don't know margin zero because then we can have it sort of budding right up against the the excerpt and our articles oops article we can basically maybe add a little spacing to that instead so that the they'll be spaced out but the uh The Heading will be right up against the excerpt I think that's probably good we can even match the spacing of the title for that okay so now we need to fetch some data so we open up this we've got to add you know a page. TS so this will be our load function that we'll need to make need to implement here so let's export load that'll be you know it can be an async function usually is a good idea to make with that so you can await various things and now this is where we are going to need our blog post so like I said you can use the content that we already gave you we don't have to do actual fetches yet we can do that in a different exercise um so for now I'm just going to import the get post summaries I think it was summaries from lib SL poost so again this is the shortcut lib it'll go into that lib directory and then posts and then we're going to use that so I think in this function we can just return posts we'll just yeah well we don't even have to await this so because of the top level of all the objects returned by the load function are awaited if they are promises uh we can just assume if this is you know acing function it'll load correctly and if it's not an asyn function it'll still load directly so we don't even need this asnc at all this will be our load function and now if we go back to our homepage here just need to add that script tag and then we'll get this data loading in here so the way you again um add prompts or sorry the way you get get access to that data from the loader is to have a prop named data so we'll do a get data here now this data should if the types are correct here have a post on it you can see it does oh and it even says our post has a slug a title and an excerpt so that's great uh so let's do a little reactive variable here we'll call this posts it'll just pull off posts and then inside here we just want to do an each each post as instead of doing post as post let's pull off the individual things that we need to do is like slug title and I don't think it was description right it was excerpt what was that again oh data oh guess it's not going to let me do this gotta finish get out of your error State before you can see the types there we go uh excerpt yeah S Title excerpt thank you typt okay so now let's do the our Replacements so we want to you know we don't have hello world for everything we actually want to replace this ref with the slug uh then we want to have the title here title of the blog post and of course the content let's keep it in a P tag we don't know what's going to be inside there but I know that it's going to be text so in this case I'll just put the excerpt like that oops some problem with me in spelling exert and there we go you can see this coming along nicely we've got our blog posts uh you know we could use maybe a little more spacing or a little less spacing between this H2 let's do or maybe it's the P tags yeah it's probably the P tags let's do that maybe a bit too much let's do just these P Tags by adding a class expert exert I will spell it correctly at some point hold all right then maybe if we need to change it to a div later we can change it okay so here we go we have our Pages um we can sort of hover over this and see it is going to a slug based on date and this one says OCT 2022 and we've got our little uh description so now let's do the individual pages so for those we are basically going to add a dynamic rout here here let's make this a little bit smaller again so we can see what we're doing so we've already got our about route and our home and I think our our uh blog can pretty much be just right off the root here we don't need to do SL posts or anything we can just do the root because well we'll learn about it later but the way this will work is the about page will still be accessible so let's do that let's just add a new directory because again directory based and we'll have the dynamic you know the oops the dynamic box we'll call it slug so if it doesn't match about it'll match a slug and in here we'll need a plus page file of course and we can think about what we want for this um I think we kind of want to copy most of the other Pages first so we'll do for the title it'll be blog how about and then maybe its title uh we're going to need that data but we'll get that in a sec uh script this could be data title and same with this now of course it's erroring because we haven't set up that load function for these types yet and then uh we'll do an article oh I guess this should all be an article actually article one article being the whole blog post and we'll just do I don't know another P tag for the content again data. content all right now let's do the load function here so again we create a Plus page. Ts and we're going to need a load function so we get load oops and yes co-pilot already has predicted this we will need params because we're going to pull that Dynamic slug off the pams here so whatever is sort of in the second segment on the URL is what we're going to get as slug as long as it's not about uh so from there we just say you know C slug equals pams slug uh we don't need that join thank you very much this should just be a string and I think just because of those errors then we are going to return and now we need an object that's going to sort of represent uh this blog post so we have that function which we can import which is import get post by slug posts and I think maybe this returns an object returns a post object yeah so we can actually just return this I think and then we'll get all sort of the individual uh objects separately we could also add a post maybe just for good hygiene we can just do Post we'll call it and we will pass it the slug so now if we come back here might need to hit save again we've got a post right so now we need to actually make this not data so this will be uh well we'll do the reactive one so that it actually changes post and then we'll change all these little datas to well we could even well let's just do it this way post title post title make sure put that in the little templating interpolation thing and post content okay so what is post undefined it says it's either a post or undefined and what does that mean exactly if we go down to here our post has slug title exer content okay so this should be okay slug we don't need Title post title oh it's possibly undefined because it might not find one okay well we're going to have to deal with that that so for now I think we can do well let's actually deal with that in the load so instead of posting here let's do c post equals and we may need to await that um we probably do just in case it's async and now we can basically say if there is no post so if this didn't find a post matching that then we can throw an error and we want to import that error because we don't want to use the error just a regular error we want to actually use that error that spell kit supplies from spel js. kit and so error takes a status and then a message or a body so we'll do error say 404 post not found sure that looks pretty good now we go back here everybody's happy because we know if it throws ahead tight scripts aren't enough to know that oh well now I know there is a post so this is actually just a straight up post time and let's see what we've got if we open this up just to see a little more this is our index page we hover over this it's going to go to December 02 and there we go nice we might want a little bit of styles you know maybe we want to do article Max width and we could do something like you know whatever smaller maybe 600 pixels or 90% I'm not much of a designer so you do whatever you think looks good but I'm just trying to think of something and maybe we just want to like Center it in the page so margin Auto and there we go that looks pretty good if the screen gets too big oh maybe my um Max width didn't work or I'm mistaking how it works article actually kind of curious let's inspect here so our article is Max width well maybe 600 just isn't big enough if I change this to like 400 or 200 I guess it's just not big enough so let's let's drop this all the way down to 400 and uh now we might be able to see that difference so whatever is smaller 400 pixels or 90 there we go cool and that is the exercise so again uh the next exercise we can build on this same thing so keep this around keep this project around or if you need to you can go to the repo and just check out you know whatever the current state of the next exercise is see you in the next module so welcome to module 3 even more routing so to be as flexible as possible spel kit provides a bunch of routing features so that you can create the URL structure you want without having to compromise um and so we're going to just go through Rapid Fire a bunch of these features so to see how they work with little examples so the first is rest parameters if you don't know statically how many route segments you're going to need or what they are you can use the rest syntax uh so similar to the rest operator in JavaScript uh you know function parameters you can add three dots and adding these three dots to a dynamic segment is a rest Bram so in this case here um if this was the routing structure we had with the directory so or repo tree is like not Dynamic branches Dynamic and then dot dot dot file if we were to navigate to this route then the prams data we would get is this data right here so it matches the org y That's in prams repo is in prams branch is in prams and then file comes back with the rest of the route so the rest peram comes back as a string not as an object so you have to parse that string yourself and you can do whatever you need to do with that and it doesn't have to be used at the end either but if you do use it in the middle you need to be aware that that it will match whether there is an inner segment or not um so in this case this is going to match you know a/ C if if there was nothing A B C or any of the like anything that has a but also has a c sort of at the end so to look at that we just have a quick little example that kind of follows exactly what we said here um we have this route or repo tree branch and then file and so just like I said in the the slide here's a link I'm going to click this link and you can see it's this page TS is or page felt is just displaying the the pams to the page and what we got back for pams were org which matches this you know uh spelt JS kit or repo which matches this kit branch which matches Master because tree was uh uh you know was static it was already just defined right here uh as the word tree so in order to match that had to be exactly tree and then everything else just gets put under file as a string and you have to match that yourself so that is rest parameters optional parameters so let's say you had a route you know and and your directory structure was sort of dynamic Lang and then slome let's say this would match in home so let's say you want the language code to be the first segment you get language from the PRS and then you you send translations uh based on that let's say but what if you also wanted just slash home without anything there uh to also match um in this case it wouldn't right you you wouldn't have a lay there so it just doesn't even match the route at all but you could go through the rigma roll of you know oh I'm going to just have another slome directory and you know in the route and that'll just make work just like slash Lang slome but there's a better way obviously if you just wrap the dynamic parameter in double boxes double square brackets um it becomes optional and now the route matches even when the first segment isn't there when you do this the prams will come in as empty uh but the route still matches and so the files that Jud you know what you're going to actually serve uh is from the page. felt or whatever uh and what you're going to load still matches so let's get a little more live coding explanation of that uh so we've got here an optional parameter of Lang we've got our page here and you can sort of see in the code what's happening is we get our prams and if Lang isn't defined we default to but if it is defined just use whatever that is and then in our spelt whoops in our spelt component here you can see we just basically use that right off of the data and so what we get from that is this we basically have our route defaults to English but if you wanted to have French or Spanish you could have that and all the rest of their website could follow down after these after this match breaking out of layouts so in general the layout. felt is in effect for all the child routes defined below it you know in the directory hierarchy but you can break out of that using the at segment syntax uh you can add that to your file name so you can add an at about to the plus page. spelt file name and spelt knows to break out of that layout all the way up to the about section layout uh so essentially this would ignore all the layout. spelt files in between their and their loaders as well so in this case uh the layout at section ID layout and section ID info layout would be ignored you can also just jump right to the root by not adding a segment so you've just out the at file page at. spel it'll break out all the way to the root layout um so just doing this uh can actually be a good strategy sometimes it can get confusing trying to do everything with groups and layouts and it can kind of get messy uh so this technique just kind of gives you an option where you can always just rewind all the way to the route then import like a reusable layout or loader function and use that here um just giving you full control in the end and so things don't have to get too messy this of course also works on layout do spell files they can break out as well using the same syntax um yeah in this case the layout if you add it outout would just jump all the way to the about file uh if you do it this way everything Below in the hierarchy for this layout will also have been effectively Broken Out In the exact same way so this might be a little confusing so let's let's check this one out oops so we've got our old example here where we've got the app and the marketing and the app has its own layout and ignores the marketing and the marketing has this like nested layout uh especially the about page here where we have the team the story and the commitment in this case uh and so if we show by opening commitment here if I'm going to go up to the about page again and I'm going to I'm going to rename this commitment to at page at and now we need to go higher than the above Pages currently this is using the about um layout so if we go all the way up to marketing the group layout here then that should get us all the way up to this marketing layout. spelt and so you can sort of see how that works the about page looks the same team looks the same story looks the same but if I click on commitment here we've lost the tabs because it jumps out of the the tabs are brought in in this about layout uh but this has jumped all the way up to marketing layout so we still have the top layer and now if I also were to just like take this completely out now this will jump all the way to the roote and uh oh let's hit refresh there I think uh again Sor commitment all the way to the root so we don't even have the top nav um and that actually sort of demonstrates an interesting problem with CSS loading and how it works because if I hit refresh here CSS never loaded because the root layout doesn't load CSS in this so we actually need to add a root layout to this this example but yeah that is how the example uh you can break out of your layouts in case you needed like more control over exactly what things look and this is how you do it with the at simple so matchers matchers are a way to really get control of your routing by validating what actually matches a route so let's say you have a route like post slash page where page is dynamic you could match you know page sl3 uh and that might be what you want but it would also match page SL what does this do because it matches pretty much everything ites doesn't differentiate between what are like numbers and what are uh strings uh but you can specify that with matchers so matchers are predicate functions functions that you want to return true if it if your parameters do match and false if they don't match so spelt kit looks in a special directory Source per Rams source params for matchers the file name indicates the name of the matcher and every matcher file has to return one function called match uh it has to export that sorry not return that the file names can only be alpha numeric and have underscores uh and that's sort of to match how it uh will be called sort of or introduced so in this case this is a match file this would be at source prams Workshop unor type and there's some types happening here but what this function essentially does is it's only allowing in the strings intro intermediate and advanced to match if it's not one of those three specific strings this route will not match and it'll either fall to alphabetical or default or whatever else you know however you're doing your matching the way you add the matcher to the dynamic parameter is just with an equal sign essentially you say you have your Dynamic page and you just add equal sign and then the name in this case Workshop type of the matcher that you want to use so now this route would only match if it had one of those three valid Workshop type segments uh failing to match and throwing a four or four if it was something else is probably what you want so let's see how that works uh so we've got the same setup from earlier uh you know we've got the characters loading here in our our Bob's Burger but let's say we didn't want you know we like it you know if you type in an ID that's out of range oh yeah we like to say hey that character is not found but we kind of don't want just like gobble theg you know what does does this do to like show this screen this like character not found we kind of want this to throw like an error or the the go to the error page like this page isn't found what are you even looking for um and so the way we do that again is with matchers so we can do that by oops we can do that by adding a directory here and this will be pams because it always looks in pams and now we name the file uh basically whatever we want our matches to be so this in this case we only want integers to match so we'll just call it integer and that'll be the matcher we use and then inside this file we need to export a function a predicate function called match and now this function is going to get a value and it's always going to be a string because this is sort of the segment value and now we just need to return true if it's what we want to match yes and false if it's not so in this case we can do return and we can just do a re X actually this is a really great one what it's had uh this is just any digit uh you know one or more test and that's it if there's something else in there it's going to be false so that seems like exactly what we want um and so now the way we use that is in here where we've got characters and their ID we just need to change this directory name this Dynamic ID to include integer as a matcher so now this will continue to work we can see doy um and if we go out of range you know 999 uh oh we still get a 404 character not found but if we go back to that what does this do just like some other route it throws 404 because this is our default 44 hey that page doesn't exist what have you even looking for so that's how mattress work so with all these different ways to match routes it may become obvious that one route can match multiple route paths so route priority or as it's known in the spelit docs sorting is basically deciding which route actually matches when multiple routes could match so for example if you're navigating to fu- ABC you would actually match all of these different routes configured in your directory structure so how does it decide which of these like page do spelts is actually going to get served well there are rules uh basically the uh first rule is that more specific routes will have higher priorities so a route with like no Dynamic parameters is more specific than a route with one Dynamic par parameter and will therefore have higher priority uh parameters with matchers are a higher priority than those without optional and rest parameters are basically ignored unless they're the last segment in which case they're still dealt with with the lowest priority uh so what does that mean exactly it means like if you had X and then an optional parameter Y and then Zed this has the same priority score essentially as XZ there's it'll it'll be sorted based on something else because that's the same priority and then lastly all ties are resolved alphabetically so just to take a look at that if we look here U we've got basically that set up we've got Fu here and if we look at our whoops let's just get rid of this if we look at our directory structure you can see we've got right now just one actual route in the route so this is the only route that's going to match but I've got these other routes and I'm just going to drag these into the route to demonstrate the priorities so now fu- ABC could match any of these and so if I click here we can see ah this is the one that's being served that's what all these just say which one is they actually being served so of course the one fu- ABC which is the most specific with no Dynamic parameters at all it's the highest priority but if we move that one out so it's no longer an option and I can like go back to here so it's not to ruin the surprise um which of these do you think will be the match Now Catch All a equals b b or fu- c um well if you guessed f- C you'd be right because again we've got some static parts of this so it's specific only going to match on Fu Dash and then the dynamic C so that's higher than the B the a the whatever so we move that one out and which one do you think will match now oh it's the matcher right because Dynamic routes with a ma matcher are higher priority than those without so of course it's going to be higher priority than the B and that of course is only if it actually matches um let's move that out it would be the B and last ly because it has no real value the catchall which is a rest so that's a demonstration hopefully you understood how priority is determined and which actual route is served based on the rules so in this last uh module we talked about a lot of different things we talked about uh rest parameters we talked about optional parameters we talked about uh breaking out of the layout hierarchy we talked about matchers and how you sort of Define those to narrow what routes are actually matching uh we talked about right priority and which would actually serve if you uh have multiple routes that match multiple different uh directors now on to the exercise so for our next exercise I'm going to ask you to add a portfolio page to the blog you've already created in the last exercise so this portfolio page uh it has a few requirements so it should have a list of project links and you can style them out of image whatever you want um and these links should open a new window and that window should not share any Styles or layout at all with the blog Styles and layout uh they should just be completely blank sort of like the demonstration here in the slide so one thing you might want as a hint is you probably want to import the style CSS in the root layout so they have access to global Styles but maybe you want to move that around possibly not sure there's lots of different ways you could solve this lots of different ways you can implement this so feel free to like just mess around try things out experiment um I am going to give you one example of many of adding a portfolio page right after you give it a try so give yourself about 20 minutes and then come back and watch the rest pause the video okay I'm going to assume you tried it how did it go hopefully good so here's what I going to do so portfolio Plage okay we're going to make it look kind of like this all right good let's get rolling so here is our blog from the last exercise so let's start out by doing some things I guess so I guess the first thing we want to do maybe we will just fix up some of these little Styles so in the root layout we could add add maybe I want to do this in the Styles let's add a little padding to this body because it looks a little squished right up against the uh the Border like that let's just give it a one R padding just to add a little space there and now uh you know maybe in our uh layout here our root layout add some style and we'll just give like uh you know we'll have the nav let's not do Justified content let's let's do justify content uh Flex end let's move it to the other side there we go and we just need a little Gap in between those okay that's that's looking pretty good so yeah with the Styles like that now I guess we can add a portfolio link so first off I'll start by adding a route so I'll use the uh VSS code extension here and I will add a route called portfolio and I'm just going to add a page felt to that right now and in here we'll sort of like steal kind of what we do with the about page we'll just put portfolio here instead oops here as well and then I guess we're going to actually need a link to this so uh in the layout we'll just add another one here another link and yeah we'll just thank you Goot just take that one okay so now we have home about and portfolio go to portfolio see portfolio title all right off to a good start so now let's make our portfolio uh so let's start out with a list you know this is a list of our projects so we'll do a UL on Li and maybe just for style sake we'll just get rid of the list Styles padding and in each of these we would like to do a project card so a good thing about spel that I like is that it's so HTML focused just HTML and JavaScript and CSS that you can pretty much use any examples you get anywhere so let's just go onto the internet and Google for uh CSS card maybe and uh just take the first result here okay this this actually looks pretty good this is kind of what I want and so I'm just going to inspect this um that's the image just bring this down a bit maybe I'll make this bit wider and let's find that card here we go so I am just going to right click and like copy the outer HTML here and or or actually I can just take this right here and just pop that right in there okay and then we just need the Styles so I can sort of do the same thing well um here let's just make some Replacements first so in here uh we don't want this uh because that's you know doesn't exist here uh let's just put for now uh placeholder doom and uh we'll just do the 150 pixel size um holder oh it looks huge I think that is because I am uh zoomed in a little here but let's keep going here so I am actually going to just grab my Styles so that I don't bore you you can play around with your styles for these cards it's really not the important prer right we're not learning CSS here we're kind of learning uh spelts so I'm just going to paste my styles from my notes here and there we kind of have that uh that same looking card looking pretty nice so now uh we want to make three of these we want to have like projects right project one project two project three so let's just kind of make those exist so let's turn these cards here let's turn this card here into a link and we'll give it a h of we'll just make this one go to SL portfolio slash uh project one and yes this doesn't exist yet but I will create that in just a second okay we got got a hover effect there and uh let's just change this so this will be you know project one and then a description something like a really cool project you know and then let's make three of these so just copy and paste you know we could load this from data but right now I you know I I don't want to so yeah three and just change these to project one and three and maybe we'll change the description here to I'll just say this one is uh experiments with smell kit and maybe this one is uh an awesome Todo list Okay so we've got our three projects now we just actually need to create those routes so back to our directory structure and in portfolio here I just going to use the uh VSS code extension again to create a route and I'm just going to call it project one I think I said I'll just add a SM thing here and these we're just going to make super simple they're not even anything they're just a demonstration we would just want to show how we're going to do our portfolio requirements so this is just going to say prodject one nothing else or project one so now I should be able to click on this there's project one and I will just quickly do some copy and paste to make project two and in there we'll just change the project two and again copy paste for project three and the hit her again okay so pretend those projects were actually something interesting something cool but the idea here is that we we have our portfolio page now and we can link into these projects but this isn't what we want right we want this to open up in a new window and we want it to have none of these Styles like we can keep all the code here but we don't want to have any of these you know this header nav and all the styles that we've kind of got from our blog so if we open up the portfolio page here well actually what we probably want to do is we well we could try this right we could say okay well first we need to make the uh links open in their own windows so we'll just get you know ref here I'll do all of them at once and we'll just add Target equals what is it underscore blank that'll just make it open up in a new window when you click on it like that and now we need to make the Styles go away so my first instinct is I'm going to come in here and I'm just going to add that like root level layout at you know this is like escaping all the layouts up until the root level and now if we check that out will be disappointed because it doesn't work and why is that and that is because when you're skipping all the layouts like this you're skipping the individual layouts so we're skipping you know uh if there were a portfolio layout or in project but we do still get the root layout like this is the root layout and it's adding the nav and it's adding you know all the some of the Styles here all the Styles here in fact so how can we fulfill our project page conditions well one thing we could do is use groups so uh there's probably a bunch of different ways but this is the way I'm going to do it right now I'm going to create a new folder here and I'm just going to call this the blog so this is our blog group so it's going to not really affect the URLs that's just how grouping works and I'm going to put basically everything into the blocks the about page the slug uh the layout and the page and the loader everything except the portfolio really so I'm going to put that in this blog group you guys already see portfolio kind of went nuts there and oh we've got a little error but the error is the Styles right and we've dealt with that before so we know we just need to go into here this layout uh we can close these um and we just need to add you know that extra thing and there we go so our blog is back and our about page is working our you know in our individual blog pages are working and our portfolio now um if I hit refresh here you'll see it's unstyled and if I kind of go there from here uh it it's styled again but if you hit refresh it's not and so why is that that kind of comes down to where this lay this layout Styles is loaded so because portfolio is outside of the group doesn't share the layout now if the CSS is already loaded it just stays in the browser because again this has to do with that hydration uh when spelit hydrates it loads the CSS and it's still there when you look at the portfolio all the D stuff match but if you are loading directly into portfolio then it's not there so uh now if we open up their project Pages this is exactly what we want with no Styles we want to just be able to show our demo off in the new window here um but we've got to fix this project page so one way to fix this project page would be uh something as simple as just copying and pasting the layout from the blog so you know you might be like at this and may be right but this is a really simple fix we could just oh yeah we just copy and paste we hold that in two places you know our uh projects here still do the what they're supposed to do and everything seems to be happy if I hit refresh here it still loads everything the same for these now if that kind of makes your stomach turn okay sure let's do a slightly better thing let's make in our Libs let's make a layouts folder or directory and in here we will make a page layout do spelt and what I will do in page layout. spelt is I will actually take all the content of this layout you know the one that we're kind of copying and pasting here and I will put it as the content in here so now we've got this sort of sharable page layout and then what do we do so each of these are still going to need layout files because they still need the file directories and sort of the file based routing system but what we can do is in here instead of having all this stuff that might get out of sync isn't quite right we can just uh you know erase this all import page layout from dollar sign lib slash layouts page layout. spelt and then we would just use page layout here so we've got page layout and now the interesting thing you got to think about is like oh what do layouts do right they they need a slot to sort of pass things in and so our page layout would take a slot for its content and so we basically just need to put our slot right here for the page content and so now we can check out our portfolio and oh it still looks the same we can copy and paste this into the blog layout as well and now these are going to stay in sync because it's really just importing that uh page layout component and using that everywhere and I believe if I'm not mistaken we have now met all the requirements for our portfolio so we can load here nothing in the Blog has changed everything's still working as expected our portfolio I can hit refresh and it will open when I click on these links into new windows with no Styles so hopefully you came to something similar with your exercise let's move to the next module so this next module is called serers side spelt so spelt kit allows you to restrict and isolate code to only ever be run in the the server not the client so why would you want to do that well sometimes you need things to only run on the server uh maybe you want to have secrets or off or something maybe you want to send emails or you know read from a file system the point is having access to a server is a good thing and it lets you do a lot of things easily that you can't do on an SBA or can't do easily uh in the browser and by server what do I really mean because spell kit lets you decouple your app and your deployment so a server might be a no JS server for sure but it could also be Cloud flare workers or aino server or serverless functions or something else um so this next section is really just about pretty much doing things on the server but not on the client so one thing you can do is by changing your Plus page. Ts to Plus page. server. Ts it now restricts it to running on the client and Sil K it'll actually throw a little error saying hey if you try and import this into client code that will run on the client uh you can also do the same with plus layout files Plus layout. server. Ts and you can even make your own modules server only by adding that do server.js or. TS uh extension as well and as another option you can also throw it in Libs server and then it knows oh hey any anything imported from here uh is only allowed to run on the server so if you import it into some code that might end up in the client it'll again throw you a nice and layer so let's see what that looks like so we're back to our our characters you know our uh Bob's Burger characters here and if we go in here to the routes let's go into the character individual character and I am just going to add a log here so I'm just going to fetch this uh fetching character and I'm just going to put the pram IDs here and now if I go into an individual character you can see oh it's logging fetching character too you know or wherever Adam here fetching character 3 now I can change this to page. server. TS and that's usually pretty much all you have to do and now I'm G to hit refresh here go into these and you'll see it's not logging on the client anymore this load function isn't running in the browser but you can see it's running here on the server and it's that easy um some things will have changed for example uh let me just open this down this event is different on the server than it do is on the client so I'm just going to take this change this to event the structure event here and then we just W to do event well actually one sec let's go back to it being a client or Universal technically loader it's going to run on both the client and the server and I'm going to just do event Dot and I'm going to hit the little autocomplete thing here oops that's not the autocomplete thing that's not the autocomplete thing there we go there so on this event we have you know these are not right at all so typescript is not running right now if I hover over this you can see it's not running but if I sometimes what you need to do is you need to restart the language server and then restart typescript it gets a little confused um uh and now let's see there we go so now you can see this is is a load event and on our load event we've got data depends fetch prams URL stuff you're familiar with here maybe you're not but we'll get into more of that later but now if I change this to the server we're going to have different ones server. TS oops now we might have to do this again depending on if typescript picks up on this so if we hover over here okay so this worked okay so this is now a server load event which is different than just a regular load event uh we can close this little guy and now if I do the same thing event Dot and I hit the little autocompleter oh we've got new things we've got cookies we've got get client address we've got locals platform so just to go through these quickly cookies is sort of an API that allows you to set and read cookies uh fetch is the the fetch that we're used to but it's on the server get client address and platform are sort of uh they are adapter specific they're going to give you uh results that'll be available on your platform whatever you're deploying to locals is kind of a catchall you can sort of use this to put things on that can be sort of persisted AC crossload functions and requests um but yeah the point here is and we have the request object actually so this is uh the request object there's nothing uh SP Kitty about it spel Kitty about it that's kind of a funny way to say that um it's just a standard request object that you could even like look up on MDM here um oh that's the response option but same idea [Music] so yeah that's changing it to the server and I'll just get rid of that console log so it doesn't bother us but you can also do this you can see that everything continues to work um whatever you return from a server load needs to be serializable but it's serializable using uh a library called what is it called again serializable using a library called devalue and that allows you to automatically serialize things like dates and Maps uh and sets so serializable but you know so don't use your own classes and everything but there's a there's a little bit of leeway in there we can also do this to the layout which we can we can just do this right here so if I rename this layout. server. TS oh you can sort of see here typescripts mad again but I think if we just kill that without saving and then maybe we need to do the old reset restart types script restart language server sometimes it gets a little confused uh in this case one thing that might help is killing the dev server and just starting it up again too that will sometimes help and then that often in combination with what I just did which is kind of resetting the restarting the typescript [Music] server I think that's probably it no the language server go was that file oh did I have the old file open still unhappy about this okay what is the problem so it's not typescript is not picking up on the spelt kit types for some reason um I think if I just do command P or command shift p restart language server first then immediately do a quick restart of the type server typescript server that worked it looked like okay so now we can see here this is now a layout server load event uh and uh yeah so we'll have access to those uh request and cookies and whatever in these this as well and you can see here everything continues to work um so whether it's Universal or whether it's server um it still kind of manages to do okay so let's talk about environment variables because most apis are going to require you to have like an access token or a secret key to use their apis and you need to keep that secret not in your source code usually so you're going to have to add it by some sort of configuration uh so environment variables are basically defined by the platform you're running on it'd be like process.env and node but because spel kit sort of abstracts the idea of where you're going to deploy to you don't actually know what environment you're going to deploy to so it abstracts over the environment variable so that you have a consistent way you can call for it regardless of where you're going to deploy and they're broken into public and private and static and dynamic so the idea of private is they can't be imported into client codes Fel will give you a little error if you try to do that and public is they always have to be um prefixed with a big Capital Public underscore um that's actually configurable you could change that if you wanted a different prefix but it needs to be prefixed this way so that you're very explicit about which ones you want to allow out in you know visible code like client code and which ones need to actually stay secret so the private ones obviously are the secret ones and then there's static versus Dynamic static environment variables which are actually coming from from V they're only available at build time and what it's basically doing is replacing in the code where you're accessing that variable with like a string or the value um so you can use that to do like dead code elimination like if you were to have oh this code should only run in dev then you could like set that up where it's looking at the dev environment and then oh this will be replaced with just false and you can dead code eliminate it because it'll that code can never get run uh so you provide these by and then Dynamic variables sorry uh are available at run time they're usually provided by the platform you're running on and this would be like process. EMV and these are provided to your Dev environment by the EnV file you can put a EnV or a env. loal uh in the root of your project and then spel knows to grab from there it's technically V I think again but it knows to grab from there and put those into your code and Fel it has this dollar sign EnV library that you can use to access those and this is how that would kind of look so the dollar sign EnV static private these are for your private variables and this is going to do that code replacement uh you would import something like directly so import API key from dollar sign EnV static private um then there's the equivalent EnV static public uh which again has to have that public underscore prefix but you directly from there you would be static public and then you get into the dynamic ones these are more like uh you know kind of like the process EnV so you actually import EnV because there's the possibilities these were never set right so and you're you can't really know that these are going to be there so you import EnV and then you use it off ofv so it be EnV do whatever your Environ variable name is uh private ones obviously you'll get a little error again if you're trying to use these in client code and then the public ones uh again need to be prefixed with still with public uncore because you got to be explicit about it but they're these ones are actually kind of interesting because they're sort of provided to the client from the server so configs and stuff is a good idea for that so let's look at that so if we go back to our U Bob's burer API we can put at the root here a EnV file and I already have one it's just hidden I guess um oh it's hidden because it's not showing in the um it's not showing in the uh vs code here but if I do code. EnV we can open that up and here we go all right so I've already prepared myself here so this could be used for generally you want to use this for secrets and keys like I said um config would be more public stuff probably um so in this case I'm just going to pretend this is a secret API like it's not it's not really but just pretend this was a key or something so I want to import Bob's burer apis and use it uh in my code so if I go into the um loaders here let's go to the layout loader I would just import so if this is a secret it's going to be private import Bob's Burgers API was that is that what I called it Y and so this would be from and now you do the dollar sign EnV slash and then this would be whether it's um dynamic or static so in this case we'll do static we're going to replace the code itself but it's still going to run the server so we're going to go private and now I can do something like we can configure which API this uses so the API is going to come from this environment variable and then in our code here we're just going to replace where this is and now oh we don't have to use this felt. fun in fact uh we don't need this felt. fun Library we could just use the API here and as long as it has a slash characters that Returns the right thing everything will continue to work and you can move that around configuration and you can see here this is still working we still get all the files here um so that's kind of just how you would use it and then the various different ways you import it uh as I explained in the slides so cookies and headers so a server load like a load function exported from a do server file you know page. server layout. server or actions which we can get into later um get this cookies helper p as a property of the event you know and it on this cookies they have sort of a way to handle setting and reading and cookies uh from the browser and so you can use cookies doget uh cookies. set cookies. delete cookies. serialize and these are all from a library just called cookie um and so it's an mpm package you can look it up you can read the docs there uh one thing to be aware of though is you're almost always going to want to use the p option in cookies so there's options you pass the sort of the second values you're almost always going to want to set that to the root I mean you know what you're doing with cookies so maybe you want to set it elsewhere um but it's a good idea to set that also um just by default spel kit has HTTP only and secure default by true when you're building so for production but in Dev uh it's off so just so you can read things uh in dep another thing you get on that event in the load functions on the server is headers and so with headers you get a set headers function um which is passed as a property on the event that's passed to load and this is useful if you wanted to do like uh page caching some sort of caching header uh maybe for authentication if you want to send you know a bearer header off when you're uh setting when you're return returning something um Fon has a different way to set content security policy that's done in its config but you could override it with set headers if you needed to on various points uh you can also do cores that's a pretty common use for set headers uh so that you can set up like an API to respond to cores and uh set headers you can actually use on both the server and the universal loaders but when called on the client it just does nothing it just is like a noop so just a tool in your toolbox to know that that it's there cookies and headers oh right all those things I just said so the server fetch the fetch function that's provided as you know a property on that load event uh and in actions as well is a special fetch as we mentioned before so the fetch provided to server load uh sends cookie and authorization headers along so if you make a fetch it'll uh from your load like we are in the example um it'll actually send along the cookie and authentication headers from there so this makes it really easy to proxy something so if you want to have you know they request your domain API but you proxy that to somewhere else you know you've got your other business apis that are uh not necessarily just for your front end um that's a really great way for doing that just a little convenient method you you could do it without that code but like you could with your own fetch it also makes fetch available on the server which sometimes it's not you don't have to pull in anything it's already pulled in for you and so it's usually a good idea to use the fetch but another thing it does is it can make relative requests so normally with fetch you have to have a fully qualified URL um but you can do like dot do slash um which I think I even have written down here if I if I actually clicked on my slides um so you can do relative request like dot do slash kind of thing to go up one level and another thing that maybe we'll have to get into after this is if you use your the fetch provided by that and you call an API endpoint that you've created in spel kit it'll avoid that whole you know oh let's make an HTTP request and get it back and just call the API endpoint code directly and so it's like a a performance benefit if you're call if you've created an API endpoints uh in spelit and then you're calling them from your load functions it just like does the most efficient thing and just calls that function directly so that's a very cool addition so API endpoints what do we mean by that well um so you remember those special route files well now we know enough to talk about the last one which is Plus server. Ts so as well as Pages you can Define API and point routes with the Plus server. Ts file so in that file uh you can export named functions that correspond to the HTTP verb so get post patch put and delete uh these request handlers receive a request just like the load function and or load functions that you were defining before and should return a response object though not just an object like the other ones a response object what do I mean by a response object well this is like a standard you can look this up on MDM this is a response object it's available globally and it's kind of like an industry standard as well as a actual standard and so that's follow cell Kit's philosophy of like oh yeah we stick to the platform uh you know use the web stuff but we just enhance it make it it a little better make it a little easier and smooth over the edges so response objects you can pass a string uh you can pass uh there's a Json helper that spelit provides so if you're doing Json responses for your apis just making that a little easier and you can also even respond with readable streams uh if you have like large amounts of data or you want to do server sent events or something that being said you should know um some platforms like AWS Lambda buffer the responses so you wouldn't be able to if you're deploying to Lambda you wouldn't be able to stream your responses that's that's just a limitation of the platform that's not really to do with spell kid but just so you're aware and there's probably others that have limitations know your limitations so the same route can be either a page or an API endpoint because you could put a Plus server. Ts file in with a plus page. spelt and whatever so to determine which one like the API or the page that spell kit returns uh there are some rules and basically those rules are if it's a put patch or delete request is always handled by the API endpoint the server.js because the browser doesn't actually do those ones uh normally you have to write JavaScript to actually make those requests or you know use some some other tool but if it's a get or a post then what it looks at is the accept header so if the accept header has text/html that type in uh priority position so either at the front the only one uh then it will serve the page otherwise it'll go to the API endpoint response does that make sense hopefully so let's see what making an API endpoint is like uh so we're back to our bobsburger characters here um and what we're going to do is replace the fetch to spelt that fund with this fetch to our app you know Local Host in this case but wherever we were to deploy do the same domain thing uh so now you can put these server files anywhere in the routes right like you can put it in characters you could put it in whatever it's got to be under routes obviously but um but just to be familiar let's put it in an API directory so it's SL API slash whatever um just because it's familiar it's how some other Frameworks do it uh but you wouldn't have to you can you can put these anywhere you want uh let's do character and then in character we will make Plus server. Ts so in this server. TS file we're going to export a function called get so matching up with the HTTP we're going to make a get request uh it can be an async function uh it does not have this request response though actually this is the event just like in the load function and then we return a response uh so the response object uh is Constructor it's class so return and you can provide this argument um as a string you can do Json let's do hello world and just make sure this is working so if we whoops go to Local Host 5173 API SL want do characters got nothing so I did it wrong whoops uh character I named it character but it actually should be characters so let's actually rename the um file because I actually want this to match the way we have it already in the load characters and now yes now we get hello world okay well we don't want to hit hell world uh what we actually want to do is fetch just you know we're going to have our API proxy that request over to the sp. fun API so let's go into where layout is fetching that and steal some stuff from here so we want this and whoops want both of these and we want the actual fetch should give us a response so can we just return this response I actually am not sure let's see if we can do that so if we just return the response we've awaited fetch so we get a response object back and then we throw that response object in the let's find out if I hit go here oh it's cashed so you have to watch your cash on these things um uh sometimes it's it's a lot more cashier than you might expect oh maybe this isn't cach maybe this is doing some sort of loop because it's kind of stuck decoding fail okay so you can't can't you can't send the response object directly I guess uh one thing you could do is new response and it would be response. body because that is actually a rable stream will this work now yes there it is there's our response proxied through our own API so on that note uh we're not really using the event here but just to show you this event you know it's just like the one from load it's got fetch it's got locals it's got all the things you need platform URL cookies if you need cookies but we don't need it for anything right now so now we can take we can clean this up right we don't need this response we don't need this response and from here we're just going to fetch like from SL API characters and now if you recall what I was saying during the slides is so because we're using the fetch provided by the load function this isn't actually going to make that HTTP request this is going to find the code from server. TS call that directly this get function and get the response out so yeah efficiency for the win um and this should all just work uh if I get rid of that equal sign at least this should all just work and there we go so this is our characters now I'm just going to hit refresh to make sure it's not just cached and yeah that is working now let's do the same for the um ID function so or the individual details so like you know Doty manous page here so just like every other routing it follows all the same routing rules there's no difference here it's just the plus server thing so we just do the same thing we basically make a you know dynamic parameter route here ID and inside here we put a plus server. TS and in our ID one we we well we basically do the same thing copy all that code except that on this case we add slash and we want to do the pams here so we are going to need the event we're going to need the pams off this event and we do pams doid and typescript is there to help us already just so you can see the whole page there and so now with that we have our API end points they working so now we can on this one whoops we can now get rid of this load complexity so again we just make the fetch directly to our API SL API so our root API characters and then the param ID because our that's the same thing essentially we're pulling the pram and just passing it down um yeah I don't think I need to change a thing here other than that that looks great yep so let's see if that works huzzah and just to make sure that we're making a request from the right place let's look at the network Tab and if I well I guess we won't be able to see that request because it's on the server so never mind that is how you create these API end points characters and we could do you know here character slash uh two and we can see we get the mle's full response proing for the win so let's talk about hooks so if you're familiar with react hooks this is absolutely nothing like those um so hooks are an app wide function that can be used to modify the behavior of the app like you can hook into certain parts and do different things and there's two types of hooks in spell kit there are server hooks which you can Define at source hooks. server. Ts that file you put all your hooks in there and client hooks which you define at source hooks. client. TS so just those two files put all your hooks in there so what do we have for Server hooks well the first hook we can talk about is the handle so the handle function if you export this from your hooks your server hooks file uh will every time you hook your server your selected server receives a request whether that's an API request or a load function uh during pre-rendering uh you can hook into that and and change the response or something uh you return the result of you you're going to get the event you know the event that has prams and URL and everything on it you're going to get the event and a result resolve function and you are going to return the result of calling resolve on the event so you can do something in between there you can change the event you can do something async but you're going to return the result of resolve and the default if you just were to not even Define this is it just calls resolve and Returns the result immediately um if you request static assets like something in the static folder these don't go through this they they don't get hit by the hooks they don't trigger these hooks because they're just like oh that file exists I'll send that down so this is just for like I said when the API gets it or the load function essentially on the server because these are server hooks uh this would be a great place to maybe deal with uh off or maybe you want to set up some sort of caching or proxying this depending on what you want to do now you do have to Define one handle and like export one but if you wanted to do multiple handle functions uh spelit offers this uh res sequence function sorry the sequence function which allows you to basically Define multiple handles and then it just pipes it's like a pipe function pipes the events through when you call resolve and you pass it the event there's actually a second argument it takes to it's the options argument now I'm going to tell you about these but I'm not really going to do anything with them I'm just showing you so you know they exist uh so here are the options I'm not going to get deep into this but there's uh one function is you can pass as transform page chunk so this is basically you're going to get stream of chunks uh of HTML from the page response and you can do something with it you can you know string replace on it uh like in this example uh or do something else if done is false there's more trunks to come when done is true it's the end of the iteration essentially and so that's the last chunk you can clean up whatever you're doing or close off your tag or whatever I don't know what you're doing but it's essentially like a stream Transformer chunks uh then there is filter serialized response header so this determines which headers would be included in these serialized responses when a load function loads a resource with fetch so by default none of these are included so this would be opting into having those headers uh in the response and then there's preload which basically just determines what files get added to the Head tag to preload it and you can sort of set you know oh maybe you want I don't know maybe you want to mess with the the preloading this would be where you can do that so another hook you get is handle fetch so this allows you to modify or replace any fetch requests that happen inside a load function or an action which we haven't talked about yet um any of those that run on the server at least so in this you get the in in this function you're defining handle fetch that you're exporting uh you get a fetch the fetch I guess and the request so you could do something you could do something a sync uh you just need to return a response essentially you can modify the request uh so yeah you could conditionally proxy um yeah I'm not sure what you're going to do with these hooks but these hooks exist for you to do something with so another uh hook you get on the server is handle error so this is called whenever an unexpected error is thrown during loading or rendering uh and you could use this to return a custom uh oops went too far you can return this to return a custom error maybe one that removes all the sensitive details or the stack Trace actually you don't want to show that to the user uh whatever you return from this function ends up as the result like the value of page. error in the page store so and that of course you use in the custom error pages so this is how you can modify that you might even use this just for logging errors um because you are going to get all unexpected error so maybe you want to this is the last spot hey something happened we throw that off to the logger or error thing that we have so the client hooks uh sort to spoil the surprise earlier but there's only one and it's handle eror and it's pretty much exactly like the handle error from the server except it's on the client so and it's called whenever an unexpected error happens during loading or rendering on the client again you could use this to clean up the error before showing it to the user or you know remove any sensitive details and you could lose it for logging or something as well so let's just take a quick look at hooks so we're back to our characters thing again we're going to add uh a hooks file here so it's just Source hooks. server. TS and in this hooks file we'll just do we'll export a handle so this is the one that uh anytime a request comes into the server uh you can do something with it so oops got to actually Define it right and this can be async as well uh so you can do something async and we are going to get in here we get the event um that has pram and whatever on it uh we get uh what do we get we get the resolve do we get anything else think we just get the event resolve so what you'd want to do you know if you weren't doing anything you just do resolve event but obviously we want to do something so maybe we would do something like this we would say okay let's let's get the cookies yeah let's get the cookies well let's let's get the session we'll say off the cookie so we'll say session equals and then we would do event. cookie cookie and then we want to say get and I think we just pass a string to event. cookie or it's cookies yeah it is cookies and then so whatever we pulled off that maybe we would say uh you know we'd have a function that's something like uh await get user info and we'll just pass it the session so let's just Define this um this might be something you know more interesting than what I'm going to write here but uh let's just make it an async thing that returns we we're going to keep this really simple it's going to return an object that has a name that is equal to the value in session which is not you know this isn't real but I'm just saying you could be going this could be going to a database or something and like pulling out the user info based on the session token or something but I'm going to just do it this way so it's easy and then we can just to say oh this is the user um and now we could throw the user on event. locals there we go so event. locals user equals user we got no typescript happening here let's just restart typescript server hopefully something will come up here all right well right doesn't like that it's like okay that's got to be a string that makes sense it's like hey is this a string it might be empty right yeah it's string or undefined so I guess we could say string it's not and the name could be undefined too um or we could just not do this at all actually this is probably better we always want to have the uh we'll only do this if there is a session yeah then we'll get the user up and throw on the event yeah that's better so now now let's do something with so now event. locals has a user on it presumably if there was a session and so we can let's add just just to this main page here let's add uh a server load whoops in the route though uh new file uh plus uh page. server oops TTS and in here we'll just do a really quick load function and all it's going to do is we're going to pull off that locals whoops from the event and we'll return well it'll be an object right with uh a name so we'll return user equals locals. user here we go and I feel like now in the page. spelt here we can just do so we just have data here exp let data and now we should have possibly uh a name here and so I guess what we could do is let's move this up here let's get spell kit traines and then instead of saying that if there is a session then we know that there's a name so we'll say uh data dot user and then optionally name but if that doesn't exist subjects right so now hit refresh it still says trainees let's pull this over so now I want to well not inspect but I want to go and add a cookie so if I'm just here and I add a cookie called session except I spell it right and then I'll just give it the value Adam that's me uh now if I hit refresh if I'm not mistaken hello Adam woot woot so again you wouldn't put Adam in here you wouldn't put the name this would be like a you know JWT token or something um and you know you wouldn't uh just do sort of the simplistic simplistic thing I would do You' probably want to get that from some sort of uh you know database or uh user service of some sort but this is basically the idea you pull the session off the cookie you get the user information from the session and throw that on event. locals which is basically a little catch all uh for just handling that kind of thing so yeah hooks so that's the end of the module uh server size felt so what did we learn here we talked about uh page server. TS and layout. server .ts uh Plus server. Ts for API endpoints uh we talked about how to limit certain libraries to server only talked about environment variables cookies and headers and of course felt good hooks so now it's time for the exercise so now for the exercise we're all learned up on our server only so let's change our blog to pull our data from a CMS like a pretend CMS uh this could be something like you know in real life you would pull something from be contentful or sanity and usually from cms's you need to have a secret key or multiple things uh accounts and keys that you want to keep secret and sort of add to maybe the authentication header or some sort of special header or just to the request every time you make a request um so we're going to fake that essentially so we will need in our uh blog we're going to replace that library that we used with that kind of have the data just in Json with actually fetching from a server we're going to use the URL sp. fundi poost but that will require a special author author authentic a special authorization header um and the authorization header has the value of spelt is fun Spore isore fun sorry don't forget the underscores so we want to keep that secret so make sure not to include it anywhere in the code except for you could possibly use your environment variables um and while doing that let's make sure that we don't accidentally leak it to the client as well so don't add it to the front end code you can use a Blog that you you know created for the earlier exercise or if you need to you can check out exercise 4 uh Branch from the repo and uh you should probably start by creating a EnV file in the root of your project and add this like secret posts token Spore isore for fun all right good luck give yourself about 20 minutes did you pause the video pause the video first okay so you're back you're back to see how I'm doing it all right this is how I'm doing it uh so yeah let's try out so the first thing like I said let's add a EnV file to our root um and in ourv file we want to have our sorry secret post token and it has a value of spelt underscore isore fun so we're going to need that secret token in the future no co-pilot I don't want whatever that is so now we need to change uh from using that weird library that we provided to actually fetching the data fetching the blog data so just get rid of that guy what have we got going on here so we're in our blog because we don't really care about the portfolio that's just the way it is still and oh here okay so here we go we're loading our post summaries here and then in the slug Dynamic slug segment we are loading the details for the individual blog posts so let's change these into server only because we don't want to serve to the client these are Universal loaders right now uh just to try and avoid that problem with the types I'm going to create a new file plus page do server. TS and we'll just take away the old one um and let's do that over here too sorry so let's start with the full list Plus page. server. Ts so we can sort of copy what we were doing before I'll just paste that in there but let's get rid of this because we don't need this anymore we're not going to actually fetch from there we need our fetch from here let's make sure the types are right yeah types are good here so now we want to fetch from so we'll do cons response equals oops const response f and we're doing https sp. fun slost API API posts sorry perfect oh internal error but let's not worry about that for now um we have this going on could ignore this stuff in fact let's get rid of all this for a second so after our response we still want to do that thing where we check did this response come back successfully and if it didn't so we want to say if the response is not okay then we want to throw an error so we need to get that error from spell kit so let's import error from spell kit nice try co-pilot but not quite there spelt Js SL kit and error takes two parameters so the status so we'll just do the response status and uh we won't do this load because right now this actually isn't this is a promise of a response so we need to await this and to await this we need to make this an async function so uh await and now we've got response status and we'll do response uh status text so that's if it's not okay and then if it is okay we get our posts out uh so now this is going to be untyped so if we send this up to our um our page it's actually going to be a problem now we see here 403 Forbidden and that is because what have we forgotten we forgot that this requires a secret so our request to spelt that fun is failing with a 403 Forbidden so we need to add our authorization here so our uh way we do that with fetch is in the options object here uh you can also pass fetch request but this is just easier for now so we want authorization it's got a capital in case that's uh what you need and now we want to get our environment variable so how do we do that again we import it I guess we want this out this import and now this is uh well let's get the import up first your secret posts token and now it's dollar sign EnV but we got to think about this so now do we want static or dynamic private well we definitely want private we don't want public um because we want it to be uh kept a secret we don't want to have it included in our code uh so we definitely want it private because we want only on the on the server code at least but I think we can do static because the code won't be downloadable anywhere this is just how the server is going to run that you know so we can do static private oops little emoji fun there and so now now if we just take this and return that so that's going to be spiled is fun it's working already well look at that so now instead of getting it from that library that we had we're getting it from there now let's just make sure that this isn't just working because there's no errors and actually delete this page. TS let's move that to the trash Oh error for a second but now it's back so it seems to be working oh post not found okay so we probably have different tokens from the server than we do from our library so let's fix our uh other one our individual so again we can open up the old ones so to see what we got make some changes so we still want to do basically most of this we just don't want to use this Library so let's get rid of the library and we still want to import secret posts token not li. in dollar sign in static and private and then from here we want to well we'll probably have to do this in two steps we want to uh get the response and we may even want to put this into a config but I won't that for right now um and then we still need to do the authorization header here yeah I don't know why I put that in a string before we don't need to put that in a string um and then let's do our song and dance of waiting for the in well let's just copy and paste it from the other one is the response okay if not throw a thing uh put that in there and uh oh we need to await the fetch of course and now looks pretty good we can get rid of this so now our post instead of relying on this get post by slug oh right we have to actually add the slug um so the slug here will be added here like this turn this into a template string and we know this API responds in the same way because I wrote it and now looking it over it looks okay let's delete the regular page one and see if we are all server sided up I'm just going to hit refresh to make sure click on here and there we go still working and now we're pulling in the content on demand from a CMS and we've got our little use of our secret token so everything's nice and secret and because that's in ourv file we're not even going to store that on the server that's just going to stay uh you know locally for us and then of course wherever we deploy we would have to um add it to the environment variables somehow whether that's through a command line or through the environment you know if you're on say versel there's a place you can just add uh environment F wheels so yeah hopefully your solution came close to mine and uh oh yeah even just as a little last halalu we don't need this lib anymore so we can just delete it you're trashed huzzah see you in the next module this is probably my favorite thing about spelit forms so the thing I like best is how spelit once again tries not to do too much and relies on how web forms already work and then just enhances it makes it easier it uses standards like form data and request response and it even actions except like xww form URL encoded data not Json because that's how forms work on the web already and that means it works without JavaScript which is pretty incredible but it also gives you a way to easily enhance it with JavaScript so when javascript's available it overcomes some of the weaknesses you can have if you have your forms not using JavaScript and everyone's like oh what's a big deal nobody turns off JavaScript right but there actually been a lot of study on this and sometimes JavaScript just doesn't work uh it's can be incompatible versions browser extensions break JavaScript sometimes firewalls can block it sometimes it just fails to download and another thing uh unlike react Frameworks you probably don't even need a form Library like as long as it works with HTML forms and maybe even you have to use a hidden input or something your fancy widget will probably just work so that's incredible so State full workflows also become a lot easier when you sort of take that server side server first approach but that's maybe a bit of a degression let's see how you can use forms in spel kit so what we got here is a little movie log um it's essentially just a little app for yourself to log the movies rate them and maybe leave comments how you like them so let's open our page. spelt and our page. server to see kind of what's going on in here and you can see our page. server is very simple right now we Define a movie type we're putting an array just an inmemory array here and a load function that returns that array so this is just hardcoded I don't really have a database I'm not going to set one up um you could do that of course but this is just to demonstrate forms not really like hooking this up to real data so this will work and as long you know whenever the server Dev server restarts this movies is going to be reset that's fine um you can even hit refresh though because it'll be on the server um yeah so then what does our page look like it's just a table right now uh just what you see so let's add a form to log movies so I have one already um that I'm just going to copy and paste and then we can walk through it so it's just a regular form no component needed no spelt do colon form or anything and then the method is post because you know we're dealing with server data you always want to sort of post the the data back uh we've got a label here uh sorry we've got a input here with label wrapped around it uh for name we've got one for release date uh it just says release but release date um I can even put that here we've got a rating from one to five just is just a drop down with like stars uh and then comments you know you can add whatever comments you want uh for the movie and of course this will do nothing because hey we don't know have anything set up yet so let's figure out how to do that so spell kit allows every like Plus page. server. Ts to export an actions object and this will be an object and on it you'll sort of do the methods which are the actions that you can take um there's a default one so you can just name your action default and then it'll be the one export oops I need cons uh it'll be the the action that happens when you sort of like submit your form to this page and we can show you the other actions after that so here you're going to get the event um just like you know I this event you've seen before cookies fetch locals platform um and from there we can get the request so this is the request when the form is submitted to the page and you that's just kind of how forms normally work whoops got to destructure that though and so from that we can get form data and that is uh basically requesting uh form data is right off the request it's form data but it's a method so there's it's a method because it's lazy and it returns a promise actually so we're going to have to async this so let's make this an async function and actions can be async and we're going to await this form form data because long story short this is just how the web works this isn't anything felt Kitty but if you uh access the form data then it actually like oh does the it lazily doesn't do a lot of stuff especially with files that it would do as soon as you request form data uh you can read about that on mdn though because that doesn't have anything to do with spell kit that's just the web so from here though oh I'm just going to log it to show you what you get oops console log form data so if I open up the console here and now um I'm just going to put some stuff in my form here so Shrek 2001 of course it's five stars and it was very funny I'm going to hit log and let's see what we get in the log the movie and we'll see what we get in the console log so we got a form data instance and then it has uh under State here name release you know basically the values that we've submitted so that's pretty cool um this form data object is kind of a special object it's not it's sort of a map you actually can sort of call entries on it um but it's got sort of a special API so what we're going to do is we are going to try and get the data out of it now one way we could do that uh we could say you know this is our movie data we could do object dot entry or from entries and then form data entries and this actually works um this will give us mostly what we want but it's going to not be great for typescript I'm just going to console log this so if I were to sort of submit that same you know Shrek 2001 festar five funny um you'll see oh hey now it's a regular object with just these strings basically but these aren't really strings you can sort of see they form data entry values which could also be files and could also be undefined and so it's kind of like oh typescript isn't sure what you're going to get so the easier way to just sort of deal with typescript here is we're going to pull the values off individually so we're going to say and if we look at our type here movie is name release num rating number comment optional so let's make movie data well we'll keep the one we already have I guess and we're just going to make this into an object and we're going to pull off the individuals now we don't have ID because this is sort of creating a new one so we'll start with names so name we can do form data. getet and then the string of the of the key you want to pull off that get name now this is still a form data entry value or null so we're going to be like well we know that it's uh it's a string so we're just going to cast it as a string except that if it's null we kind of want it to be a empty string I think that's probably right so we'll go we sort of do the uh nullish coalescing and then we'll just say as string so I think that will work for what we want so now movie data oh still thinks it's a form right because this as string needs to go need to actually say wrap this value and now we can look over movie data and we know that it's going to be a string all right so then let's do that for release but now release of course is a number not a string so we're going to have to do something similar so we're going to get the form data out we're going to call um well if it is not null that then we're going to do number on it we'll just convert it to a number in the simplest way possible and this will be release and yeah we will do the same for um rating and now um comment is actually kind of an interesting one because it's not it's not it's optional we don't need to have a comment on here so we could do it as a string like co-pilot wants to do it but I think we should go uh get it and only to string it if it actually is a value so we'll say if it's not no and it's not an empty string I guess uh then we'll do the same thing for uh not name though these are all oh I forgot to change this release and rating and rating change them in one place not in the other and comment and so if it's there we'll do that again as the result as string otherwise we will do just undefined I guess sure okay so now we might have to come back to that one later so now with our movie data we want to validate it we basically want to show like oh hey we need a name we need the release State and we want to show little errors if they don't so in our HTML we've got a little place to sort of say errors we just have to have it come in as a value so well I'll show you that in a bit so first off let's make a Val let's make a validate movie so and we'll take the movie data from that const validate movie and this will take well we know this it's kind of a movie it's not fully a movie so we could do something like a partial movie yeah so we'll just we'll say uh movie data because it's not really a movie and we'll just say this is a type of partial movie and now what are we going to return here rather than just like true or false like is this true a good thing we could do is you know this is where you would want to use a library like Zod that like parses it and like gives you you know you know that your types is or else it throws an airor um this would be a good place for that let's make like a little not our little own homegrown version of Zod because it's going to be very specific to just this movie we don't need to create a schema or anything and so we'll return an object that is either like success true or false let's do first uh and false will have an error which would just be a string and or it'll be an object that success is true and the movie will be a movie but it won't actually be a movie will it right because it won't have an ID yet so we'll do we'll use typescript again and we'll just say it'll be everything that a movie should have except not the ID we use emit to do that just need to fix that and close off the object think I have an extra oops it's all going okay close my object that is my return I've got an extra one of these and an extra one of these all right patial partial whoops okay so now we just need to implement this that's what they are is saying right now so first thing uh we just want to make sure that these movies are valid movies so we'll say um you know we're getting in the right kind of movie data we'll say if there's no movie name we'll just say name is required uh that's probably a good way and then we'll do something well okay yeah we want success Falls name is name of the movie is required sure [Music] and oh this just really did everything for us well all right co-pilot go go co-pilot go that looks pretty good and then of course if everything is successful we return successful true and we throw these on like that great okay well let's validate that movie and Y to copilot so we'll just do yeah con validation equals validate movie so take takes in the movie data and now this should be either success or false so oh I see I've got something wrong in the uh the old template there get out of there um uh and so basically if we want to say something like if the well if the validation is not successful then we don't actually want to return this this is not what we want to do we want to um we have to get a fail function so spelt kit has a fail helper specifically for this kind of validation so this isn't an error it's like oh hey your validation failed and so we're going to import fail from uh at spel js. kit sorry not done and so we can sort of look at fail fail takes a um number of the status status number and then the data uh which I'll show you what we do with the data so if the validation is not successful we're going to return fail and then we need a status code so the failure code is usually 400 for forms uh it's like bad request uh and then we want to have some data so we will put the validation error right there CU we know that if this has uh success false then we know it has an error property and then we're just going to need a little bit more we're gonna have to spread the movie data we might even need to I might have to think about that one okay and if it is success ful well let's just return this sort of will end up being the response of the of the uh the form data essentially so I I don't think we need to do anything interesting here we'll just say yeah that was successfully created um but I don't think we'll need to send the movie data so now how do we use this data okay so the validation has failed um I'll even take this away for now so we can sort of see how this is going to go so in our spelt kit uh template sorry in our page template here we've got the data this is where our movies are coming from and now there is another prop we can actually get and that is form now form is kind of a a ethereal almost it only exists when it exists and if you like change Pages it'll change too but you can also find this on the page store just like you can data so it's there it exists and it might change based on you know if it had an error in it for example and you move Pages you wouldn't want the error to be there when you came back so it's it goes away when when things change but on this form object this is our action data um we can basically pull off the error so let's put that right here I believe we called it form dot no was it error I guess we did call it error and just in case form doesn't exist we've got the little whatever helper here and now let's just see how that works form error is undefined okay that's because we are always no it's just because I got to hit refresh that's all right so we basically I uh we only want to show this error if there actually is an error so we would do something like form error you know or an empty string there we go so now if I hit log the movie and I haven't entered anything it should say name of the movie is required great I'll say fight clip then I hit oh release date is required but look name went away and that's not right right we want the data to stay there and that's kind of what I was doing with the spread that I took away there by adding the movie data here here now that data should be available in the form object so oh okay now that we've got that we can sort of populate the data here with this form data so this would be form. name and uh again we'd have to sort of say oh is this is this valid and also uh release. let's do the value is uh form. relase and for our rating here we can actually because spel kit Let's us use the value here on the select we can just do value here um I guess that's actually just a web thing too now that I think about that and this is the rating and our text area here we can use the value on the text area as well just like the others. comment and now you can see oh but they show up with undefined by default that's not right and that's because undefined doesn't uh when you convert undefined to a string it goes to a the word undefine so we just need to do the old nullish coalescing to an empty string and we'll just do that at all these spots um so Nish coales to an empty string I did that already and that's the error sorry I need to do it on the rating and on the release and did I do that here I did that in there great still have undefined up top maybe I just need to hit refresh nope oh yeah seems I missed it okay so now log the movie name of the movie is required okay Shrek now I log the movie hey Shrek stays around so now I can say oh what the release date of Shrek 2001 hit log the movie oh rating is required five stars now comment isn't required so this should actually just success and because I returned success the form date is gone there's uh I only put success in there all the data resets back to its original form probably what we want so now we just need to actually handle success so right before returning the success we will just say um movies push and now here's the interesting thing we can't just push on this movie data can we because it doesn't have an ID property ID is missing in time so this is an easy enough fix we know that this was validated this is our creation method so I think we can just do something something like um you know we'll spread the movie data first and then we'll add an ID ID can be if we use the global crypto you can just add a random uu ID to it and now this should work um and I'll do this just to show you fight club 1999 four stars awesome log it and there it is now how did that appear right hey we didn't we didn't program anything for that we didn't write any JavaScript to like move that into there so what's happening is after the form requests that basically invalidates the load functions and so our load function here is recalled because oh hey it's invalidated we need to reload that and then because now the uh after the uh successful push now the data is in there so we didn't have to handle any of that on the client side that's all server side and it all continues to work so now that we can add movies it sure would be nice if we could delete them so let's add Shrek 2001 uh five stars funny I'm just going to keep saying the same comments um so how we're going to delete the these well that'll give us a reason to talk about uh some of the other features so let's get into here we're just going to add a column here th we're going to give it a class of action Yes except I'm G to have it be empty and it'll be action and then I'm going to add another one of these and in this we'll call this we'll give this a class of action and in here we will add a button and we will just say delete with our button and I'm going to give this the name so with forms it'll be like oh hey how do how do we get the the data out of a button well you can just give it a name and a value and then that'll actually be the same so it'll work just like uh checkboxes and inputs so in this I'm going to say this is the movie to delete and if we just hit save we can see okay we got our delete button and I've styled that already and then we need a value as well here so the value is going to be let's just go with a movie ID and now this won't do anything of course because it's not hooked up to do anything but what we need to do is turn this button into a separate form because the form is over there yeah okay so then we'll just do a separate form here uh so form the method will be post of course and the action now we're going to name our action uh def delete movie so action and so this is sort of a spel kit thing now so your actions basically say like where am I going to post this form to and you can put URLs or whatever but our spel kit addition here now to make these kind of little things easier is you get to put a question mark and then like the root slash kind of thing and then the name of Your Action so in this case it's delete movie and now this form and I need to change this to type submit and now this form this little form and there's basically a little form here little form here little form here uh we actually try and delete now I think if I hit it's going to error if I hit right now boom threw an error so what's this error say no action called delete movie that makes sense we didn't implement it yet so where we've got our def default action in our actions let's make a delete movie so delete movie and you may have already guessed this but in our delete movie we will um pull off the Pam or not pams yes we will pull off the requests sorry not the pams pams are you know if you were doing gets and stuff but request and then from the request we want to get the form data again so we'll say uh you know const uh how would we do it const uh movie ID equals request form data and now form data again is an asynchronous thing so we're going to have to await that so we're going to have to make delete movie doesn't like that delete movie and async function or method in this case we're going to await our form data and then we just need one property off it so I'm just going to wrap this in here and then say get and we want movie to delete because that's what we named that button essentially so the movie to delete and the value is going to be the movie ID so if I log this now console log movie ID we will see if this is working oh internal error okay and let's read the ER when using named actions the default action cannot be used right and there's reasons for that you can read the docs that they kind of address in that and so the way to fix that for us in this case is we are just going to rename our default action log movie and so if our default action named log movie we just need to change that in the actual form too so now the form posts needs an action it's no longer the default action and that will be question mark slog movie these are named actions great so now if I hit this we should see and there it is these are the IDS of the movies login and now it's as simple as kind of dealing with it the way we were before we can just say you know uh well actually did I make it a const I may have let's make movies a let so we can reassign it and then we'll do movies is equal to whatever movies currently is oops I missed my equal sign filtered and we're just going to say you know movie and wherever the movie ID is not equal to the movie ID keep it and where it is it'll remove it and I think that should work so let's see how that goes so we are on here we had [Music] Shrek funny and I'll even add Fight Club 1999 awesome and now I delete Shrek and it worked so now we've got this working fully um and we can even you know show this off let's inspect this and I am going to turn JavaScript off so disabling JavaScript hitting refresh and you'll see that this is still working let's add Shrek to 2001 five stars I won't even add a comment this time boom and oh comments undefined whoops got to fix that and I delete and it deletes and there we go and we still have our uh you know our validation working Fight Club here it'll say oh the release is required rating log the movie delete Fight Club delete Fight Club and delete Shashank Redemption so let me turn JavaScript back on before I forget and causes trouble [Music] later oh maybe it wasn't disabled before let's disable it now and show that it was still working Shrek oh I've already got a Shrek ah let me just save here and make it that all the movies go away okay there we go now I'll add Shrek 2001 five star rating funny yay and then I'll delete it still working with JavaScript disabled I think maybe I can't close that all right well there oh that so that can be a little bit of an issue uh sometimes you want to redirect after a form submission maybe after you've created something you want to go back to the details page and so to do that in spelt kit uh in a spel kit action is kind of the same as the load function where you can redirect as well um you basically import a redirect from spell kit so where we got fail here we'll get redirect and and you can sort of see this redirect function takes a status and then a new location to go to and so in this particular case well actually I feel like with JavaScript turned on this shouldn't do that but it did so I guess we can redirect back to our root here um so we'll say instead of returning this we'll return a redirect uh back to the root and our status will just be uh created what's created uh 301 is that right let's see oh internal error cannot return redirect you have to throw redirect okay there we go deleting and then our deletion action we can do the same thing uh that one I guess just uh 200 oh right after form validation so after form validation uh a redirect is usually uh a 303 is usually the way you want to do it um that's kind of the the status code for doing things like that okay looks like we got it working so now another thing you can do so we we've got this working and it's it's great and I and don't get me wrong I love it but something that they added to spell kit that just makes everything a little bit better is to overcome some of the problems that you have with like these form when they don't do any sort of uh JavaScript based handling uh like the way it loads the way it takes a little while the way it always has to refresh the whole page and you lose any state um they make that super easy to overcome and it's super easy because all you need to do is import a action so the action is called import enhance enhance from um just make sure it's spell kit yeah spell kit app. forms my mistake so it's actually from the special dollar sign app SL forms and then with enhance now now it's this enhanced function because it's sort of generator here is aware of like oh it's it knows what uh what to expect where to post and where to throw the thing I can just add this now to this form and so this is a spelt kit action uh not to be confused with the other kinds of actions so there's spelt action sorry and then there's form actions and those are different things it's action-packed they say in the uh documentation but these are spelt actions and so uh enhance and that's all you need to do and now your form will be enhanced with JavaScript and it won't run into any a lot of the little troubles you have before like losing State and now it sort of acts like an Spa oh but I didn't enhance the other form so we got to go do the delete form as well you can sort of see that flicker and jump when I when I did that so you can sort see here use enhance that one's enhanced as well now and now we can at Shrek funny add Fight Club oh right so I guess actually the default thing of enhance is to not clear it unless you return success so now our little uh redirects are the wrong thing to do whoops so I think if we take those out everything should be fine so let's just make sure that that's right there we go trk and then I'm going to delete yeah fight CL 2001 five stars awesome it was 99 99 and and delete so yeah that is how to do forms and form actions in spell kit so what did we learn there we learned about server actions uh we learned how you can use a default action if you post the page direct to it we learned how to use named actions uh we talked about how it uses form data which is just a standard in the web and we talked about how you have easy validation with that fail you can just like use the form data form prop on your page components and then how use enhance can sort of enhance it with JavaScript so now I'll see you in the exercise so for this challenge we are going to add a login form to your blog now you should use the the blog you've been building up all along or if you don't want to you can always just check out the repo and get the demo code for that uh so the challenge is we're going to create a login page with a username and password form and you're going to use some sort of form action to validate that on both the server and the client um you don't have to do any real authentication though like this is not about off just check a hardcoded username and password we're not we're learning about forms and server stuff we're not learning about oth right now so on a successful login the user should probably be redirected to the main page maybe um and once the user is logged in they should show somehow that they're logged in and you should have the ability to log out somehow so you might want to keep state in a cookie or something so take up to a half hour maybe even an hour for this one um use all the skills you've learned so far and uh good luck I'm now going to show you what I would do for the exercise so oops let's see here so we're going to start by adding I'm going to add a login link up here and maybe a login page so in our page layout which is that shared layout that we made earlier oops I'm just going to add another link here and we're going to call it login Lo Legion login login and uh going to go to a page that doesn't quite exist yet so on that note I'm going to make a route so this route will live in the blog because it the portfolio well we'll see how this works but the portfolio yeah I'm not sure not sure where the best place for this to be is I'm going to go with the blog so we'll make a login and it is going to need a page. spelt and a page. server. TS okay so our page. spelt here let's just go with H1 login and our server get rid of all that we're going to basically export uh actions so we're going to have a login action and we can just use oops const we can just use the default action I think on the login page and so that will be I'll make it a sync and well we'll get to this so we get the event here we probably want the request and from the request we're going TOS close that uh we need the form data well that's probably fair enough now let's make a form all right so back on the login page page here let's uh click here and there we go there's the login page let's do a form and we want a method of post and now we want a username and password where's my hey nice co-pilot I was about to say where's my co-pilot when I need it username and password nice nice it's pretty good actually uh so now we'll just add some STS what does it give me not bad not bad all right well we can we can definitely work with this let's make this a Max width form of 400 picks and a margin Auto on that and uh now we're going to need some that's pretty good pretty good oops have a problem with that um yeah let's let's get let's make this button just have an active State just so that when we uh when we click on it yeah we can do that we just want the background color to change a little did not work maybe it's just not enough I to CCC there we go okay so now we need a little space to put errors let's say class equals error because we want these validation errors right and I'll just put some error for now so we can just see how it looks probably want these under both username and password and yeah let's style those up do eror that looks pretty good uh not display none though let's go with uh let's go with a height maybe a Min height of 1 em or 1.2 em yeah sure that way when they disappear it won't make the form kind of shift around so yeah that looks pretty good see that one disappearing or not okay so this is a pretty good login form lookwise so now let's get it all hooked up so we will go here so we're going to request the form data and we're going to need username and password close copile like close username and password and if the username is well how do we want to do that exactly first let's see make it required let's just do our validation in here we won't like we won't overly complicate the validation step here um so if username if there's no username let's say or username type of username is not a string that's just to like make sure this will like narrow the type so that we get rid of the possible file data of uh whatever form data entry value does not equal string so this would be our failure condition so we want to return and now we don't just want to return object here we want want to return that fail so we're going to have to import fail from spell kit SL kit everything good except for that last little thing there um yeah I see you got an internal err there we'll get to you in a sec this is at Jaz all right so we want to fail this with and we should probably have a fairly consistent return here so um what was a good bad request I guess yeah bad request so 400 and we'll just say username is required um but let's make it let's make it a more robust object than that let's send username and then it'll have username can have both a value um and an error let's say and the the error maybe will be null sometimes close that off our value is username uh and I missed one okay so now if username isn't there we should say hey it's required and then we'll also do password which should be the same thing pretty much password and just let's make let's capitalize these error messages just for the look of it okay so now I think we can maybe start using the data so we're going to need a script tag and we want L.S so we have and then and we need our form so we want to say export let not page we want to say export L form and so just like we kind of showed before we want to see this value will be either form. username or if that doesn't exist an empty string because we don't want undefined to show up all the time and then for this instead of some error we want to say oh yeah and it's form. username Dov value. value right uh and so for this one we would say form. username do error that might may or may not be there and then we can do the same thing for oh it doesn't like that for usern name is possibly undefined okay does that solve that yep it does so let's do the same for password [Music] password and password so this should oh we got that undefined that I don't like in the airor right so we just need to do the same thing or an empty string so now we should have if I'm not mistaken here so a little bit of like uh at least the required part uh so let's hit log in and hey username is required if I add something to there H log in again oh now it says password subcrib oh but the username disappeared so let's go see what was wrong with that so username and password so we actually need to send back so for username it didn't matter because that's the first error you get but username actually needs to go back here as well so we should probably be fairly consistent with these Returns value username and maybe error null just so it doesn't get complicated with the different types so now if I hit log in username is required fill that in usw is required usw uh that's another validation here typing is hard and then we're going to uh and if I get them both just clears all right so then we want to actually do sort of like valid this is pretty good if username and password if username does not equal admin and password does not equal password because that's classic then we'll return an error here and we will do kind of what we've been doing already we'll do username password except that let's put the error here under password and say something like that username password combination is invalid sure so we're just hard Cod looking for this like I said you'd actually want to do something here where you you know check for the actual you know you want to Hash these the password and the username you want to send it to somewhere you want to check something maybe you're using like ozero or some uh service like that but we're just hardcoding this for now username is required admin password is required p that's not rid password and presume that would be successful okay so then if we are successful I guess um this is where we start doing stuff now so on a successful login let's get our cookies out cookies and on a successful login let's set our session cookies. set this is pretty close pretty close co-pilot uh I'm going to set it to my name I think it should be like an opaque you know token of some sort which you then get user information out of a database or something but this is just a learning experience we don't need to worry about all that and path is usually a good idea you almost always want the path option when you're dealing with the cookies um just because this is going to say like this cookie is always sent regardless of what path I'm on right now it's anything from the route out and that's generally what you want generally I mean if you don't want that you'll know and then I think if it's successful so we don't want to just stay on this page we probably want to redirect to the homepage I mean maybe you want to like take the old page as a query pram or something and then do something else but I think for now we can just say let's redirect so we need to import that redirect we need to import that redirect from uh cellit and then we will say I you throw a redirect throw redirect and we'll just go to the root and oh we need a what is the status for like just this is just a redirect from a form so I think it's 303 I think it's 303 so now we should be able to set our session on a successful login so then well let's see yeah let's just see how that goes so I'll say admin password log in and there we go logged in so presumably my session is now Adam so let's deal with that so I think a good way to deal with that will be a hook so we will use that sort of hook way we were doing before a server hook and we will change our session into a user so uh we want to export handle which is a function and that function gets like the event and uh resolve as I recall you return yeah that thing return resolve and now we can sort of do stuff in here implicitly has any type hey oh you know why because it's I wrote hook but it's hooks rename reboot hooks there we go types are happy again so we got our event we've got our resolve we're resolving here and so this is where we would want to do something so this is going to happen on every server side request so we basically want to say let's get yeah request and cookies out of here do we even need request probably not what we actually need is locals locals so then we will say if cookies get session so if that's got a value uh then we will set the locals user to that value so in this case it would be Adam again we'd really want to do an object you actually want to do this correctly in real life but we're just doing a learning experience here so now it doesn't like user and that's because it's not on locals I think I actually missed this part before but so the way you deal with that is this app. TS so this app. TS actually has a bunch of um these sort of Global interfaces that are useful across the various different um parts of the spell kid and so this one locals is how you kind of say oh hey I get to Define locals right here and so I'm going to do user um it's obviously not always on there so it's optional and then it's a string it should be an object with the user but we're going with the string for now because currently it says Adam so that solves that little problem so now it's on locals I think that's all we need to do with the hook and now we can use this somewhere so if we look in our layouts layout. sell so we are using that right the uh the page layout so if we open up the page layout I think one thing we could do is we could pass the page layout a prop so let's pass it a user prop let's say export let user and uh yeah that's probably good enough and then we want to say something like and I guess we can say it's a string even though it maybe should be a user object um but it's optional to string or undefined so then I think we want to do an if here we want to say like if that's pretty good except let's fix it up if there is a user let's put their name there and let's make this go to profile we'll make a profile page in just a sec and then that's where we can give them the ability to log out so if the user exists and then we're going to like print the name there otherwise a login that looks pretty good so now we just need to pass it so now what's that say user is missing okay that's pretty good so now we need to get the user and so how do we get that we will need a well we'll actually need a layout a server layout stop that for now so where were we put our server layout now we're going to need this in both uh the portfolio layout uses page layout and the blog group here layout use this page layout so we're going to need it in both so I think we can just make a server a layout server up here so we'll do plus layout. server. DS now this should be a really simple one because all we're really doing is we're um but we have locals. user and so if locals. user exists we just want to send that on so that's going to be our load function actually uh we'll just export load and'll be a cons and it'll just be a function doesn't even have to be async actually and all we want to do is take off locals from here and return user which is locals. user I think that's all and now in both of our layouts we should just be able to say Where's that yeah that's in the so in the layout. SP here we should be able to say let's get data so export let data and from our data we should have a user which is string or undefined and that's exactly what we need so we need data. user pass that into that shared page layout and we'll just do the exact same thing on the portfolio okay typ scripts happy I don't even know when that changed uh I wasn't paying attention but yay it says Adam cool and then this will go to a 404 because we haven't done a profile page right yeah right but um yeah looking good for now if we kill that cookie session cookie and refresh it should say log in yay nice admin I'll hit log in just to see the error again yay that's not the right password password okay so let's make a profile page then and give them the the ability to log out and I believe that will be all we need so we'll use the create route and in this case we're going to say profile and we're add a smell page and a a loader right so we need a page. server. TS yes because we need to have a action on it because it'll have a logout form okay so let's say we'll do the script [Music] tag and we'll say export let so this can access the same data that everything else did so we should have user on there if it exists so now we can sort of say well actually we could do that in the could do that in the load function too maybe that's the better place to do it because then we could say if there is a user show this page page but if there's no user go to the login page because why are you looking at your profile when you don't have one yet okay that's what we're going to do um but for now we'll leave that on there though and we'll say um you know H1 and this will just be data. user and then I'll make a logout button so we'll make a form with a method of post and an action if you remember let's get that action of remember this syntax log out now that action doesn't exist yet but we will make that in just a second there we go log out is log out one word or two honestly not sure and yeah so now let's open up the server we've got our load kind of half made for us here already we don't need these types anymore so on our load like I said we kind of want to get out we don't need this to be a sync either actually um we want to get out the locals and see if we have a user uh if there's no locals user now we don't want to return this we actually want to do a redirect throw redirect and this be 401 403 maybe 401 unauthorized sure and then we want to but it's a redirect so it has to be a three never mind 303 again I guess 303 and we'll go to the route oh no we'll go to login right yeah because we want you to log in to see your profile right okay I think oh yeah we need to import redart close close you're getting warmer there copilot all right I think that's all we need for that now we need the action though the actual log out action so const export wait we need to export const actions and our actions is an object and this time we won't use the default we'll actually use a name log out called log out and could be async but it doesn't actually have to be and what we will do is we will pull out cookies and we will just delete the session from cookies cookies dot delete I think it is yeah and we always want the path again and yeah um so you hit log out probably want to go back to either login or the root what do you guys think let's go to the root root so that'll be that action that'll be that long and let's let's see how we done how we've done that's been a lot of code without actually checking anything oh not bad not bad let's uh style that up a little bit see if cop pilot what do you think copilot yeah I mean we want Rebecca purple but not bad not bad you got anything for the form copilot no all right well form let's do um display Flex sure Flex maybe and we'll go justify content let's do Center and oh we should get the button from that other page maybe just quickly just quickly from the login page so they have the same looking kind of button probably would want actually a shared button component from a component library or something but hey again just trying to move quickly and fun all all right not bad not bad at all so now if I hit log out oh internal error so close so close what do we got here return redirect you can't return a redirect you have to throw a redirect right throw a redirect okay so now the cookie did actually whatever so again we'll check our login password's required doesn't work if it doesn't not actually the right password I type in the right password we get redirect to the front and Adam's there so now I click on that and I see the profile Adam we could load this up with whatever profile information we had um I'm still logged in across portfolio home and about I go back to here I can hit log out and boom I am now logged out again everything working I hope your solution was something like mine we'll see you in the next one so this this is the last module deployment so let's talk about deploying your app so when you're thinking about releasing your app from development into the world of production you'll probably need to know a little bit about the page options these allow you to control down to the individual page how you want to render your production application like do you want to render the whole pre-render the whole site do you want to like have SSR the majority of your application but have like the marketing Pages just be pre-rendered or maybe you want your hottest new products pre-rendered for performance but the rest of your site can just be server rendered on demand or maybe you want to build an spa and that is a perfectly fine option so as we discussed before by default spell kit will render or pre-render any components first on the server and send it to the client as HTML JavaScript and CSS and then it will as the JS loads it'll render the component again in the browser and make it interactive which is the process called hydration and then spelt kit will initialize the and take over all the navigations acting more like an Spa at that point um but if you hit refresh it does the whole process again from the server by exporting page options from either page. TS or page. server TS or layout. TS or layout. server TS you control how rendering is done for Pages or for groups of pages in the hierarchy uh so child layouts and Pages override the values set in the parent layouts or pages so for example you can enable pre-rendering for your entire app and then just disable it for pages that need to be dynamically rendered so let's talk about the options and how you do them so you basically from your server. TS or sorry from your uh page. TS or your layout. TS or your layout. serts or your layout. page. server. TS uh you export these variables this one is pre-render you would export pre-render it's a Boolean and you could say pre-render true and if you pre-render true then you're they're served as HTML fi files they're generated at build time um it removes it from the dynamic SSR manifest there's this manifest that decides what actually is SSR and and it gets removed and it serves it generates these files at build time and just serves them directly uh when you need them this is great for performance uh any pages that are all the same no matter who hits the URL are really like appropriate for being pre-rendered so pre-rendering true is great for those kind of pages pre-rendering false means like hey SSR this page whenever a request comes in like which is the default Behavior but this is how you can like mix and match you can have oh we're going to pre-render this this group but then this from the hierarchy down will be pre-render false that makes sense preer actually also has a third option it's not just a Boolean it's a Boolean plus this option uh it's the string Auto if you set your export your pre-render variable and it's set to the string Auto uh it's used for this case where you want to pre-render a route but also included in the SSR manifest so a route gets requested by the Rowser browser and if an HTM ml file exists because it was rendered at build time uh it gets served and if it doesn't it goes to the fall back route and then calls backend functions renders it so the pre- renderer will start at the root of your app and generate any files for any pre- renderable Pages or actually server server API routes it finds um uh each page is scanned for a tags or anchor elements and any of those that point to other Pages uh they also become candidates for pre-rendering so it'll sort of crawl your tree and because of this you generally don't need to specify which pages should be pre-rendered or accessed if you do need to specify because you don't have any links pointing to some pages but you actually do need them to be rendered as HTML um you can do that with an option in the felt config called entries you can also uh in your page. TS uh export an entries function uh which can do sort of the same thing and I won't go into that but if your entire app is suitable for pre-rendering you can actually just use their adapter static it's one of the adapters which we can talk about later and that'll just render everything statically too so another option page option is SSR so if you export a variable called SSR uh it's a Boolean if you set it to false it renders an empty HTML shell page to the client instead of like rendering it on the server and then hydrating it uh if you were to say export cons SSR equals false in the root layout. TS uh you would create an spba so that's an option uh CSR is client side rendering some pages don't require JavaScript at all and you can disable it entirely for that page just by exporting CSR equals false on that page. TS or page. server TS quick Cav it if both SSR and CSR is at false nothing gets rendered which makes sense but why would you do [Music] that then there's another option here there's trailing slash so you can export trailing slash and uh there's a few different options it can be basically by default spell kit will remove trailing slashes from URLs if you visit like uh slout it'll be slash or sorry if you visit slab slash it will respond and redirect to you to slash about without the slash takes the slash off um you have this option to change that behavior if you need which might be useful depending on your server um this option also affects pre-rendering too so if trailing slashes always so it can be never always or ignore if it's always a route like slout will result in a directory about with an index HTML file in it otherwise it will create an about. HTML and this kind of mirrors how static web server conventions are right now so those are the page options and if you combine those uh with your adapters you have an incredible amount of variance of what you can do so now we should talk about images and assets so if you want to use an image in your app you have a couple of options you can use the uh static directory and as we talked about before it'll serve from the root and it won't process these at all so you can put images in there and you could just like link to them with like a slash root relative link and they will be served without any modification um but if you well if you need a stable URL like you need oh this always has to be at this place that's actually probably the best place for it you know if you're always sending this PDF or this image from here that's probably a good place for it but you can also uh use the lib the dollar sign lib uh you can put your images in there in that directory and then you can import that in like you know your spelt dot your page. spelt let's say and then when you use it as like the source you can use the variable that you imported as the source uh it'll actually link to that and a neat thing is when you build this this will add a little hash to that so imported you know images and whatever that are used get this little hash added to it and that's good for you know breaking the H C sorry breaking the cache if you needed to uh you know every time you deploy oh the image Chang so you don't have these you know over you can cach them forever and it's fine because you're going to change the hash on that image the next time you load it anyway so that can be useful um and if you do do that import you can even use that in CSS like you you can write in your style uh you know image background image uh and then use the the same import route that you would in the import I can show you that in a bit um and then one of the last things is if it's small enough the image will actually be uh inlined as a base 64 string and that can be really useful especially if you just have these little small images you just like want to throw them up like little icons or whatever um great for performance just keeping it all so you don't have that extra request you kind of being wasted um it's if it's small enough and the way this that feature actually comes from V pre-process uh and same with the CSS and so you can configure that uh with a there is a configuration it's called it's build assets inline limit and then you sort of set the size and so if it's small enough it'll actually inline that so let's have a look at that so here we have just a little page here um and it's just got a little image so we've got our little hero image here and it's set to slh hero and you can sort of see in our static file we've got our hero here and our hero small and so uh we can set the background here using this and this is because of the V pre-process so we could just put the hero ping here oops just have my CSS messed up not a problem and you can see here so we have now like oh hey this div is actually got a hero here it's style the same size and whatever um so yeah this other here is actually bigger than this but I just put the height and the width at 100 just so they kind of match so that's one thing you can do and the other thing you can do is you can sort of uh you know if we were to take these and move them maybe I won't move them I'll copy them uh well no I'll move them move them into Libs SL images now our images will break but um now you can do something like in your script tag here import and then we would do um you know hero from and it's the lib file so you can actually use that and then it would be what's it in images images slh hero. ping and now I can use this as the source so this will get convert it into a string or whatever so you can just put that there and I could even well actually I can do this with this same import path I can put that here and this will work and now see they both come back and uh I just want to show you this other thing so you can have I've got the small image on there I've got that for a reason um I'll just small from there as well small it was small hero I believe hero small I was close small hero hero small these little hero avatars are from something I can't remember what hero small oh something not quite right there Heros small.png hero small.png small oh don't know where that came from wasn't paying attention down there all right so there we go so we have a small image here small im here we can actually change this to small hero too if it mattered um hero small I mean how many times can I make the same mistake as many as I need to um so yeah I wanted to show you um let's just throw another one of these with the static link up so we'll just put this back and I will do uh slh her. ping and I will make a copy of that that doesn't exist in the static paste all right I'll do the small one actually do the both but in here I want to do hero smell and now why am I doing this okay so it comes during development this is going to make no real difference it's during production that this actually matters so to show this part off I'm actually going to run npm run preview so this is how you run oh I need to run build first npm run build so this will build your spell Kit app um this little error here is like oh it's trying to use the auto adapter and you haven't deployed to somewhere it recognizes that's fine it doesn't matter we're not really deploying right now I just want to show you the differences in the build so now if I run un npm run preview you this will run our app as if it's in production mode essentially um we just need to click this other Port so 4173 here this is our our uh production build essentially and I wanted to show you the elements here and what the differences are so the first one here which is just the straightup um static it just comes from static points right at static that's the URL that's what you're going to get now this one that we imported from hero this one is oh it's got a little hash here 9879 because it's being built here this way you can sort of do cash busting and you'll always sort of have this and this little hash is great for that um so that can be a real performance Improvement because you can then cash these forever then you see oh the small one that came from the lib even though the one from static doesn't get changed the small one that came from the lib is being inlined as a string so this is just a base 64 string uh that represents that image and it's small enough to do that and then lastly if we look here on the Styles we can see this background image is also being uh inlined as a string because it's small enough and again that's configurable I don't know what the default is I think it's like less than 100 I don't even know something um but you can change that if you need to uh just for you know whether you want the tradeoffs between whether want to inline them or not so yeah so we are going to continue on so adapters so adapters are one of the core offerings of spell kit and they are fantastic so what are adapters adapters are small plugins that take the built app like after I just run npm build as input and they generate output for some deployment platform or some deployment environment and this is the decoupling of authoring your application and deploying your application that really follows that spelt philosophy and it's this kind of decoupling that allows for a great DX developer experience without sacrificing the user experience it's important um uh so spelt kit has many official adapters that they support and we'll show those but it also has a bunch of community provided adapters and of course you can build your own so what do it have for officially supported ones so it's got a node.js server so you can just basically anywhere you can run a node.js server you can throw this one up adapter node uh you can do adapter static for pre-rendering Pages or Spas um there's adapter netlify and adapter verell for netlify forell those popular Cloud platforms uh Cloud flare workers and cloudfare plages pages also have official adapters uh so that's great and then there's a whole bunch of community adapters uh which I will show here so these are Community provided adapters um these include platforms like Dino bun Firebase Azure static web apps um yeah a bunch of things check them out um this is actually actually at where is this again well if you go to uh kit. felt. Dev and then look at the adapters uh it'll have a link to this where you can find all these Community provided adapters so adapters make it easy to deploy your app and some of the adapters even allow a zero config deployment where out of the box the auto adapter is will figure out where you're trying to deploy deploy to and install the correct adapter and then build for you um and so some of those are cloudfare Pages uh netlify versel and Azure static web apps if you deploy oh and one more via SST so if you deploy to these places with the auto adapter on which is what kind of gets put by default when you generate the app uh you don't even have to set anything up it'll just figure it out and deploy for you and on that note let's move to the final exercise so exercise the exercise here for module 6 is we're going to deploy our little blog that we've been working on to uh somewhere you get to choose you get to deploy anywhere you want um but I'm going to show you how easy it is to deploy to netlify netlify I swear I have trouble saying that for some reason so I have put up my I have pushed my repo to the exercise branch of the spel kit workshop and so now if I sign into netlify and log in all right you can sort of see mine and now I can just add a new site and I want to import an existing site because I want to choose it from GitHub now don't worry about all my little things here but I looking for the felt kit Workshop there it is and well there we go the branch to deploy is the exercise Branch excellent so uh that's the branch I want to deploy to I'm not going to change any of these settings because they all look right uh yours might be main your branch or whatever you're doing depending on where you put it and I'm just going to hit this button deploy site and it says is deploying all right so now it's building and we're going to see you know how's this going uh things are working sort of see everything working out in progress failed oh well that's too bad let's see why it failed right the secret post token the secret post token that we need to get our posts from sp. fun okay so that's not a problem because we just need to know now you got to figure out how your platform adds uh environment variables but I know in uh netlify it's actually really easy we go to deploy settings there's environment variables and I can just add a variable here so I would just say uh secret posts token and then I'm going to give it the value spelled is fun because remember that's the that's the value create that variable and now back to our build and deploy and so if I'm not mistaken we should be able to [Music] deploy deploys trigger deploy and let's watch it deploy again all right didn't configure anything other than that one environment variable that we were using of course I could have uploaded an enem file to and had a bunch of deployed at the same or a bunch configured at the same time but the point is now looks like it's working so we're building we're building we're building we're deploying we're [Music] deploying and we're done and there it is up on a production URL and of course I would configure my domain if I wanted to go on with this but there is our spelt kit blog and our little portfolio that's how easy it is with spel kit adapters so now what whoops so we learned how to add routing and SSR to our apps we learned how to load data from assets from the server we learned how to use forms and change data from from the client we learned how to add API end points if needed and how to build and deploy our apps to popular cloud services and there's actually still even more spell kit gives us so don't forget to check out the docs at kit. spelt dodev uh find libraries courses uh and all sorts of Rees at sp. framework. Dev and you can always join the spelt Discord uh at the community there and of course just start building applications so thanks very much that's all this program is presented by this. laabs the framework agnostic consulting firm helping Enterprises realize their technical goals through staff augmentation Consulting project management on demand subject experts training and other Professional Services find out more at this . labs.com
Info
Channel: This Dot Media
Views: 13,538
Rating: undefined out of 5
Keywords:
Id: wWRhX_Hzyf8
Channel Id: undefined
Length: 304min 34sec (18274 seconds)
Published: Tue Oct 24 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.