Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get values from SvelteKit's $app/stores outside of the lifecycle of a component

My Svelte components import readable stores like this:

import { classes, locations, schedule } from 'stores.ts'

In stores.ts, I want to build the URL for fetch dynamically using page.host from $app/stores.

// Note: this is not a Svelte component; it's stores.ts
import { readable } from 'svelte/store'
import { getStores } from '$app/stores'
const { page } = getStores()
let FQDN
page.subscribe(({ host }) => {
  FQDN = host
})

const getArray = async (url) => {
  const response: Response = await fetch(url)
  if (!response.ok) throw new Error(`Bad response trying to retrieve from ${url}.`)
  return await response.json()
}

const getReadableStore = (url: string) => readable([], set => {
  getArray(`http://${FQDN}${url}`)
    .then(set)
    .catch(err => console.error('Failed API call:', err))
  return () => {}
})

export const classes = getReadableStore('/api/class/public.json')
export const locations = getReadableStore('/api/location/public.json')
export const schedule = getReadableStore('/api/schedule/public.json')

The sixth line throws this error...

Error: Function called outside component initialization at get_current_component (/Users/nates/dev/shy-svelte/node_modules/svelte/internal/index.js:652:15) at Proxy.getContext (/Users/nates/dev/shy-svelte/node_modules/svelte/internal/index.js:685:12) at Module.getStores (/.svelte-kit/dev/runtime/app/stores.js:17:26) at eval (/src/stores.ts:6:38) at instantiateModule (/Users/nates/dev/shy-svelte/node_modules/@sveltejs/kit/node_modules/vite/dist/node/chunks/dep-e9a16784.js:68197:166)

Two questions...

  1. What is the correct way to get page values from $app/stores outside of the context of a component? Is this possible? Answer from below: No, this is not possible outside the context of a component.
  2. If I'm accessing a SvelteKit site, let's say http://localhost:3000/something or https://example.com and a Svelte component loads a readable store from stores.ts, is there a way in stores.ts to determine whether the original page request that loaded the component (which loaded from stores.ts) was http or https? Answer from below: No, this is not possible in stores.ts - only from a component.

UPDATE: Based on the feedback, I'm going to set a value in my .env called VITE_WEB_URL=http://localhost:3000 and change it for the production system. This cuts down on the number of lines of code and may be a better practice (comments welcome)...

// revised stores.ts
import { readable } from 'svelte/store'

const { VITE_WEB_URL } = import.meta.env

const getArray = async (url) => {
  const response: Response = await fetch(url)
  if (!response.ok) throw new Error(`Bad response trying to retrieve from ${url}.`)
  return await response.json()
}

const getReadableStore = (url: string) => readable([], set => {
  getArray(`${VITE_WEB_URL}${url}`)
    .then(set)
    .catch(err => console.error('Failed API call:', err))
  return () => {}
})

export const classes = getReadableStore('/api/class/public.json')
export const locations = getReadableStore('/api/location/public.json')
export const schedule = getReadableStore('/api/schedule/public.json')
like image 440
nstuyvesant Avatar asked Dec 20 '25 20:12

nstuyvesant


1 Answers

  1. Extract from https://kit.svelte.dev/docs#modules-$app-stores

Because of that, the stores are not free-floating objects: they must be accessed during component initialisation, like anything else that would be accessed with getContext.

  1. Therefore, since the readable store is bound to the context of a svelte component, I suggest you subscribe either way ($ or .subscribe) inside the component of the SvelteKit website and then send the protocol value (http or https) as parameter when it updates so that stores.ts stores it in a variable.

However, it looks like SvelteKit does not provide the protocol value, so parse the client side window.location.href in the page subscription and then send it.

like image 56
Alexandre Du Lorier Avatar answered Dec 24 '25 11:12

Alexandre Du Lorier