I have a backend REST API written in Python, and I want to make a simple front end in Svelte. The front end should be a Single Page Application and not have to rely on a Node.js server, or any kind of server side routing. I want to serve this over Nginx and rely on client side routing. The front end is "dynamic" in the sense that it needs pages with unknown parameters, for example:
/blog/1
/blog/2
However, it is not quite intuitive as to whether you need to prerender and which build adapter to use. Without the correct settings, the build will most likely fail. Even if you get the build to run successfully, it is hard to test it on your local host.
The key to making this work is to add a fallback
page in svelte.config.js
; without this you won't be able to build successfully:
import adapter from '@sveltejs/adapter-static';
const config = {
kit: {
adapter: adapter({
fallback: 'index.html'
})
}
};
Next you need to disable server side routing and prerendering, as well as enable client side routing. In your src/routes/layout.js
, add the following:
export const ssr = false;
export const csr = true;
export const prerender = false;
You can actually prerender certain content. But any page with [parameters] must not be prerendered.
Now you can run npm run build
.
In your build
directory, you should now see an index.html
file:
To test it, you would ideally set up an Nginx on docker. However to quickly test it you can use Python's simple server.
On the command line navigate to the build
directory and run:
python -m http.server
Now in your browser, go to http://localhost:8000/
. Python's web server will default this /
to your index.html.
However, if you try to directly load another route, like http://localhost:8000/foo
, you will see a 404. To rectify this, run the following Python code from within the build
file and try again:
import os
from http.server import SimpleHTTPRequestHandler, HTTPServer
class FallbackHTTPRequestHandler(SimpleHTTPRequestHandler):
def send_error(self, code, message=None, explain=None):
if code == 404:
self.path = "/index.html"
super().do_GET()
else:
super().send_error(code, message, explain)
httpd = HTTPServer(("localhost", 8000), FallbackHTTPRequestHandler)
httpd.serve_forever()
What this will do is always serve the /index.html
file as a fallback.
Without the fallback
option in svelte.config.js
, you can see errors when you run npm run build
such as:
> Using @sveltejs/adapter-static
@sveltejs/adapter-static: all routes must be fully prerenderable, but found the following routes that are dynamic:
- src\routes/
- src\routes/bar
- src\routes/bar/[lol]
- src\routes/foo
This error is because adapter-static will require all routes to be prerenderable, unless you add a fallback.
Another error you may see if you mark your routes as prerenderable:
Error: The following routes were marked as prerenderable, but were not prerendered because they were not found while crawling your app:
- /bar/[lol]
In this case, you have a dynamic route, so prerendering won't work.
The solution for SPAs is to use a fallback in svelte.config.js
.
This is particularly important for local development when you need your SPA connecting to a local webserver.
Add two files to your root directory:
/project
src/
...
.env
.env.local
For SPAs, all keys need to be prefixed with PUBLIC_. This will make the variables accessible from +page.svelte
files.
For example in .env
:
PUBLIC_BASE_URL=
In .env.local
:
PUBLIC_BASE_URL=http://localhost:8080
You can then access these from your +page.svelte
via:
import { PUBLIC_BASE_URL} from '$env/static/public';
When you build and deploy, having the empty PUBLIC_BASE_URL in .env
means that all fetch requests will go to the same host.
Note that if you receive this error it means that your .env
files are not located in your root directory:
SyntaxError: ambiguous indirect export: PUBLIC_FOO
To get $lib
imports working and proper IDE checking in VSCode, add this jsconfig.json to the root directory:
{
"compilerOptions": {
"checkJs": true,
"noImplicitAny": false,
"paths": {
"$lib":["./src/lib"],
"$lib/*":["./src/lib/*"]
},
},
"exclude": ["node_modules"],
"extends": "./.svelte-kit/tsconfig.json",
}
Name: Berberoast
Creation Date: 2023-09-18
This has literally saved my life you have no idea how happy I am to have found this page.