0.4.1 • Published 12 months ago

sveltekit-python-vercel v0.4.1

Weekly downloads
-
License
MIT
Repository
github
Last release
12 months ago

sveltekit-python-vercel

Write Python endpoints in SvelteKit and seamlessly deploy them to Vercel.

This is very much in beta.

Current Features

  • Write +server.py files nearly the same way you would write +server.js files
  • Deploy (quasi) automatically to Vercel Serverless

Installing

  • 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.js

    import { 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 /api directory 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"
        }
      ]
    }
  • Write some +server.py endpoints. See the example section below.

Testing Locally

Using Poetry to manage your virtual environments with this package is recommended.

  • Run poetry init to create a new virtual environment, and follow the steps. Or simply create a pyproject.toml like 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, and uvicorn.

  • Install whatever other dependencies you need from pypi using poetry add package-name

  • Enter your virtual env with poetry shell

  • Run pnpm dev or npm 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.

Deploying to Vercel

  • 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 /api folder by running:

    1. poetry export -f requirements.txt --output requirements.txt --without-hashes
    2. node ./node_modules/sveltekit-python-vercel/esm/src/vite/sveltekit_python_vercel/bin.mjs
  • Then commit requirements.txt and the changes in /api and 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

Example

  • 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.py

    from 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}

### Backend Caveats

There are currently a few things that have to be worked around.

- `GET` endpoints 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.

## Fork of `sveltekit-modal`

Check out the awesome [sveltekit-modal](https://github.com/semicognitive/sveltekit-modal) package by [@semicognitive](https://github.com/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.

## Possible future plans

- [X] 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\
0.4.1

12 months ago

0.4.0

12 months ago

0.3.0

12 months ago

0.2.0

12 months ago

0.1.0

12 months ago