sveltekit-python-vercel 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -1,22 +1,34 @@
|
|
|
1
|
+
<p align="middle">
|
|
1
2
|
<img width="100" alt="image" src="https://user-images.githubusercontent.com/20548516/218344678-d41f4c4a-6b1b-48cc-8553-2b9fbe2169d6.png"/>
|
|
2
3
|
<img width="100" alt="image" src="https://camo.githubusercontent.com/f1ac9955f30176e6183aeeeac1b77354c7a132696fdc77c06ef0f0bec30f258c/68747470733a2f2f6861636b616461792e636f6d2f77702d636f6e74656e742f75706c6f6164732f323031392f30392f707974686f6e2d6c6f676f2e706e67"/>
|
|
3
4
|
<img width="100" alt="image" src="https://camo.githubusercontent.com/add2c9721e333f0043ac938f3dadbc26a282776e01b95b308fcaba5afaf74ae3/68747470733a2f2f6173736574732e76657263656c2e636f6d2f696d6167652f75706c6f61642f76313538383830353835382f7265706f7369746f726965732f76657263656c2f6c6f676f2e706e67"/>
|
|
5
|
+
</p>
|
|
4
6
|
|
|
5
7
|
# sveltekit-python-vercel
|
|
6
8
|
|
|
7
9
|
Write Python endpoints in [SvelteKit](https://kit.svelte.dev/) and seamlessly deploy them to Vercel.
|
|
8
10
|
|
|
11
|
+
- [Current Features](#current-features)
|
|
12
|
+
- [Installing](#installing)
|
|
13
|
+
- [Testing Locally](#testing-locally)
|
|
14
|
+
- [Deploying to Vercel](#deploying-to-vercel)
|
|
15
|
+
- [Example](#example)
|
|
16
|
+
- [Backend Caveats](#backend-caveats)
|
|
17
|
+
- [Fork of `sveltekit-modal`](#fork-of-sveltekit-modal)
|
|
18
|
+
- [Possible future plans](#possible-future-plans)
|
|
19
|
+
|
|
9
20
|
**This is very much in beta.**
|
|
10
21
|
|
|
11
22
|
## Current Features
|
|
12
23
|
|
|
13
24
|
- Write `+server.py` files nearly the same way you would write `+server.js` files
|
|
14
|
-
-
|
|
25
|
+
- Deploy (quasi) automatically to Vercel Serverless
|
|
15
26
|
|
|
16
27
|
## Installing
|
|
17
28
|
|
|
18
29
|
- Open or set up your SvelteKit project
|
|
19
|
-
- Install
|
|
30
|
+
- Install SvelteKit's Vercel adapter: `pnpm i -D @sveltejs/adapter-vercel`
|
|
31
|
+
- Install with `pnpm i -D sveltekit-python-vercel`
|
|
20
32
|
- Update your `vite.config.js`
|
|
21
33
|
|
|
22
34
|
```javascript
|
|
@@ -34,7 +46,7 @@ Write Python endpoints in [SvelteKit](https://kit.svelte.dev/) and seamlessly de
|
|
|
34
46
|
- Update your `svelte.config.js`:
|
|
35
47
|
|
|
36
48
|
```javascript
|
|
37
|
-
import adapter from "@sveltejs/adapter-vercel";
|
|
49
|
+
import adapter from "@sveltejs/adapter-vercel"; // Use the vercel adapter
|
|
38
50
|
import { vitePreprocess } from "@sveltejs/kit/vite";
|
|
39
51
|
|
|
40
52
|
/** @type {import('@sveltejs/kit').Config} */
|
|
@@ -50,8 +62,10 @@ Write Python endpoints in [SvelteKit](https://kit.svelte.dev/) and seamlessly de
|
|
|
50
62
|
```
|
|
51
63
|
|
|
52
64
|
- Update your `vercel.json`
|
|
65
|
+
|
|
53
66
|
- The build command prepares all your endpoints and copies them to the `/api` directory where Vercel looks for functions
|
|
54
67
|
- Functions and Routes tell Vercel how to run and redirect function calls
|
|
68
|
+
|
|
55
69
|
```json
|
|
56
70
|
{
|
|
57
71
|
"buildCommand": "node ./node_modules/sveltekit-python-vercel/esm/src/vite/sveltekit_python_vercel/bin.mjs; vite build",
|
|
@@ -72,7 +86,8 @@ Write Python endpoints in [SvelteKit](https://kit.svelte.dev/) and seamlessly de
|
|
|
72
86
|
- Write some `+server.py` endpoints. See the example section below.
|
|
73
87
|
|
|
74
88
|
## Testing Locally
|
|
75
|
-
|
|
89
|
+
|
|
90
|
+
Using [Poetry](https://python-poetry.org/) to manage your virtual environments with this package is recommended.
|
|
76
91
|
|
|
77
92
|
- Run `poetry init` to create a new virtual environment, and follow the steps. Or simply create a `pyproject.toml` like the one below.
|
|
78
93
|
|
|
@@ -94,15 +109,38 @@ Using [Poetry](https://python-poetry.org/) to manage your virtual environments w
|
|
|
94
109
|
requires = ["poetry-core"]
|
|
95
110
|
build-backend = "poetry.core.masonry.api"
|
|
96
111
|
```
|
|
112
|
+
|
|
97
113
|
- Required packages are python3.9 (that is what Vercel's runtime uses), `fastapi`, and `uvicorn`.
|
|
98
114
|
- Install whatever other dependencies you need from pypi using `poetry add package-name`
|
|
99
115
|
|
|
116
|
+
- Enter your virtual env with `poetry shell`
|
|
100
117
|
- Run `pnpm dev` or `npm dev`
|
|
118
|
+
- 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.
|
|
119
|
+
|
|
120
|
+
## Deploying to Vercel
|
|
121
|
+
|
|
122
|
+
- 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.
|
|
123
|
+
|
|
124
|
+
- When you make changes to your python endpoints, you have to manually regenerate the `/api` folder by running:
|
|
125
|
+
1. `poetry export -f requirements.txt --output requirements.txt --without-hashes`
|
|
126
|
+
2. `node ./node_modules/sveltekit-python-vercel/esm/src/vite/sveltekit_python_vercel/bin.mjs`
|
|
127
|
+
- Then commit `requirements.txt` and the changes in `/api` and push.
|
|
101
128
|
|
|
129
|
+
Note:
|
|
130
|
+
|
|
131
|
+
- To make this a bit smoother, you can add a script to you `package.json`:
|
|
132
|
+
```json
|
|
133
|
+
"scripts": {
|
|
134
|
+
...
|
|
135
|
+
"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"
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
- and then just run `pnpm py-update`
|
|
102
139
|
|
|
103
140
|
## Example
|
|
104
141
|
|
|
105
142
|
- Frontend: `/src/routes/py/+page.svelte`
|
|
143
|
+
|
|
106
144
|
```html
|
|
107
145
|
<script lang="ts">
|
|
108
146
|
let a = 0;
|
|
@@ -110,12 +148,12 @@ Using [Poetry](https://python-poetry.org/) to manage your virtual environments w
|
|
|
110
148
|
let total = 0;
|
|
111
149
|
|
|
112
150
|
async function pyAddPost() {
|
|
113
|
-
const response = await fetch(
|
|
114
|
-
method:
|
|
151
|
+
const response = await fetch("/py", {
|
|
152
|
+
method: "POST",
|
|
115
153
|
body: JSON.stringify({ a, b }),
|
|
116
154
|
headers: {
|
|
117
|
-
|
|
118
|
-
}
|
|
155
|
+
"content-type": "application/json",
|
|
156
|
+
},
|
|
119
157
|
});
|
|
120
158
|
let res = await response.json();
|
|
121
159
|
total = res.sum;
|
|
@@ -123,10 +161,10 @@ Using [Poetry](https://python-poetry.org/) to manage your virtual environments w
|
|
|
123
161
|
|
|
124
162
|
async function pyAddGet() {
|
|
125
163
|
const response = await fetch(`/py?a=${a}&b=${b}`, {
|
|
126
|
-
method:
|
|
164
|
+
method: "GET",
|
|
127
165
|
headers: {
|
|
128
|
-
|
|
129
|
-
}
|
|
166
|
+
"content-type": "application/json",
|
|
167
|
+
},
|
|
130
168
|
});
|
|
131
169
|
|
|
132
170
|
let res = await response.json();
|
|
@@ -138,9 +176,9 @@ Using [Poetry](https://python-poetry.org/) to manage your virtual environments w
|
|
|
138
176
|
|
|
139
177
|
<h3>POST Example</h3>
|
|
140
178
|
<form>
|
|
141
|
-
<input type="number" name="a" placeholder="Number 1" bind:value={a} />
|
|
142
|
-
<input type="number" name="b" placeholder="Number 2" bind:value={b} />
|
|
143
|
-
<button on:click|preventDefault={pyAddPost}>Add</button>
|
|
179
|
+
<input type="number" name="a" placeholder="Number 1" bind:value="{a}" />
|
|
180
|
+
<input type="number" name="b" placeholder="Number 2" bind:value="{b}" />
|
|
181
|
+
<button on:click|preventDefault="{pyAddPost}">Add</button>
|
|
144
182
|
</form>
|
|
145
183
|
<h4>Total: {total}</h4>
|
|
146
184
|
|
|
@@ -148,14 +186,15 @@ Using [Poetry](https://python-poetry.org/) to manage your virtual environments w
|
|
|
148
186
|
|
|
149
187
|
<h3>GET Example</h3>
|
|
150
188
|
<form>
|
|
151
|
-
<input type="number" name="a" placeholder="Number 1" bind:value={a} />
|
|
152
|
-
<input type="number" name="b" placeholder="Number 2" bind:value={b} />
|
|
153
|
-
<button on:click|preventDefault={pyAddGet}>Add</button>
|
|
189
|
+
<input type="number" name="a" placeholder="Number 1" bind:value="{a}" />
|
|
190
|
+
<input type="number" name="b" placeholder="Number 2" bind:value="{b}" />
|
|
191
|
+
<button on:click|preventDefault="{pyAddGet}">Add</button>
|
|
154
192
|
</form>
|
|
155
193
|
<h4>Total: {total}</h4>
|
|
156
194
|
```
|
|
157
195
|
|
|
158
196
|
- Backend: `/src/routes/py/+server.py`
|
|
197
|
+
|
|
159
198
|
```python
|
|
160
199
|
from pydantic import BaseModel
|
|
161
200
|
|
|
@@ -174,10 +213,15 @@ Using [Poetry](https://python-poetry.org/) to manage your virtual environments w
|
|
|
174
213
|
|
|
175
214
|
```
|
|
176
215
|
|
|
177
|
-
|
|
216
|
+
### Backend Caveats
|
|
178
217
|
|
|
179
218
|
There are currently a few things that have to be worked around.
|
|
180
219
|
|
|
220
|
+
- `GET` endpoints are directly fed the parameters from the url, so when you define an endpoint
|
|
221
|
+
- 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.
|
|
222
|
+
|
|
223
|
+
See the example above.
|
|
224
|
+
|
|
181
225
|
## Fork of `sveltekit-modal`
|
|
182
226
|
|
|
183
227
|
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.
|
|
@@ -25,7 +25,8 @@ for module_path in glob.glob(str(root_dir / 'src/routes/**/+server.py'), recursi
|
|
|
25
25
|
|
|
26
26
|
# replace the root_dir with api_dir
|
|
27
27
|
api_route = api_dir / Path(module_path).absolute().relative_to(root_dir / "src/routes")
|
|
28
|
-
|
|
28
|
+
api_route = Path(str(api_route).replace('[', '{').replace(']', '}'))
|
|
29
|
+
|
|
29
30
|
if not api_route.parent.exists():
|
|
30
31
|
api_route.parent.mkdir(parents=True)
|
|
31
32
|
|
|
@@ -22,6 +22,9 @@ for module_path in glob.glob('./**/+server.py', recursive=True):
|
|
|
22
22
|
|
|
23
23
|
api_route = module_path[1:] if module_path.startswith('./') else module_path
|
|
24
24
|
api_route = str(Path(api_route).parent)
|
|
25
|
+
|
|
26
|
+
# Replace square brackets with curly brackets
|
|
27
|
+
api_route = api_route.replace('[', '{').replace(']', '}')
|
|
25
28
|
|
|
26
29
|
mod = importlib.import_module(module_name, module_package)
|
|
27
30
|
|
|
@@ -52,6 +52,9 @@ if __name__ == "__main__":
|
|
|
52
52
|
# Convert the relative path to a string and remove the file extension
|
|
53
53
|
api_path = "/" + str(rel_path.parent)
|
|
54
54
|
|
|
55
|
+
# Replace square brackets with curly brackets
|
|
56
|
+
api_path = api_path.replace('[', '{').replace(']', '}')
|
|
57
|
+
|
|
55
58
|
print("ADDING API PATH:", rel_path, api_path)
|
|
56
59
|
|
|
57
60
|
if hasattr(mod, 'GET'):
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"module": "./esm/mod.js",
|
|
3
3
|
"types": "./types/mod.d.ts",
|
|
4
4
|
"name": "sveltekit-python-vercel",
|
|
5
|
-
"version": "v0.
|
|
5
|
+
"version": "v0.3.0",
|
|
6
6
|
"description": "Write Sveltekit server endpoints in Python and seamlessly deploy to Vercel",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|