Svelte5 might change things all of this is based on svelte4

Gotchas/FAQ

Combinations

SSRPre-renderstatic-adpterother-adapter
SPA--YES-
Mixed SPA-YES(some)+fallbackYES-
HydrationYES--YES
Mixed HydrationYESYES(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.
  • Full Static Site Generation
    • Use adapter-static (Skips any +server.js related stuff)
  • 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)

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)
  • 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 and prerendering
  • 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 server
  • adapter-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
  • src/routes
  • src/service-worker

Components

  • Components need not just be *.svelte file, it can be a directory with an index.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.

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>)
  • 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)
    • +error.svelte: Page to show if +page.ts’s load 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)
    • +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
  • Dynamic routing

    • Priority of routes is basically more specific route name wins
    • We’d want to use matchers from src/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 inside src/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

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 as div or button etc. Then you can use on:click on the main component 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 passing on:click there and things should work.

*.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.

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.
      • WAY2:
        • I don’t really understand this properly but this is around passing the db object from src/hook.ts to event.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 the handle 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.

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

  • Files we have
    • We have +layout.svelte|ts|js
    • We have +page.svelte|ts|js
  • In these files, the variables are not shared unless you use a load function and then use export 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

Loading data

  • Sveltekit has a whole page on loading data, check that
  • The load method has a special fetch function which is enhanced version of the normal fetch api method.

Store in Svelte

  • Types
    • Readable
    • Writable
    • Derived

State Management in Svelte

What’s the combo of connect-es, transtackQuery, svelteStore and PageLoad? (when we don’t want Selvekit backend features)

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 in contexts. 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 use context and derived 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 use setMessage. so setMessage for everything.

Tips

TODO My svelte no-scroll app template

  • This is pretty annoying and has killed lot of my time in the past

Design Patterns for Svelte

Data heavy website