Svelte5 might change things all of this is based on svelte4
Gotchas/FAQ
Combinations
SSR | Pre-render | static-adpter | other-adapter | |
---|---|---|---|---|
SPA | - | - | YES | - |
Mixed SPA | - | YES(some)+fallback | YES | - |
Hydration | YES | - | - | YES |
Mixed Hydration | YES | YES(some) | - | YES |
SSG | - | YES(all) | YES | - |
- Some pages prerendered, some dynamic
- Use any adapter here and then use
export const prerender
as per need per page.
- Use any adapter here and then use
- Full Static Site Generation
- Use
adapter-static
(Skips any+server.js
related stuff)
- Use
- SPA
- Use
adapter-static
- Disable prerender (Use
svelte fallback
) - Disable SSR (When ssr is disabled, its SPA mode)
- We can still pre-render individual pages (enable ssr and prerender on those pages)
- Use
About Pre-rendering
- Prerendering means that when we deploy our website, all the
+page/+layout files
javascript is compiled and executed and the resulting static HTML pages are saved.- i.e
page load
functions will be executed and baked into the generated page - Can be used along with
ssr
(altogether or on page-by-page basis)
- i.e
- The way prerender works is that it crawls all your rendered pages for links so it can pre-render them all.
- To tell sveltekit where to find links you that you may not have linked on your pages you should use
entries
When prerender vs ssr?
- Some pages only have static content, or they fetch content that changes very little over time.
- If the page keeps on changing we want to be using ssr. (But we don’t want to be using sveltekit backend, so we mostly don’t want ssr)
Hydration
- Interactive javascript is separate from
SSR
andprerendering
- Hydration happens when you’re using SSR
- Term used for loading interactive javascript on your page is
hydration
- Happens in the browser and after the page is all rendered
- Once the components are fully hydrated, they can react to changes to their properties just like any newly created Svelte component.
SSR & Static Adapter in Svelte
npm run build
will build both server and client component if you don’t use this adapter
Svelte adapters
- You apply the adapter in
svelte.config.js
- Adapters are for production/deployment
- When you use local dev with npm dev, you’re doing SSR anyway
adapter-node
runs SSR on a Node serveradapter-netlify
runs SSR in Netlify functions
adapter-static
export const prerender = false;
export const ssr = false;
- Prerendered routes
- We can route to known, prerendered routes
- Has associated
.html
file that represents the HTML content for that route. - pre-renders results from any
load()
calls at build time
- Dynamic routes
- We can route to unknown, dynamic routes
Reactivity
$ symbol
$
: accessing reactive value$:
reactive statement$$
$$
doesn’t indicate that this is a store value; it’s just a naming convention.
- See [The many meanings of -meanings/)
SvelteKit routing directory structure
General directories
src/hooks*
src/lib
src/params
- For storing matchers
src/routes
src/service-worker
Components
- Components need not just be
*.svelte
file, it can be a directory with anindex.ts
and the<component>.svelte
and the index.ts file can be exporting the component - Global components will probably live in
/src/lib/components
- But we can have route->page specific components inside directory conventionally named
(components)
- i.e If components and modules are needed by multiple routes, it’s a good idea to put them in $lib.
- But we can have route->page specific components inside directory conventionally named
Structure
+
signifies a “route file”. Any other “files” (NOT directories!) inside a/src/route
directory are ignored by SvelteKit. So we can use custom files and use them in the+<>.svelte/ts
files. Eg. subcomponents/modules etc.- If you want to create directories inside
src/routes
and you want the directory to not appear in the path, then use(<directory name>)
- If you want to create directories inside
- there are
*.server.*
variants that we’re skipping here because not using atm - Root:
/src/routes
+page.svelte
: Page component+page.ts
- Data for page component, exports a
load
function - Can also be used to configure other behavior of how the page loads and such (prerender/ssr etc)
- Data for page component, exports a
+error.svelte
: Page to show if+page.ts
’sload
function fails- Static fallback error page:
src/error.html
, it’ll bubble up to this - Nested
+error.svelte
page will not show up though for that you’d have to use[...path]
like rest params (See advance routing)
- Static fallback error page:
+layout.svelte
- Layout that applies to every page
- Only needs to have
<slot>
+layout.ts
- Data loading using
load
function for+layout.svelte
- Child pages will automatically have this data
- Data loading using
-
Dynamic routing
- Priority of routes is basically more specific route name wins
- We’d want to use
matchers
fromsrc/params
as such:src/routes/archive/[page=integer]
/src/routes/something/[slug]
/[org]/[repo]/tree/[branch]/[...file]
this will allow for/sveltejs/kit/tree/main/documentation/docs/04-advanced-routing.md
, the parameters will be correct names and be available to the page.- Use
(<dir name>)
if you want have a subsection of things insidesrc/routes
but don’t want it in the url. Eg. usecases- Eg.
(utils)
/(components)
directory - Eg.
(marketing)
/(app)
, just high level business level separation but these need to be in the same hierarchy in the URL but different+layout.svelte
- Eg.
About on:click
- I am unsure about this but seems like this sort of only works with primitive HTML elements
- Svelte allows you to forward things, but if suppose you want to
on:click
on a event as such, seems like we can’t do it directly, you need to “forward”.- What you need to do: Wrap the
component
around a primitive element such asdiv
orbutton
etc. Then you can useon:click
on the maincomponent
when using it and then when defining the component since you wrapped it around with a primitive element, you can use the forward mechanism by simply passingon:click
there and things should work.
- What you need to do: Wrap the
*.server.ts
API endpoints vs +server.ts
- They’re the same.
- API routes by adding a
+server.js
file that exports functions corresponding to HTTP methods: GET, PUT, POST, PATCH and DELETE.
+page.server.ts
vs +server.ts
+page.ts
- Load function associated with a page.
- Load data first, then hand it over to the page and render the page.
- If page is is visited as first page, load runs on the server. (IMPORTANT)
- If page is visited via client-side nav, load runs on the client. (IMPORTANT)
+page.server.ts
: Certain things are not suitable to be done in +page.js, e.g. accessing data from an API with a secret. Then you reach for this file and force execution of load to be always on the server (even during client-side nav). Can not only include load, but also form actions.+server.ts
: standalone API route. Not associated with a page. Think of implementing a mini API.
- Now the usecase of
+page.ts
vs+page.server.ts
is clear but when should we create a+server.ts
instead of+page.server.ts
is my confusion. - If we strictly need an api we go with
+server.ts
- If we need data loading for our page, we go with
+page.server.ts
- Some people are using combination where they create the endpoint and call the endpoint via
load
functions.- use
event.fetch
to call your API sveltekit server load won’t make a network request it will call the API route as a function. (IMPORTANT)
- use
- More resources on this
TODO Setting up DB connection
- https://kit.svelte.dev/docs/faq#how-do-i-use-x-with-sveltekit-how-do-i-setup-a-database
- https://github.com/sveltejs/kit/issues/1538#issuecomment-1002106271
- Steps
- Have a
$lib/db.ts
(singleton) which creates the pool and exposes a method to get connection from the pool. - Initialize it
src/hook.ts
, just have the global declaration. - Use
- WAY1:
- Use the method(get connection) from
$lib/db.ts
in either+server.ts
or+page.server.ts
load function.
- Use the method(get connection) from
- WAY2:
- I don’t really understand this properly but this is around passing the
db
object fromsrc/hook.ts
toevent.locals
- For
+server.ts
(API endpoint)- Initialize the db with a global variable, then pass the variable down to the Request object’s
locals
in thehandle
function. - Inside handle, I also have a trap to check if the db has been initialized (just in case), and if it isn’t reinitialize it.
- Initialize the db with a global variable, then pass the variable down to the Request object’s
- I don’t really understand this properly but this is around passing the
- WAY1:
- Have a
TODO Hooks?
- These kinds(3 kinds) of hook files run on startup
- These contain hook/handlers of certain pre-defind kinds. (See doc), these get triggerred when some other things happen. Eg. one common one is
handle
which is available in all 3 kinds, it runs when a request is received.
Hooks and locals
Auth and protecting pages
Concepts
Routing related files
- Files we have
- We have
+layout.svelte|ts|js
- We have
+page.svelte|ts|js
- We have
- In these files, the variables are not shared unless you use a
load
function and then useexport let data
in+page.svelte
Routing in Svelte
- We could use conditional components but using SvelteKit
- with
@sveltejs/adapter-static
- along with disabling SSR is much more straightforward
- with
Loading data
- Sveltekit has a whole page on loading data, check that
- The
load
method has a specialfetch
function which is enhanced version of the normalfetch
api method.
Store in Svelte
- Types
- Readable
- Writable
- Derived
State Management in Svelte
- See State Management Libraries for React Framework aswell
What’s the combo of connect-es, transtackQuery, svelteStore and PageLoad? (when we don’t want Selvekit backend features)
- If you’re using
connect-es
for Protocol Buffers, it has something called connectrpc/connect-query-es which branches of TanStackQuery- Issue is the svelte variant is not very well supported yet
- Because of which we’d want to use connect-web so that we can do rest api calls
TODO Overview
Using context
and store
together
- A store contains a value that can be subscribed to, and is thus reactive.
- A context makes a value accessible to a whole tree of components.
- context and store both are ideas and implementation in svelte
- context can be used usually in cases when you want to avoid prop drilling
- context are not reactive like stores
- So it’s a safe practice to pass around
stores
incontexts
. This seems to me like a solid combination.- i.e all components have access to the store, and can reactively use the value within it.
Other notes and tips
- When writing
store.ts
prefer using multiple stores and usecontext
andderived
stores to make better use of it. In addition, use factory pattern to create the stores. Eg.createXStore
const createXStore = () => { const { subscribe, set, update } = writable([]); return { // NOTE: A valid writable store requires atleast subscribe and set // NOTE: We could also wrap around set around another fn // eg. set: (newVal) => {doSomething(); set(newVal)} // NOTE: What "subscribe" returns is what you can call an unsubscribe with subscribe, set, // NOTE: Instead of directly using exposing "update" here we could also // have custom methods that use update. update }; };
+page.js
can’t use the$
(autosubscribe) shortcut to access the value from a writable store.- You’ll need to explicitly subscribe
- Make sure to unsubscribe if not using
$
- using
#await
: https://www.reddit.com/r/sveltejs/comments/124rx4n/sveltekit_when_to_use_load_vs_await/
Effect x Svelte
TheStockBroker
- Unfortunately I am not familiar with a live example, but fortunately svelte is pretty close-to-metal so integration would not be too demanding, basically just using a store or something to represent effects. There are 2 main ways to integrate effect into your application. As a logic engine, it holds the state, the actions, and context of your application. Or as a workflow executor, it only handles actions, you must handle the rest. Theres also the consideration on what exists servers-side and what is allowed to “leak” into the client side. All-in-all the latter version is simpler to work with but less powerful
- The former would requiring introducing effect-rx into the mix, which is rather advanced in concept. I can help you understand it but it’s non-trivial and builds on a lot of previous understanding
Forms
What we currently using
- svelte forms(base) + super forms(form state management) + formsnap(to avoid html boilerplate)
- Even though superforms has
setError
to show error, rather usesetMessage
. sosetMessage
for everything.
Tips
TODO My svelte no-scroll app template
- This is pretty annoying and has killed lot of my time in the past