Updated
—
4 min read
SvelteKit, being SSR-first and having API endpoints, comes with fullstack capabilities. But there are cases where you may require a more robust backend than what SvelteKit provides, in which case a monorepo is a great choice.
In this short writeup, I'm going to give a tutorial on how to create a SvelteKit monorepo, so that you can share code (like Typescript types) between your SvelteKit project and other Node.js apps (an Express.js server in this example).
Here's an example of why you might want to use a monorepo with SvelteKit:
When I was working on a SvelteKit project that requires file uploading, I found that SvelteKit is
a little lackluster regarding multipart/form-data
handling.
As of writing, SvelteKit cannot handle streaming of request/response bodies.
But Express.js alongside busboy
for example, can do this no problem. This is one example of why having a separate
backend for SvelteKit may be a good idea.
For sake of simplicity, let's assume a simple monorepo with a www
project housing your SvelteKit app and backend
housing an Express.js server.
markdownproject
- www # Your SvelteKit app
- backend # An Express.js app, for example
To share code between our www
and backend
projects, we'll need a "common" module, or shared folder.
To do this, create a new Node app that is siblings with www
.
markdownproject
- www
- backend
- common # Where we'll put shared code
Initialize a new npm package in common
:
bashcd common
npm init
Then, install some basic dependencies for Typescript:
bashnpm install -D typescript @types/node prettier
Most importantly, you need to install tsconfig-paths
, which will be important later:
bashnpm install -D tsconfig-paths
Create a tsconfig.json
file in your common
directory.
Then, here's a basic setup you can copy:
json{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"esModuleInterop": true,
"strict": false,
"noImplicitAny": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"resolveJsonModule": true,
"isolatedModules": true,
"moduleResolution": "node",
"baseUrl": "./",
"paths": {
"www/*": ["../www/src/*"], # Path alias to SvelteKit project
"backend/*": ["../backend/src/*"] # Path alias to Express.js project
}
},
"include": [
"../www/src/**/*.ts",
"../backend/src/**/*.ts",
"**/*.ts"
],
"exclude": ["node_modules"],
"ts-node": {
"require": ["tsconfig-paths/register"]
}
}
This lets you access www
and backend
files from your common directory.
For example, in common
, you could now do:
javascriptimport { Schema } from "www/src/types/schema";
// ...
Lastly, we need to do something similar with our www
SvelteKit project.
In your SvelteKit project, open up tsconfig.json
.
Note: SvelteKit warns that "If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes from the referenced tsconfig.json — Typescript does not merge them."
Basically, you want to open ./.svelte-kit/tsconfig.json
and copy include
and exclude
into your
root tsconfig.json
.
From there, you can add in the include for the common
Typescript files.
json"include": [
"../common/**/*.ts",
// ... rest of includes copied over
]
In the end, your new SvelteKit tsconfig.json
should look something like:
json{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler"
},
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
"include": [
"../common/**/*.ts", // Include files from common module
"ambient.d.ts",
"non-ambient.d.ts",
"./types/**/$types.d.ts",
"../vite.config.js",
"../vite.config.ts",
"../src/**/*.js",
"../src/**/*.ts",
"../src/**/*.svelte",
"../tests/**/*.js",
"../tests/**/*.ts",
"../tests/**/*.svelte"
],
"exclude": [
"../node_modules/**"
]
}
Lastly, we just need to add a path alias to our SvelteKit config so we can access the common
files.
To do that, open up svelte.config.js
and add this block under kit
:
javascriptconst config = {
preprocess: vitePreprocess(),
kit: {
adapter: adapter(),
alias: {
$common: "../common/src", # Add this path alias
},
}
};
Now you're all set! In your SvelteKit project, you can now import code from your common
module like so:
svelte<script lang="ts">
import { Schema } from "$common/types/schema";
import { SCHEMA_DATA_TYPES } from "$common/static/constants";
</script>
Hope this short tutorial helps someone. I couldn't find a specific writeup on how to share types between a SvelteKit frontend and a backend server.
Let me know if you have any suggestions or improvements to make.
Meet the Author
Ryan Chiang
Hello, I'm Ryan. I build things and write about them. This is my blog of my learnings, tutorials, and whatever else I feel like writing about.
See what I'm building →.
Thanks for reading! If you want a heads up when I write a new blog post, you can subscribe below: