Open janopae opened 4 weeks ago
Update: It seems like this also stops the build process, not just the dev server.
Is there really no way to only target a browser if that's the only place your code is going to run in?
please provide a link to a repository with a complete and minimal reproduction. You mention a custom adapter and the filename you use layout.ts
is missing the +
at the start.
My apologies – the custom adapter and the missing +
were both a mistake. I use a custom adapter in the app I develop, but I could reproduce this with adapter-static
.
I created a repository to reproduce the problem: https://github.com/janopae/reproduce-sveltekit-tries-to-run-ssr-code-even-with-ssr-disabled
It seems like SvelteKit has to execute the +layout.ts
, otherwise it wouldn't even know that SSR is disabled.
So we need either another way to add layout code that won't be used at compile time to determine wether SSR is enabled (would be a weird twist on the naming of the file), or we need a way to disable SSR from the begin with (e. g. in the svelte.config.js
).
you can't use localStorage in +layout.ts without an if(browser) guard, spa mode or not.
also you have to put code in exported functions, not top level.
Im pretty sure your code works IF you put it inside a load function. The file has to be evaluated so sk can read the ssr setting but if SSR is off, the load function is not executed on the server.
Alright. I think this is an unexpected gotcha that could be avoided with a general ssr
switch in the svelte.config.js
, which would turn this issue into a feature request. But if there are reasons I don't know about why we can't have a switch in the top level configuration and you think it should stay this way, feel free to close this issue.
Personally, I reconsidered the use of SvelteKit for my use case, as there have been too many gotchas that took me a lot of time to resolve, and they keep coming, mostly relating to disabling SSR:
+layout.{ts|js}
) – this might create some "time bombs", when library code (both npm and self-written one in the lib
directory) uses browser API behind the scenes, maybe just under certain conditions (this is basically the problem imposed by this issue, but also that one: https://github.com/sveltejs/kit/issues/11310)Especially, developing a browser extension using sk seems impossible at the moment, because both prerendered and "fallback" routing code can only be executed with the CSP setting "unsafe-inline"
, which can't be enabled for browser extensions (https://github.com/sveltejs/kit/issues/11009).
I'd love to see the SvelteKit homege communicating its focus on deployments with a node server, as currently, the website presents SvelteKit as "super flexible" and especially mentions SPAs without node backends as a use case.
Thanks for the thorough overview @janopae. I'm early on my SPA journey with SvelteKit, and you point out some gotchas I have yet to hit.
I personally didn't reach for SvelteKit for the "typical" reasons. I wanted to use Svelte to create a client application, but there simply aren't viable CSR routers for Svelte other than SvelteKit. My use case is building a local-first application that relies on SQLite in the browser, and I use +page.ts
files to execute queries against this database before displaying the page. Obviously, this cannot run in a server context. I managed to get this working client-side with a browser
guard in front of my database object, but I do worry how brittle this could get overtime.
Personally, I expected a +page.client.ts
file that mirrors the format of +page.server.ts
. It seems odd that you can create a server-side loader and a "universal" loader but not a client loader. This reflects the vibe I got trying to build an SPA: the authors do not believe client SPAs are a good practice, so the experience is second-rate. I'm hoping new architectures like local-first prove where client-side applications are a good idea.
Personally, I expected a
+page.client.ts
file that mirrors the format of+page.server.ts
. It seems odd that you can create a server-side loader and a "universal" loader but not a client loader.
I think it makes sense to not have the +page.client.ts
- if you're using SSR, only running on the client could cause hydration issues, and if you're CSR, it doesn't matter. However, I do agree that SvelteKit importing / evaluating +page.ts
files on the "server" when SSR is disabled is annoying.
I've felt the pain of that myself plenty of times when building client-side apps, and I understand the frustration when considering past comments denouncing SPAs. However, we want SvelteKit to be the best tool for the job, even for SPAs!
there simply aren't viable CSR routers for Svelte other than SvelteKit
There are other options such as Routify, and numerous other declarative ones available. Routify v2 specifically should work just fine if you're using Svelte 3/4
Funny, @Rich-Harris spoke on this exact in a recent interview!
But, you know, amongst that, I at least am definitely thinking about what are the ideal integration points between the rendering framework and the data if the data exists in this sort of local first context.
@ghostdevv Appreciate the thorough response here!
I do agree that SvelteKit importing / evaluating +page.ts files on the "server" when SSR is disabled is annoying.
Yeah that's all I'm getting at. I totally agree that +page.client.ts
isn't a nice API. My understanding is that +page.ts
must be executed at build-time to read the export const ssr
flag, specifically for dynamic values like export const ssr = import.meta.env.DEV
. My suggestion of +page.client.ts
was to find some way to avoid server-side evaluation of these files entirely.
Also have a suggestion from maintaining Astro: it may help to remove dynamic value support for export const ssr
so exports can be traced with an export crawler, without executing the file to determine the value. This was our approach for our prerender
flag.
And I appreciate those links to community routers! I just prefer to use solutions that are first-party maintained and have a diverse contributor graph. I hadn't noticed the latest Routify v3 release though. May be worth a second look! In a perfect world, I'd use a SPA router within Astro ;)
Thanks for pointing this out guys. I think it's an important issue, so added it to the SvelteKit 3 milestone to make sure we take a look at what can be done better here. I've heard at least a few options:
ssr = false
in their layout file and that's it. We could during build add values that can be determined statically or are undeterminable to the ssr manifestThis is important as many people build SPAs in order to support things like capacitor and tauri and want to be able to directly reach for browser-only APIs without having to add if (browser)
checks since they know their app will never have to run on a server
Describe the bug
Even though I did everything the docs provide in order to disable any form of server side rendering or static site generation, the dev server tries to execute my code on the server.
Reproduction
Edit
src/routes/+layout.ts
according to https://kit.svelte.dev/docs/single-page-appsEdit
svelte.config.js
according to https://kit.svelte.dev/docs/single-page-apps#usageCreate some code that will only work on client side
Start the dev server
Open the website in browser, and there will be an error complaining about
localStorage
not being definded.Logs
No response
System Info
Severity
serious, but I can work around it
Additional Information
No response