sveltekit-python-vercel 0.2.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
|
@@ -17,13 +17,12 @@ Write Python endpoints in [SvelteKit](https://kit.svelte.dev/) and seamlessly de
|
|
|
17
17
|
- [Fork of `sveltekit-modal`](#fork-of-sveltekit-modal)
|
|
18
18
|
- [Possible future plans](#possible-future-plans)
|
|
19
19
|
|
|
20
|
-
|
|
21
20
|
**This is very much in beta.**
|
|
22
21
|
|
|
23
22
|
## Current Features
|
|
24
23
|
|
|
25
24
|
- Write `+server.py` files nearly the same way you would write `+server.js` files
|
|
26
|
-
- Deploy (
|
|
25
|
+
- Deploy (quasi) automatically to Vercel Serverless
|
|
27
26
|
|
|
28
27
|
## Installing
|
|
29
28
|
|
|
@@ -47,7 +46,7 @@ Write Python endpoints in [SvelteKit](https://kit.svelte.dev/) and seamlessly de
|
|
|
47
46
|
- Update your `svelte.config.js`:
|
|
48
47
|
|
|
49
48
|
```javascript
|
|
50
|
-
import adapter from "@sveltejs/adapter-vercel";
|
|
49
|
+
import adapter from "@sveltejs/adapter-vercel"; // Use the vercel adapter
|
|
51
50
|
import { vitePreprocess } from "@sveltejs/kit/vite";
|
|
52
51
|
|
|
53
52
|
/** @type {import('@sveltejs/kit').Config} */
|
|
@@ -63,8 +62,10 @@ Write Python endpoints in [SvelteKit](https://kit.svelte.dev/) and seamlessly de
|
|
|
63
62
|
```
|
|
64
63
|
|
|
65
64
|
- Update your `vercel.json`
|
|
65
|
+
|
|
66
66
|
- The build command prepares all your endpoints and copies them to the `/api` directory where Vercel looks for functions
|
|
67
67
|
- Functions and Routes tell Vercel how to run and redirect function calls
|
|
68
|
+
|
|
68
69
|
```json
|
|
69
70
|
{
|
|
70
71
|
"buildCommand": "node ./node_modules/sveltekit-python-vercel/esm/src/vite/sveltekit_python_vercel/bin.mjs; vite build",
|
|
@@ -85,7 +86,8 @@ Write Python endpoints in [SvelteKit](https://kit.svelte.dev/) and seamlessly de
|
|
|
85
86
|
- Write some `+server.py` endpoints. See the example section below.
|
|
86
87
|
|
|
87
88
|
## Testing Locally
|
|
88
|
-
|
|
89
|
+
|
|
90
|
+
Using [Poetry](https://python-poetry.org/) to manage your virtual environments with this package is recommended.
|
|
89
91
|
|
|
90
92
|
- Run `poetry init` to create a new virtual environment, and follow the steps. Or simply create a `pyproject.toml` like the one below.
|
|
91
93
|
|
|
@@ -107,6 +109,7 @@ Using [Poetry](https://python-poetry.org/) to manage your virtual environments w
|
|
|
107
109
|
requires = ["poetry-core"]
|
|
108
110
|
build-backend = "poetry.core.masonry.api"
|
|
109
111
|
```
|
|
112
|
+
|
|
110
113
|
- Required packages are python3.9 (that is what Vercel's runtime uses), `fastapi`, and `uvicorn`.
|
|
111
114
|
- Install whatever other dependencies you need from pypi using `poetry add package-name`
|
|
112
115
|
|
|
@@ -115,6 +118,7 @@ Using [Poetry](https://python-poetry.org/) to manage your virtual environments w
|
|
|
115
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.
|
|
116
119
|
|
|
117
120
|
## Deploying to Vercel
|
|
121
|
+
|
|
118
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.
|
|
119
123
|
|
|
120
124
|
- When you make changes to your python endpoints, you have to manually regenerate the `/api` folder by running:
|
|
@@ -122,8 +126,8 @@ Using [Poetry](https://python-poetry.org/) to manage your virtual environments w
|
|
|
122
126
|
2. `node ./node_modules/sveltekit-python-vercel/esm/src/vite/sveltekit_python_vercel/bin.mjs`
|
|
123
127
|
- Then commit `requirements.txt` and the changes in `/api` and push.
|
|
124
128
|
|
|
125
|
-
|
|
126
129
|
Note:
|
|
130
|
+
|
|
127
131
|
- To make this a bit smoother, you can add a script to you `package.json`:
|
|
128
132
|
```json
|
|
129
133
|
"scripts": {
|
|
@@ -133,12 +137,10 @@ Note:
|
|
|
133
137
|
```
|
|
134
138
|
- and then just run `pnpm py-update`
|
|
135
139
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
140
|
## Example
|
|
140
141
|
|
|
141
142
|
- Frontend: `/src/routes/py/+page.svelte`
|
|
143
|
+
|
|
142
144
|
```html
|
|
143
145
|
<script lang="ts">
|
|
144
146
|
let a = 0;
|
|
@@ -146,12 +148,12 @@ Note:
|
|
|
146
148
|
let total = 0;
|
|
147
149
|
|
|
148
150
|
async function pyAddPost() {
|
|
149
|
-
const response = await fetch(
|
|
150
|
-
method:
|
|
151
|
+
const response = await fetch("/py", {
|
|
152
|
+
method: "POST",
|
|
151
153
|
body: JSON.stringify({ a, b }),
|
|
152
154
|
headers: {
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
+
"content-type": "application/json",
|
|
156
|
+
},
|
|
155
157
|
});
|
|
156
158
|
let res = await response.json();
|
|
157
159
|
total = res.sum;
|
|
@@ -159,10 +161,10 @@ Note:
|
|
|
159
161
|
|
|
160
162
|
async function pyAddGet() {
|
|
161
163
|
const response = await fetch(`/py?a=${a}&b=${b}`, {
|
|
162
|
-
method:
|
|
164
|
+
method: "GET",
|
|
163
165
|
headers: {
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
+
"content-type": "application/json",
|
|
167
|
+
},
|
|
166
168
|
});
|
|
167
169
|
|
|
168
170
|
let res = await response.json();
|
|
@@ -174,9 +176,9 @@ Note:
|
|
|
174
176
|
|
|
175
177
|
<h3>POST Example</h3>
|
|
176
178
|
<form>
|
|
177
|
-
<input type="number" name="a" placeholder="Number 1" bind:value={a} />
|
|
178
|
-
<input type="number" name="b" placeholder="Number 2" bind:value={b} />
|
|
179
|
-
<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>
|
|
180
182
|
</form>
|
|
181
183
|
<h4>Total: {total}</h4>
|
|
182
184
|
|
|
@@ -184,14 +186,15 @@ Note:
|
|
|
184
186
|
|
|
185
187
|
<h3>GET Example</h3>
|
|
186
188
|
<form>
|
|
187
|
-
<input type="number" name="a" placeholder="Number 1" bind:value={a} />
|
|
188
|
-
<input type="number" name="b" placeholder="Number 2" bind:value={b} />
|
|
189
|
-
<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>
|
|
190
192
|
</form>
|
|
191
193
|
<h4>Total: {total}</h4>
|
|
192
194
|
```
|
|
193
195
|
|
|
194
196
|
- Backend: `/src/routes/py/+server.py`
|
|
197
|
+
|
|
195
198
|
```python
|
|
196
199
|
from pydantic import BaseModel
|
|
197
200
|
|
|
@@ -213,6 +216,7 @@ Note:
|
|
|
213
216
|
### Backend Caveats
|
|
214
217
|
|
|
215
218
|
There are currently a few things that have to be worked around.
|
|
219
|
+
|
|
216
220
|
- `GET` endpoints are directly fed the parameters from the url, so when you define an endpoint
|
|
217
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.
|
|
218
222
|
|
|
@@ -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",
|