I have made a few changes to this starter. The key changes I have made from the previous version:
Update Route Guard functionality to be more generic and able to handle a wider range of conditions (excluded routes, post handling).
Created a new library so it is easy for me to update all my applications that use this functionality. Maybe this will be useful for others as well.
Created a new library so it is easy for me to update all my applications that use this functionality. Maybe this will be useful to others independent of the template as well.
Updated to use the latest dependencies for Luica (v3) and Sveltekit-Superforms (v2). All other libraries also updated, but these two had relatively signifianct changes.
Updated Dependencies and to use the preview release of Svelte 5.
Added server sent event functionality to unlock some realtime and collaborative functionality.
Added websockets (using socket.io) with an example page.
Previously tailwind was specifically excluded, however I have decided to include it as I like to use it, and I can make the provided elements a bit tidier, and ShadCN as it has some nice elements.
The SvelteKit-Lucia-Starter is an all-inclusive SvelteKit template that comes pre-configured with a comprehensive set of features to kickstart your next application. Inspired by the T3 Stack, this starter kit provides a similar feature set with added functionality.
Includes the following features:
routes/+layout.svelte
). With fading between pages.To get started with SvelteKit-Lucia-Starter, follow these steps:
Clone the repository:
git clone https://github.com/qwacko/sveltekit-lucia-starter.git
Install the dependencies:
cd sveltekit-lucia-starter
pnpm install
Replace the example env file:
mv .env.example .env
Start the development server (this will create and migrate the SQLite database):
pnpm dev
This template is tested to work with Docker using the provided Dockerfile. It possibly may work with a service such as Vercel or Netlify, however there may be significant changes (Prisma, Sveltekit Adapter, Auth Library Crypto, Cron Jobs etc..) and I haven't tested it.
Recommendation is to stick with Docker (or possibly node) unless you are knowledgable in the environment you are planning on deploying to.
The following environemnt variables are included
| Variable | Purpose |
| ------------- | ------------- |
|ORIGIN| Used In Production Only. Indicates the origin for all node routing to work correctly|
|DATABASE_FILE|Set the database file location. Used in both dev and production.|
|ALLOW_SIGNUP|Indicates whether to enable public signup following the first user creation. Set to "true" to enable this|
|DEV_OVERRIDE|Allows the authentication to be put into dev mode, which doesn't enforce secure cookies. This can be used if the service is to be accessed over a non-https route (i.e. IP Address)|
|CSRF_CHECK_ORIGIN|Allows CSFR to be disabled if necessary. Only disable if you know what you are doing and why you are disabling.|
|LOGGING|Allows logging to be turned on in production. Logging is always turned on in dev|
|LOGGING_CLASSES| Allows the different classes of logging to be enabled. The options are ERROR
, WARN
, INFO
, DEBUG
, TRACE
(with a comma separated list allowing multiple to be enabled). Defaults to ERROR,WARN,INFO
|
|BACKUP_DIR| Sets the location of the automated and manual backups. Defaults to ./backup|
|BACKUP_SCHEDULE| Cron string to set the Backup schedule. Defaults to "0 0 * * *" (Midnight daily)|
|ENABLE_TRANSITION| Enables the view transition API to have smooth page transitions.|
Auth is handled by the lucia-auth
library with username and password authentication. Includes each user able to be admin or not. Also includes automatic redirection to the first user creation dialog if the first user hasn't already been created.
Using a library that I have created skGuard to perform this functionality. The specific implementation of this can be found in /lib/server/authGuard/authGuardConfig.ts
. The example implementation protects routes etc...
The beauty of this approach is that it can be applied throughout the application easily and consistently.
There is custom functionality for specific use cases (i.e. redirection to first user) handled directly within the hooks.
The PWA is configured to function correctly, however to work for the specific app it wil need additional configuration:
vite.config.ts
to reflect the name of the app.static/logo.svg
with the app icon, and runn pnpm generate-pwa-assets
to generate all the necessary icons from this fileThe shadcn-svelte library is included to provide easy access to components and component core. Configuration through the components.json
file. By default, imported components will be included into $lib/components/shadcn
(which can be adjusted by modifying the components.json
file).
The Drizzle ORM schema is configured in src/lib/server/db/schema
and all files should be compiled into index.ts
to allow for the application to use this correctly. Migration files are stored in src/lib/server/db/migrations
.
If you want different information related to the user (currently only username
and admin
) to be available through lucia-auth, you will need to modify the app.d.ts
file and src/lib/server/lucia.ts
, as these values are not related to the drizzle schema.
The following scripts are available in relation to drizzle:
pnpm db:generate
: Generates the necessary migrations from the current schema.pnpm db:studio
: Executes drizzle studio to allow for db exploration.There is server sent event functionality implemented in the "sse/[id]" route. The demonstration has two canvases and uses SSE to mirror the mouse position on one across to the mouse position on the other. This is done by sending the mouse position to the server, which updates a storage object (using unstorage for key-value store management), on message being processed, a callback is run to then send the mouse position back to the browser.
This functionality is for demonstration purposes only and would require a number of different considerations to be used in a production environment.
One thing to be aware of is that the way that the data is sent from the client to the server is a POST
request, which means that there are a number of db calls to authenticate the user that are done for each update.
There is a websocket server setup, and demonstration of this functionality included in the 'ws/[id]' route. Similar to server sent events, this mirrors mouse position in a canves to other memebers of the same room. With socket.io, the rooms are handled by socket.io rooms to make use of this functionality.
The fuctionality of the server can be modified by changing the code in src/lib/server/websocket/wsServer.ts
. The current implementation has basic functionality to demonstrate how authentication may be handled by validating the session cooking using lucia auth.
If websockets are not required, the following changes can be made to remove the server:
Remove the ws
folder in src/routes
Remove the websocket
folder in src/lib/server
Remove server from +hooks.server.ts
by removing the following code:
import { wsServer } from '$lib/server/websocket/wsServer';
wsServer();
Remove websocket from dev server by removing the following code from vite.config.ts
:
import WsPlugin from 'vite-sveltekit-node-ws';
//And (From the plugins section of the config)
WsPlugin(),
Remove the websocket dependencies (pnpm remove vite-sveltekit-node-ws socket.io socket.io-client
)
Run a typescript check (pnpm check
) to ensure that there are no errors.
Custom logic using another library (skRoutes) that provides validation and easy update of search params to use them as a primary state storage location.
A demonstration of how the logic is supposed to work is included in the /params
page (with the logic in src/routes/(open)/params
). Note that this library provides more functionality than just search param validation, and is fully configured for this demonstration application.
A DockerFile has been created, that is a staged build (to reduce the final file size). A couple of things to consider:
The docker-compose-example.yml
can be used as a starting point for a docker-compose file that should work.
dockerEntrypoint.sh
script is pre-prepared for if you needed to add any specific actions on server start.Enviroment Variables (At least the server side dynamic ones) are able to be validated using a zod data structure. This can be found in the file lib/server/serverEnv.ts
.
For the CSRF protection, there is a line of code added to the file svelte.config.js
To simplify logging a logging object is created, which allows for the same input context as a console.log
, but also will prefix the server timestamp and log class (with the ability to enable / disable some or all logging using environment variables).
To log data use the following code:
import { logging} from './logging';
...
logging.info('Server Environment:', serverEnv);
There is a single function (backupDB
) for backing up the database included in the file src/lib/server/db/db.ts
, this will generate a db dump of the current state into a folder defined in environment variable BACKUP_DIR
.
There is a preconfigured cron job to execute this function every day, the schedule is configured by the Environment variable BACKUP_SCHEDULE
which should be a cron schedule (this isn't validated, the text is used directly).
dev
: Start the development serverbuild
: Build the project for productionpreview
: Preview the production build locallytest:unit
: Run unit tests using Vitestlint
: Run Prettier and ESLintformat
: Run Prettier to format the codecheck
: Run typescript check, and svelte-check of the code.db:generate
: Reads the current drizzle schema and updates the migrations.db:studio
: Runs the Drizzle Studio to allow the user to explore (and modify) the db data.db:undo
: Allows the undo of a specific migration step.db:custom
: Adds a custom blank migration.drizzle-kit
: Gives full access to the drizzle-kit functionality.