npm create svelte@latest my-app
┌ Welcome to SvelteKit!
│
◇ Which Svelte app template?
│ Skeleton project
│
◇ Add type checking with TypeScript?
│ Yes, using JavaScript with JSDoc comments
│
◇ Select additional options (use arrow keys/space bar)
│ Add ESLint for code linting, Add Prettier for code formatting
│
└ Your project is ready!
Now install dependencies
npx svelte-add@latest tailwindcss
npm i @skeletonlabs/skeleton @supabase/auth-helpers-sveltekit @supabase/supabase-js
In your tailwind.config.js
add
/** @type {import('tailwindcss').Config} */
module.exports = {
// 1. Apply the dark mode class setting:
darkMode: 'class',
content: [
'./src/**/*.{html,js,svelte,ts}',
// 2. Append the path for the Skeleton NPM package and files:
require('path').join(require.resolve(
'@skeletonlabs/skeleton'),
'../**/*.{html,js,svelte,ts}'
)
],
theme: {
extend: {},
},
plugins: [
// 3. Append the Skeleton plugin to the end of this list
...require('@skeletonlabs/skeleton/tailwind/skeleton.cjs')()
]
}
In your app.html
add <html class="dark">
//src/routes/+layout.svelte
// Your selected Skeleton theme:
import '@skeletonlabs/skeleton/themes/theme-skeleton.css';
// This contains the bulk of Skeletons required styles:
import '@skeletonlabs/skeleton/styles/skeleton.css';
// Finally, your application's global stylesheet (sometimes labeled 'app.css')
import '../app.postcss';
Make sure to checkout https://supabase.com/docs/guides/getting-started/tutorials/with-sveltekit#building-the-app for details.
Add .env
and paste your keys like this
PUBLIC_SUPABASE_URL="YOUR_SUPABASE_URL"
PUBLIC_SUPABASE_ANON_KEY="YOUR_SUPABASE_KEY"
// src/hooks.server.ts
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'
import { createSupabaseServerClient } from '@supabase/auth-helpers-sveltekit'
import type { Handle } from '@sveltejs/kit'
export const handle: Handle = async ({ event, resolve }) => {
event.locals.supabase = createSupabaseServerClient({
supabaseUrl: PUBLIC_SUPABASE_URL,
supabaseKey: PUBLIC_SUPABASE_ANON_KEY,
event,
})
/**
* A convenience helper so we can just call await getSession() instead const { data: { session } } = await supabase.auth.getSession()
*/
event.locals.getSession = async () => {
const {
data: { session },
} = await event.locals.supabase.auth.getSession()
return session
}
return resolve(event, {
filterSerializedResponseHeaders(name) {
return name === 'content-range'
},
})
}
If you have some errors don't worry they will go away later. 😄
// src/app.d.ts
import { SupabaseClient, Session } from '@supabase/supabase-js'
declare global {
namespace App {
interface Locals {
supabase: SupabaseClient
getSession(): Promise<Session | null>
}
interface PageData {
session: Session | null
}
// interface Error {}
// interface Platform {}
}
}
// src/routes/+layout.server.ts
export const load = async ({ locals: { getSession } }) => {
return {
session: await getSession(),
}
}
// src/routes/+layout.ts
import { invalidate } from '$app/navigation'
import { PUBLIC_SUPABASE_ANON_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public'
import { createSupabaseLoadClient } from '@supabase/auth-helpers-sveltekit'
export const load = async ({ fetch, data, depends }) => {
depends('supabase:auth')
const supabase = createSupabaseLoadClient({
supabaseUrl: PUBLIC_SUPABASE_URL,
supabaseKey: PUBLIC_SUPABASE_ANON_KEY,
event: { fetch },
serverSession: data.session,
})
const {
data: { session },
} = await supabase.auth.getSession()
return { supabase, session }
}
<!-- src/routes/+layout.svelte -->
<script lang="ts">
import '../styles.css'
import { invalidate } from '$app/navigation'
import { onMount } from 'svelte'
export let data
let { supabase, session } = data
$: ({ supabase, session } = data)
onMount(() => {
const { data } = supabase.auth.onAuthStateChange((event, _session) => {
if (_session?.expires_at !== session?.expires_at) {
invalidate('supabase:auth')
}
})
return () => data.subscription.unsubscribe()
})
</script>
<svelte:head>
<title>User Management</title>
</svelte:head>
Now your setup should be working, you can start designing your login page.
So I like to use server side and client side things together,