cheatsheets devlog projects search

sveltekit-cheatsheet.md

SvelteKit Cheatsheet

2023-01-14 3

Instructions to get started with sveltekit.

npm create svelte@latest project-name
cd project-name
npm install
npm install -D tailwindcss postcss autoprefixer svelte-preprocess
npm install @sveltejs/adapter-node@next
npm install dotenv
npm install svelte-kit-cookie-session
npm install bettersqlite3
npm install bcrypt

Now we have sveltekit, tailwind and the node adapter installed.

Update vite.config.js to set up the host and port to run the application on.

import { sveltekit } from '@sveltejs/kit/vite';

const config = {
    server: {
        host: '0.0.0.0',
        port: 7091,
    },
	plugins: [sveltekit()]
};

export default config;

Now update svelte.config.js:

import adapter from '@sveltejs/adapter-node';
import { vitePreprocess } from '@sveltejs/kit/vite';
import preprocess from "svelte-preprocess";

/** @type {import('@sveltejs/kit').Config} */
const config = {
    preprocess: vitePreprocess(),
    kit: {
        adapter: adapter({ out: 'out' })
    },
    preprocess: [
        preprocess({
            postcss: true,
        }),
    ],
};

export default config;

Now we can create the tailwind config file:

/** @type {import('tailwindcss').Config} */
module.exports = {
    content: ['./src/**/*.{html,js,svelte,ts}'],
    theme: {
        extend: {},
    },
    plugins: [],
}

Update src/app.css:

@tailwind base;
@tailwind components;
@tailwind utilities;

Add a global stylesheet:

touch src/global.css

Update src/routes/+layout.svelte:

<script>
    import "../app.css";
    import "../global.css";
</script>

<slot />

Update src/routes/+page.svelte:

<h1 class="text-3xl font-bold underline">
  Hello world!
</h1>

Start the dev server:

npm run dev

We should now see the home page with the hello world styled.

Create .env to hold the secret, host and port. The host and port will be used by pm2 when going live but during development it will be from the vite config file.

SECRET="super-secret-key"
HOST=127.0.0.1
PORT=6109

Create a database folder in the current directory:

mkdir db

Create src/hooks.server.js to hold the database and sessions logic:

import * as dotenv from 'dotenv'
dotenv.config();

import { redirect, error } from '@sveltejs/kit';
import { handleSession } from '../node_modules/svelte-kit-cookie-session';

import Database from 'better-sqlite3';
const db = new Database('db/kk.db');

export const handle = handleSession(
    {
        secret: process.env.SECRET
    }, 
    ({ event, resolve }) => {
        const path = event.url.pathname;
        const session = event.locals.session.data;

        if (path.startsWith("/admin") && !session.loggedIn) {
            throw redirect(302, "/");
        }

        event.locals.db = db;
        return resolve(event);
    }
);

This can then be used in a route, src/routes/+page.server.js like:

export async function load({ locals }) {
    const db = locals.db;
    let items = db.prepare(`SELECT * FROM news`).all();

    return {
        items
    }
}

A user can be logged in, this would be +page.sever.js:

import { redirect } from '@sveltejs/kit';
import bcrypt from "bcrypt";
 
export const actions = {
    default: async ({ locals, request }) => {
        const db = locals.db;

        const values = await request.formData();

        const username = values.get('username');
        const password = values.get('password');

        const row = db.prepare('SELECT * FROM users WHERE username = ?').get(username);

        if (!row) {
            return { error: 'Invalid username.' };
        }

        let valid = await bcrypt.compare(password, row.password);
        if (!valid) {
            return { error: 'Invalid password.' };
        }

        await locals.session.set({ loggedIn: true, username: username });
        throw redirect(302,"/");
    }
};

The frontend login page:

<script>
    export let form;
</script>

{#if form !== null }
    {form.error}
{/if}
 
<form method="POST" action="">
    <label for="username">Username</label>
    <input type="text" name="username">
    
    <label for="password">Password</label>
    <input type="password" name="password">
    
    <button>Login</button>
</form>