Write Python endpoints in SvelteKit and seamlessly deploy them to Vercel.
- Current Features
- Installing
- Testing Locally
- Deploying to Vercel
- Example
- Fork of
sveltekit-modal - Possible future plans
This is very much in beta.
- Write
+server.pyfiles nearly the same way you would write+server.jsfiles - Deploy (quasi) automatically to Vercel Serverless
-
Open or set up your SvelteKit project
-
Install SvelteKit's Vercel adapter:
pnpm i -D @sveltejs/adapter-vercel -
Install with
pnpm i -D sveltekit-python-vercel -
Update your
vite.config.jsimport { defineConfig } from "vite"; import { sveltekit } from "@sveltejs/kit/vite"; import { sveltekit_python_vercel } from "sveltekit-python-vercel/vite"; export default defineConfig(({ command, mode }) => { return { plugins: [sveltekit_python_vercel(), sveltekit()], }; });
-
Update your
svelte.config.js:import adapter from "@sveltejs/adapter-vercel"; // Use the vercel adapter import { vitePreprocess } from "@sveltejs/kit/vite"; /** @type {import('@sveltejs/kit').Config} */ const config = { preprocess: vitePreprocess(), kit: { adapter: adapter(), moduleExtensions: [".js", ".ts", ".py"], // add ".py" to resolve +server.py endpoints }, }; export default config;
-
Update your
vercel.json- The build command prepares all your endpoints and copies them to the
/apidirectory where Vercel looks for functions - Functions and Routes tell Vercel how to run and redirect function calls
{ "buildCommand": "node ./node_modules/sveltekit-python-vercel/esm/src/vite/sveltekit_python_vercel/bin.mjs; vite build", "functions": { "api/**/*.py": { "runtime": "@vercel/python@3.0.7" } }, "routes": [ { "src": "/api/(.*)", "dest": "api/index.py" } ] } - The build command prepares all your endpoints and copies them to the
-
Write some
+server.pyendpoints. See the example section below.
Using Poetry to manage your virtual environments with this package is recommended.
-
Run
poetry initto create a new virtual environment, and follow the steps. Or simply create apyproject.tomllike the one below.[tool.poetry] name = "sveltekit-python-example" version = "0.1.0" description = "" authors = ["Your Name <email@gmail.com>"] readme = "README.md" [tool.poetry.dependencies] python = "^3.9" fastapi = "^0.95.2" uvicorn = "^0.22.0" [tool.poetry.group.dev.dependencies] watchfiles = "^0.19.0" [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api"
-
Required packages are python3.9 (that is what Vercel's runtime uses),
fastapi, anduvicorn. -
Install whatever other dependencies you need from pypi using
poetry add package-name -
Enter your virtual env with
poetry shell -
Run
pnpm devornpm dev- You should see both the usual SvelteKit server start as well as the unvicorn server (by default on
http://0.0.0.0:8000) in the console.
- You should see both the usual SvelteKit server start as well as the unvicorn server (by default on
-
At the moment this requires a tiny bit of extra labor besides just pushing to your repository. I believe this is because of the way Vercel looks for serverless functions, but I hope to make this a bit easier in the future.
-
When you make changes to your python endpoints, you have to manually regenerate the
/apifolder by running:poetry export -f requirements.txt --output requirements.txt --without-hashesnode ./node_modules/sveltekit-python-vercel/esm/src/vite/sveltekit_python_vercel/bin.mjs
-
Then commit
requirements.txtand the changes in/apiand push.
Note:
- To make this a bit smoother, you can add a script to you
package.json:"scripts": { ... "py-update": "poetry export -f requirements.txt --output requirements.txt --without-hashes; node ./node_modules/sveltekit-python-vercel/esm/src/vite/sveltekit_python_vercel/bin.mjs" }
- and then just run
pnpm py-update
- and then just run
-
Frontend:
/src/routes/py/+page.svelte<script lang="ts"> let a = 0; let b = 0; let total = 0; async function pyAddPost() { const response = await fetch("/py", { method: "POST", body: JSON.stringify({ a, b }), headers: { "content-type": "application/json", }, }); let res = await response.json(); total = res.sum; } async function pyAddGet() { const response = await fetch(`/py?a=${a}&b=${b}`, { method: "GET", headers: { "content-type": "application/json", }, }); let res = await response.json(); total = res.sum; } </script> <h1>This is a SvelteKit page with a python backend.</h1> <h3>POST Example</h3> <form> <input type="number" name="a" placeholder="Number 1" bind:value="{a}" /> <input type="number" name="b" placeholder="Number 2" bind:value="{b}" /> <button on:click|preventDefault="{pyAddPost}">Add</button> </form> <h4>Total: {total}</h4> <br /> <h3>GET Example</h3> <form> <input type="number" name="a" placeholder="Number 1" bind:value="{a}" /> <input type="number" name="b" placeholder="Number 2" bind:value="{b}" /> <button on:click|preventDefault="{pyAddGet}">Add</button> </form> <h4>Total: {total}</h4>
-
Backend:
/src/routes/py/+server.pyfrom pydantic import BaseModel class NumberSet(BaseModel): a: float b: float async def POST(data: NumberSet): return {"sum": data.a + data.b} async def GET(a: float, b: float): return {"sum": a + b}
There are currently a few things that have to be worked around.
GETendpoints are directly fed the parameters from the url, so when you define an endpoint- All other endpoints are fed the body as a JSON. The recommended way to deal with this is to use a pydantic model and pass it as the singular input to the function.
See the example above.
Check out the awesome sveltekit-modal package by @semicognitive, the original way to get your python code running in SvelteKit. Modal even has GPU support for running an entire ML stack within SvelteKit.
- Add hot reloading in dev mode
- Generate endpoints (/api folder) automatically during build
- Auto create requirements.txt from pyproject.toml (both related to vercel functions being checked/handled before build)
- Add form actions
- Add load functions
- Add helper functions to automatically call API endpoints in project\
