Fullstack Svelte with SvelteKit

Headers, Cookies, & Shared Modules

Fullstack Svelte with SvelteKit

Check out a free preview of the full Fullstack Svelte with SvelteKit course

The "Headers, Cookies, & Shared Modules" Lesson is part of the full, Fullstack Svelte with SvelteKit course featured in this preview video. Here's what you'd learn in this lesson:

Rich discusses setting headers and cookies on the response using Set-Header, Set-Cookie, and the cookies API. Organizing shared modules into a lib directory, allowing them to be accessed by any module in the src folder, is also covered in this segment.


Transcript from the "Headers, Cookies, & Shared Modules" Lesson

>> All right, let's talk about headers and cookies. So inside your load function, as well as inside form actions and API route and hooks, which are things that we'll learn about later in the workshop. You have access to a setHeaders function, which does exactly what you would expect.

The most common thing that you would use, setHeaders for is to set a cache control header on the response so that data doesn't need to be re requested. But we can't really demonstrate that in this context, so we're gonna do something a little bit more dramatic. We're gonna change the content type of the response, To text/plain and we're gonna need to reload the page so that we can see that.

You see that it's no longer giving us an HTML response that the browser can render, it's giving us some plain text instead. And one thing you can't use the setHeaders function for is to set cookies. Instead you should use the cookies API which is also available in all of the same places that setHeaders is.

So in page.server.js we're gonna bring in the cookies API. And we're gonna replace this const visited equals false line with something based on the cookies that were sent from the browser to the server when the page was requested. Cookies get visited. And then after the first time the user visits we're gonna set that cookie to true so that when they come back, we'll recognize them.

We do that with cookies.set visited, give it a value of true. And you should always set a path on your cookies because the browser's default behavior is to set the path. On whatever the parent of the path that you're visiting is which is not very helpful. Most of the time you wanna set your cookies on the root of your application.

We can now see that when we return visited, if the user has visited the page before, they are no longer stranger, they are friend. Now, the reason we use this cookies API instead of interacting with headers is that not only does cookies set cause a set cookie header to be added to the response.

It also updates the internal map so that if you call cookies.get inside another load function that is also involved in rendering this page. It will be current with the cookie that was set previously. You have a bunch of options that you can pass here, we're using the cookie package under the hood, which you can find on npm.

But we're adding some defaults to make the behavior of your application more secure. Specifically, we're making all of your cookies HTTP only by default, we're setting secure to true. Except when you're on localhost, and we're setting same site to lax. These defaults will protect your users from their cookies being leaked.

>> To clarify about the thing you said with the cookies, so if I set a cookie in a layout, then I can reference it? Even though it's not actually in the request cookies, I can reference it as if it was in a page server file?
>> So as long as you, so there's like a potential race condition because the load functions run simultaneously.

And so if you set the cookie asynchronously after it's been requested in the load function, then that's a bug. And actually that's probably a bug that we could catch and throw an error in that situation because that is actually quite a nasty bug. But more typically, the way that you would use that is inside your, server hook, which we'll cover later on.

You would do something like event dot locals dot user equals get user, from my cookies. If that doesn't exist, then we set a cookie and then inside your load function, the cookie has been set because your hook always runs before your load function. But we'll get into all of that stuff later on.

It's also useful when you're dealing with form actions because if you have a login action, for example, you might set a cookie inside that action. And then when the load function is subsequently called the cookie will have been set by the time you read it in the load function.

So that's why we use the cookies API as opposed to relying on a fresh request coming in.
>> When working with input dependent data, what is the best approach to loading it? For instance, on a search page, should the user's input be handled with a promise on the component or with a data object?

>> It depends on the UI that you're trying to achieve. If you want the results to be streamed in as the user is typing, then you would want to have that logic inside the component, and you would have all of the async handling there. The way that I tend to build search inputs is, I'll just use a regular form that causes the data to be loaded inside a load function.

And so you have to type in the search query and then hit enter, for me I just find that to be a preferable user experience. It also happens to be much easier to implement because you don't need to deal with any of the async logic. SvelteKit takes care of it for you but it depends, there's no canonically right answer.

So because SvelteKit uses directory based routing, it's easy to place modules and components alongside the routes that use them. I find a good rule of thumb when figuring out where to put code is like put code close to where it's being used. But sometimes code is being used in multiple places and when that happens you don't wanna have to do ../ ../ ../ ../ to get a reference to the module.

It's nice to have a place to put that stuff that is common to all your routes, and SvelteKit that place is the source/lib directory. Anything inside this directory can be accessed by any module in source via the lib alias. So both of these page.svelte files are importing a file from src/lib, they're trying to get a hold of this message.

And the home page is doing it right, but if we navigate to this deeply nested route, we get an error from vite telling us that it's failed to import. And that's because we've got the wrong number of dot dot slashes, we've got five when we should have four.

So, we could fix it by fixing the number of dot dot slashes, but it would be a hell of a lot nicer if we could just use $lib instead. So, get rid of all of that and do the same in page.svelte. And that will work consistently for all of the modules and components in your lib folder.

So that's a nice place to put shared utility components, utils, js file, other things of that nature.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now