How can I populate HTML on the server with db data before sending it to the client
Hello - i am new to solidstart and today as I was attempting to port a nextjs app into solidstart I was confused as to how I am supposed to handle data fetching in a page route.
I need to render a page for my users on the server.
In my specific use case I need some session data in combination with a call to the database. I used the middleware to verify a user is logged in and store the sessiondata into the 'locals' variable which I can access inside routes - but i still haven't found out how to make my async db call to work.
I am using the 'isServer' var to run the db call only on the server but The routes themselves are synchronous so I cannot use await there, and when I use createReousrce I get no result on my page. (I know i can use an API call from the client or a server action but that is not the functionality I need)
19 Replies
I haven't touched SolidStart but it seems that the problem is in that createResource is asyncronous and you need to put the result to createEffect to catch the result once it has come
For example
Or you can just handle responseData within JSX because JSX is an Effect itself
Figured out how to do it - and it works like below- but now i have another issue -> that being When I navigate to the /profile route via a button I get an empty page.. when I refresh, or use the url bar to navigate to /profile it works as expected. ( i use the <A> tag to navigate - and i can't understand why this happens 😦
My data also populates the page on refresh
You now have converted your data to a "server-only" resource, afaict. Your whole resource fetcher is wrapped in
if (isServer)
so on client-side navigation this whole block will not execute.
Easy way from here is assume that a User is logged in and do the fetch also if (!isServer)
If I don't use the 'isServer' the code executes in both client and server which is not the behavior I need. I want to query the db - build the page and ship it as html. How can I achieve this?
You can use
routeData
with createServerData$
This is a callback that will only execute on the server.
Keep in mind that SSR only applies for your first page-load. After that everything will switch to CSR (client-side rendering) since the internal processes will take over after the initial hydration.This does a post request to fetch the data, I need the data to render on the server and be sent as html.
Is there any reason why you need the HTML specifically?
If the page is SSRed, then the
server$
callback will be called on the server and used to populate the HTML on the server.It matches the usecase of the app I am trying to port from NextJS (one call to fetch the html instead of 2 for html+data)
I selected SSR in the initialization options (althought it doesn't state anything about it in the vite config i believe that it is because its true by default) -> the server$ from what I saw does a post request fetching the data and I want to avoid having extra requests when the data doesn't require reactivity
It seems like such a simple task I am ashamed to admit I can't figure out how to make it work
The post request should only be made if you're accessing the data in CSR afaik
Like if you're calling the server$ callback in SSR, no extra request should get made
The better approach is probably using
routeData
with createServerData$
because that'll fetch the data in parallel to your route loading even if you navigate to the page on the clientAlright I made a bit of progress thanks to your input. The behaviour is as you described (if i navigate directly to /profile I get the page without any additional request made which is what i want ) but the data still gets fetched via post if I navigate to the same /profile route using a link. To be more specific, if i navigate using <a> it works as expected but page fully reloads , on the other hand using <A> a post request is sent
Is there a way to specify that I need the data only as html and resolve all resources before sending it to the client?
I paste my code below if it helps (maybe I did something different than what you described)
When you navigate through an <A> tag, the navigation happens completely on the client so the server doesn't typically do anything at all. The post request is just getting that data and only that data from the server to the client, so sending HTML isn't really necessary here
So no resources are resolved on the server when you make navigations after the initial page load
You are correct - I falsely assumed you were getting back a document on each route..
So essentially the server sends the entire app on the initial load and then the client takes over (working as a CSR from then on?)
Yep, exactly :)
Although the server doesn't usually send the entire app
Route are generally code split
So, when you navigate to a route in CSR, the javascript required for that route to work is loaded
Using routeData means that your data fetching happens in parallel to this javascript loading, so you don't get long waterfalls
Alright from what I can tell - navigating from / to /profile atm gets me this
routeData being the slowest to arrive since it first fetches the tsx and then does the post request
profile.tsx
and your routeData look like they start being fetched at the same time
The delay before your routeData arrives is probably just delay from communicating with the databaseOk so basically me changing into what I want will basically have no real effect since it fetches both document and data at the same time and instead of merging them at the server it does so in the client right?
There are no document fetches
The profile fetch is the javascript for your profile page
So the server doesn't generate any HTML here
You want as much to happen on the client as possible for subsequent navigations because round trips to the server are expensive
And the profile page javascript can be cached
Alright I see - so it's fine as it is now - Thanks a lot for taking the time to explain & walk me through this
np :)