DEV Community

Cover image for SvelteKit Hooks. Everything You Need To Know
Lucretius Biah
Lucretius Biah

Posted on

SvelteKit Hooks. Everything You Need To Know

SvelteKit has something called hooks. A file which exports a set of functions which run on every request to the server. It's really useful!

Introduction

A SvelteKit hook is a file which exports four functions which you can use to modify data from your server. It is not compulsory for your app to contain a hook file but one is implemented by default if you don't create one. It exports four optional functions handle, handleError, getSession and externalFetch. With hooks, you can extend SvelteKit to suit your needs😉.

Use Cases of Hooks

A list of possible things which you can do with SvelteKit hooks.

  • Redirecting a user
  • Authenticating a user
  • Minifying HTML, CSS and JavaScript response
  • Getting the user session
  • Setting cookies
  • Fetching data from a database
  • Handling errors
  • Modifying fetch response
  • Modifying HTML returned from the server

Creating a Hook

The default location for the hook file is src/hooks.js or if you prefer to use a folder, you can store your functions in an index.js file inside src/hooks/ which will then make the path src/hooks/index.js.

Also, you can change the default path to the file inside your svelte.config.js file by editing the config.kit.files.hooks value.

Listed below are the list of functions which are exported by hooks in SvelteKit.

handle

The handle hook is a function which runs on every request to the server and also during prerendering. It allows us to access the request and modify the response. Inside the handle function, we can add custom data to the request.locals which will then be accessible to all the endpoints.

To simply put, the handle function acts like a middle-man who sits between the client and the server and intercepts the request before taking it back to the client. This allows us to perform a variety of actions to the response before sending it back. For example, we can decide to minify the HTML response before sending it back to the server or redirect a user who is not logged-in to the login page.

export const handle = async ( { event, resolve })=> { return await resolve(event)}
Enter fullscreen mode Exit fullscreen mode

The snippet above shows the bare minimum of how the handle hook works. It receives an event object which contains the request and an asynchronous resolve function which generates the response by taking in the event as parameter. Also included in the event object is the clientAddress (a getter function which returns the user's I.P address), locals(An object which allows you to pass custom data to your endpoints), params (an object which contains the value of the dynamic path), platform (a variable which contains the system's platform. It is usually set by the adapter), routeId and url.

To add custom data to the request, just populate the event.locals with your data before returning the response. You can also minify your HTML generated by SvelteKit using hooks since it doesn't do that by default. I have written a guide on how to do it.

The resolve function also supports a second optional parameter that also gives us more control over the response.

  1. ssr

This allows us to disable server-side rendering. By default, it is set to true. If set to false. It renders an empty shell page.

   /** @type {import('@sveltejs/kit').Handle} */

   export const handle = async ( { event, resolve })=>{
       const response = await resolve(event,{
           ssr: false
       });
       return response;
   }
Enter fullscreen mode Exit fullscreen mode
  1. transformPage

This function allows you to apply custom transforms to the HTML document.

   /** @type {import('@sveltejs/kit').Handle} */

   export const handle = async ( { event, resolve })=>{
       const response = await resolve(event,{
           transformPage: ({ html })=>{
               return html.replace("a","b")
           }
       });
       return response;
   }
Enter fullscreen mode Exit fullscreen mode

Multiple handle functions

SvelteKit allows you to chain multiple handle functions with the use of the sequence helper function. What the function does is that, it takes an array of functions and iterates through them and apply the handle function to each of them.

Let's look at an example.

import { sequence } from "@sveltejs/kit/hooks";

const first = async ( { event, resolve })=>{
    console.log("First handle start");
    const result = await resolve(event);
    console.log("First handle stop")
    return result;
}

const second = async ( { event, resolve })=>{
    console.log("Second handle start");
    const result = await resolve(event);
    console.log("Second handle stop");
    return result;
}


export const handle = sequence(first, second)
Enter fullscreen mode Exit fullscreen mode

The resulting response will be:

First handle start
Second handle start
Second handle stop 
First handle stop  
Enter fullscreen mode Exit fullscreen mode

As you can see from the resulting output, the first function will be called first followed by the second function but the second function will finish before the first function. Well, I still don't know the reason why it happens this way🤷‍♂️.

Fixing Common Errors Whiles Using The Sequence Helper

  1. Cannot find package "@sveltejs/kit" on production build

This problem is mostly found for those who use adapter-node whiles using the sequence helper function. The reason for this error is that, adapter-node doesn't bundle @sveltejs/kit with the build output so it doesn't find the sequence function when running the application in production.

Solution

  1. Create a file called sequence.js and paste the sequence function code inside.

    You can get the source code from node_modules/@sveltejs/kit/dist/hooks.js.

  2. Then you import the sequence function from the file you just created.

    example below

      import { sequence } from "./sequence.js";
    

handleError

This is the hook responsible for handling errors in your application. Whenever an error is thrown when rendering your app, this function will be called with the error and the corresponding event that caused it. This function actually doesn't do much apart from reporting the errors in your application. It is mostly useful during production where you might want to get notified of every error that happens in your application. For example, you might want to write in a code that sends you an email each time your app receives an error.

During development, a frame will be displayed on your screen highlighting the cause of the error.

The handleError function will not be called when pages and endpoints explicitly respond with 4xx and 5xx status codes
Enter fullscreen mode Exit fullscreen mode

getSession

Since HTTP is a stateless protocol, it means the client and server forget about each other at the end of every request. In order to keep track of user's state, we use sessions to store data about the user. The data is stored in the server's memory.

The getSession hook allows you to access the session object. The function takes an event object and returns a session object. This function is run whenever SvelteKit server-renders a page. If it's unimplemented, the session is an empty object {}.

Apart from accessing the session object, you can also set the session inside this hook. Let's look at an example.

export const getSession = (event)=>{
    return event.locals.user = {
        name: "John Doe",
        age: "20",
        id: 112244233434343
    }
}
Enter fullscreen mode Exit fullscreen mode

In the example above, we set the session object with some values. In order to access the session in our page, we just need to retrieve it inside our load function.

<script context="module">
    export const load = async ({ session })=>{
        return {
            props: {
            session
            }
        }
    }
</script>
Enter fullscreen mode Exit fullscreen mode

Also, the data inside our session object will be accessible by endpoint if they access event.request.locals.

externalFetch

This hook simply allows you to modify a fetch request that happens inside a load function that runs on the server. Any fetch to any external resource than runs on the server is handled by this function. Actually, it doesn't do much, the only important use case I found for it was making it hit API's directly instead of passing through proxies. This doesn't do much but it helps increase the speed of your fetch requests. Also, it allows you to modify the headers of your fetch request.

Conclusion

This is a much detailed explanation of hooks in SvelteKit. If any information is missing out, please do write it in the comment section.

Top comments (2)

Collapse
 
greggcbs profile image
GreggHume

I just dont get why they would call middleware - hooks. And use a word that is already know in React as some other thing.

Collapse
 
qudo profile image
qudo

being able to HOOK into requests already happening makes a lot of sense. Not everything in web dev is inspired by React, thank god.