diff --git a/.changeset/gentle-years-leave.md b/.changeset/gentle-years-leave.md new file mode 100644 index 000000000000..9b512b8dce33 --- /dev/null +++ b/.changeset/gentle-years-leave.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +Allow `$app/stores` to be used from anywhere on the browser diff --git a/packages/kit/src/core/sync/write_root.js b/packages/kit/src/core/sync/write_root.js index c71e30f5b9d4..0dd8536bdd37 100644 --- a/packages/kit/src/core/sync/write_root.js +++ b/packages/kit/src/core/sync/write_root.js @@ -43,6 +43,7 @@ export function write_root(manifest_data, output) { + +

{pathname}

+ + diff --git a/packages/kit/test/apps/basics/test/client.test.js b/packages/kit/test/apps/basics/test/client.test.js index 05be5cf424ec..f95a9568de7c 100644 --- a/packages/kit/test/apps/basics/test/client.test.js +++ b/packages/kit/test/apps/basics/test/client.test.js @@ -585,3 +585,10 @@ test('Can use browser-only global on client-only page', async ({ page, read_erro await expect(page.locator('p')).toHaveText('Works'); expect(read_errors('/no-ssr/browser-only-global')).toBe(undefined); }); + +test('can use $app/stores from anywhere on client', async ({ page }) => { + await page.goto('/store/client-access'); + await expect(page.locator('h1')).toHaveText('undefined'); + await page.click('button'); + await expect(page.locator('h1')).toHaveText('/store/client-access'); +}); diff --git a/packages/kit/types/ambient.d.ts b/packages/kit/types/ambient.d.ts index 25981f86bb25..678de3ebe48d 100644 --- a/packages/kit/types/ambient.d.ts +++ b/packages/kit/types/ambient.d.ts @@ -216,24 +216,16 @@ declare module '$app/paths' { * import { getStores, navigating, page, updated } from '$app/stores'; * ``` * - * Stores are _contextual_ — they are added to the [context](https://svelte.dev/tutorial/context-api) of your root component. This means that `page` is unique to each request on the server, rather than shared between multiple requests handled by the same server simultaneously. + * Stores on the server are _contextual_ — they are added to the [context](https://svelte.dev/tutorial/context-api) of your root component. This means that `page` is unique to each request, rather than shared between multiple requests handled by the same server simultaneously. * * Because of that, you must subscribe to the stores during component initialization (which happens automatically if you reference the store value, e.g. as `$page`, in a component) before you can use them. + * + * In the browser, we don't need to worry about this, and stores can be accessed from anywhere. Code that will only ever run on the browser can refer to (or subscribe to) any of these stores at any time. */ declare module '$app/stores' { import { Readable } from 'svelte/store'; import { Navigation, Page } from '@sveltejs/kit'; - /** - * A convenience function around `getContext`. Must be called during component initialization. - * Only use this if you need to defer store subscription until after the component has mounted, for some reason. - */ - export function getStores(): { - navigating: typeof navigating; - page: typeof page; - updated: typeof updated; - }; - /** * A readable store whose value contains page data. */ @@ -248,6 +240,16 @@ declare module '$app/stores' { * A readable store whose initial value is `false`. If [`version.pollInterval`](https://kit.svelte.dev/docs/configuration#version) is a non-zero value, SvelteKit will poll for new versions of the app and update the store value to `true` when it detects one. `updated.check()` will force an immediate check, regardless of polling. */ export const updated: Readable & { check: () => boolean }; + + /** + * A function that returns all of the contextual stores. On the server, this must be called during component initialization. + * Only use this if you need to defer store subscription until after the component has mounted, for some reason. + */ + export function getStores(): { + navigating: typeof navigating; + page: typeof page; + updated: typeof updated; + }; } /**