I had some troubles in past days in setting up MikroORM (Archived) with SvelteKit (Archived) so that I would like to share how I finally managed to do it.

First we need to start a new SvelteKit project without typescript1, and install a couple of MikroORM and Vite-related packages.

npm init svelte@next sveltekit-mikroorm
# Use a Skeleton project with Typescript
npm install --save @mikro-orm/core @mikro-orm/sqlite @mikro-orm/migrations vite-plugin-ts uuid

Then we have to change the typescript configuration by adding the following lines to tsconfig.json under compilerOptions

  "experimentalDecorators": true,
  "emitDecoratorMetadata": true,

and by adding the typescript plugin to the Vite config in vite.config.js

import { sveltekit } from '@sveltejs/kit/vite'
import viteTs from 'vite-plugin-ts'

/** @type {import('vite').UserConfig} */
const config = {
    plugins: [
	viteTs(),
	sveltekit(),
    ]
}

export default config

Then we can start by defining our entity, like a simple Post structure

// src/lib/entities/Post.ts
import { Entity, Property, PrimaryKey } from '@mikro-orm/core'
import { v4 } from 'uuid'

@Entity()
export default class Post {
    @PrimaryKey()
    id!: string = v4()

    @Property()
    title!: string

    @Property()
    body!: string

    constructor (title: string, body: string) {
	this.title = title
	this.body = body
    }
}

and also write the database layer, which also takes care of creating and applying all migrations.

// src/lib/database.ts
import 'reflect-metadata'
import { MikroORM } from '@mikro-orm/core'
import Post from '$lib/entities/Post.ts'

const orm = await MikroORM.init({
    entities: [Post],
    dbName: "data.sqlite3",
    type: "sqlite",
    migrations: {
	emit: "js",
    },
})
// Create the new migrations, then apply them
const migrator = orm.getMigrator()
await migrator.createMigration()
await migrator.up()

// Export the orm as default
export default orm

Then create the migrations folder in the repository root and add migrations/package.json specifying that the file inside of it are in CJS format.

{
    "type": "commonjs"
}

Now we can add our custom index view and relative backend functions to display available posts and to add new ones.

<script>
 // src/routes/index.svelte
 export let posts
</script>

<h1>List of Posts ({posts.length})</h1>

{#each posts as post}
    <h2>{post.title}</h2>
    <p>{post.body}</p>
{/each}

<form method="POST">
    <label for="title">Title</label>
    <input type="text" name="title" placeholder="Post Title" />
    <br/>
    <textarea name="body" placeholder="Post Content"></textarea>
    <br/>
    <input type="submit" value="New Post" />
</form>
// src/routes/index.js
import orm from '$lib/database.ts'
import Post from '$lib/entities/Post.ts'

export async function GET() {
    const em = orm.em.fork()
    let posts = await em.find(Post, {})
    return { body: { posts } }
}

export async function POST({ request }) {
    const em = orm.em.fork()
    const form = await request.formData()
    const data = Object.fromEntries(form)
    const post = new Post(data.title, data.body)
    await em.persistAndFlush([post])
    return await GET()
}

So that now you have a simple website that persists posts into a database and allows everyone to add them. If you are interested in all the fine details, you can look at the commit diff (Archived).

Footnotes

  1. If you have an already existing project with Typescript you have to remove vitePreprocess from svelte.config.js and remove tslib, typescript from devDependencies.