Does anyone use nhost with nextjs SSR? I can't really find any examples on how to fetch on SSR so just curious if anyone could give me some feedback on my approach, or if they can suggest an alternative way of doing it
Last active 7 months ago
58 replies
14 views
- OS
Does anyone use nhost with nextjs SSR? I can't really find any examples on how to fetch on SSR so just curious if anyone could give me some feedback on my approach, or if they can suggest an alternative way of doing it
- OS
How I do it:
I've added export-prefix to nhost in_app.tsx
so I can use e.g.nhost.request
in other other files too.export const nhost = new NhostClient({ subdomain: process.env.NEXT_PUBLIC_NHOST_SUBDOMAIN, ...(process.env.NEXT_PUBLIC_NHOST_REGION && { region: process.env.NEXT_PUBLIC_NHOST_REGION, }), });
For each SSR-request I create an instance of client on the server, since this function requires a context.
export async function getServerSideProps(context) { const client = await createServerSideClient( process.env.NHOST_BACKEND_URL as string, context ); const { data, error } = await client.graphql.request( ...
- OS
I don't get why we need to pass the context, and I am considering replaceing
createServerSideClient
with_app.tsx/nhost
so that I only have one instance of the client on server too. - VE
This is how my code looks like
```export async function getStaticProps() {
const endpoint = "https://your-endpoint.nhost.run/v1/graphql";const headers = {
"x-hasura-admin-secret": process.env.HASURAJWTSECRET,
"content-type": "application/json",
};const graphqlQuery = {
operationName: "getallcourses",
query:query get_all_courses { ps_course { slug course_name course_thumbnail course_long_desc course_overview } }
,
variables: {},
};const options = {
method: "POST",
headers: headers,
body: JSON.stringify(graphqlQuery),
};const response = await fetch(endpoint, options);
const data = await response.json();const data2 = data.data.ps_course;
return {
props: { data2 },
};
}
``` - VE
Just change the static props to server side props
- OS
Does this mean that you don't need the @nhost/nextjs dependency?
- VE
yes
- VE
fetch() is enough
- OS
Can I ask how do you do in _app?
- OS
That is nice
- VE
the above code needs to be placed on index.js not _app.js
- VE
you can also call it from /api
- OS
Yes, but I also have a logged in state (admin-dashboard). So I utilize a wrapping AuthProvider in _app (based on official example)
- OS
I think that utilizes the @nhost/nextjs dep. too. So was just curious if you had an altarnative approach for that too
- OS
The logged in things will be client-side only
- VE
currently I am not using the NHost auth. instead I am using Clerk and using apollo client to fetch the client side daa
- OS
Ah, got it
- OS
I think I might get it to work tweaking your approach. Thanks! If it boosts performance I will go for this approach
- VE
👍
- VE
for realtime data, I am researching to use useSWR instead of subscriptions
- OS
I have played around a bit with useSWR some months ago but forgot alot about it. Do you have any specific reason for this or is it just a hunch? Is it maybe not possible to use Suspense with subscriptions for example?
- OS
To me they seem quite similar
- OS
and with subscriptions you could stay with minimal fetch-only approach
- EL
I would suggest looking into React Query instead of SWR. I think it has a better api.
- EL
https://github.com/nhost/nhost/tree/main/examples/codegen-react-query
- EL
@Venkata Penumatsa I'm having a tough time obtaining "logged in" state on the server-side… I've considered moving from nhost auth to clerk for this reason. Is that part of your use case?
- VE
Hello, Ellery.
I moved to Clerk because I am developing a learning management application and require advanced features such as session management and user device tracking, which are not immediately required but will be required as my application traffic grows. Also, because I am not skilled in front-end design, I do not want to spend my time building the Sign In/Sign Up/User Portal interfaces on my own. Also, with Clerk, the user object is freely available everywhere in the Next JS app, including CSR, SSR, and API routes, with middleware support on the way.
With the addition of NHOST JWT SECRET session variable editing, Clerk and NHost can now communicate via the jwk url. Thank you to the NHost development team for making this option available. As a solo developer, paying for Hasura Cloud is costly, and hosting Hasura on my own is risky because it requires little Dev Ops knowledge.
I hope this information is useful to you. Please let me know if you require any additional information.
- VE
In my LMS application, I am loading the index page and slug page as static pages as they load from the Vercel CDN fast. However, there are scenarios where I need to capture the data changes live (without page refresh) this is where the useSWR hook comes in handy to me. For example for a course when a new user is enrolled, I need to show the newly updated Enrollment count in both the index and slug pages. like this, I also need to capture the information of Feedback (Number of Reviews & Ratings, etc) these are the 2 use cases I am using the SWR hook, and also it's a lightweight dependency.
I'm doing this by invoking an API route from the client side using the fetcher function. That's all. It will continue to run behind the screen whenever the end-user is active on that particular page. It will track the most recent data and invalidate the browser cache only when necessary.
The reason I did not use subscriptions is that it maintains a continuous connection between the browser and the database, which I believe is fine with low traffic, but when we have a lot of traffic, I believe subscriptions will cause unnecessary network overhead (this is my personal guess), so I do not use subscriptions and instead use SWR hooks.
- OS
@ellery Have you tried to copy the whole examples/nextjs folder and connect it to your local nhost-cli? I did this because I had the same issue as you (nhostSession always being null) and wanted to confirm if it was indeed some issue with my local frontend setup. For some reason it works for me when I try their example, even though I feel like I did a very similar approach for my own setup. The main changes I did was in regards to their updated api (e.g. subdomains/region instead of backendUrl). I will further compare my setup with the example when I have time, but I'm putting this on hold. For me logged in is only for admins, so it doesn't matter that much if there is a bit of performance overhead.
- EL
> The main changes I did was in regards to their updated api (e.g. subdomains/region instead of backendUrl)
I think this could be the reason it doesn't work for you - EL
I don't think we've tested SSR with subdomain/region. Only backend url.
- OS
@elitan Just to clarify I still use backendUrl for getNhostSession. It is when I instantiate the client I use subdomain/region:
lib/nhost.tsx
:export default new NhostClient({ subdomain: process.env.NEXT_PUBLIC_NHOST_SUBDOMAIN, ...(process.env.NEXT_PUBLIC_NHOST_REGION && { region: process.env.NEXT_PUBLIC_NHOST_REGION, }), })
(I only apply region when such a variable exist)
In SSR i still use backendUrl,pages/admin.tsx
:const nhostSession = await getNhostSession( process.env.NHOST_BACKEND_URL, context );
For curiosity I tried:
export default new NhostClient({ backendUrl: "http://127.0.0.1:1337", })
and
const nhostSession = await getNhostSession("http://127.0.0.1:1337", context);
instead. But still always gives
null
. - OS
One other things that differs betweeen docs and the example is that the example does not have have a wrapping UserProvider. I tried to remove that (in _app.tsx) but also didn't fix :/
- EL
Hmm, would you mind creating an issue for this?
- EL
UserProvider
is not related to Nhost. It's just a custom React provider. - OS
Yes, I can when I have some extra time over. I want to see if I can reproduce it with a clean installation using a combination of the docs/example
- VE
Hi @oskery Regarding the SWR this is what I am mentioning previously
- OS
Beautiful! I understand your reasoning for using SWR now, and I think either SWR or react-query will be a huge improvement for high traffic.
- GU
Just as a clarification, the above video is not working with subscriptions/polling it's just fetching again. SWR fetches again for default when the user unfocuses the current window (goes to another window/page)
- EL
I dug into why getNhostSession was returning null in my other thread, and noticed it has to do with js-cookie returning null for the refreshToken cookie, even though I see the refreshToken data present in the headers. This is a huge blocker for me and I'm trying to hack a solution around it. I'll put in a ticket when I have some time
- EL
Thanks for providing context around your clerk.dev use case. My use case is much simpler (just need auth data in SSR) so I'm hoping I can get nhost auth to work since I've put a lot of effort into it.
- KR
@Venkata Penumatsa Maybe I don't see something but if you're already using apollo client, why do you need useSWR? Apollo client knows your graphql schema and it creates a normalized cache automatically on the client. This means if a data changes in the cache (e.g. due to a mutation which can return the updated value after the mutation), every component which uses that data (even if not in the same query) will re-render automatically (without an additional fetch).
- VE
Hi, Apollo does not perform automatic cache invalidation unless you explicitly instruct it to do so by writing some extra code and updating the cache, or by using the refetchQueries array inside the useMutation hook. This is also not in real-time. I mean, when you open a page and spend idle time on it, some data updates happen behind the scenes that you won't see unless you refresh the page. However, with the useSWR hook, every time you return to the browser window or make a mouse click, it will automatically execute the query and apply a delta between cache and query response and render only where there is a change.
- KR
What I meant is that you can write a mutation which returns the updated data like this.
mutation { update_tasks_by_pk(pk_columns:{id:"xxx"}, _set:{completed: true}) { returning { id completed } } }
Because of the
returning
part, apollo will automatically update its normalized cache so components using the updated task will re-render (if they use thecompleted
property of the task).As for the refetching: you can poll a query by adding
pollInterval
to the query properties. Or if you'd like to refetch when the window regains focus, you can add an event listener (or write a simple hook for this).The main benefit of apollo over useSWR/tanQuery is its normalized cache (which useSWR/tanQuery cannot do because they don't know the schema of your graph). This means that if you have a component which uses a query like this:
tasks {id, completed}
and another component which uses this:
user { id, name, tasks { id, completed } }
then if you receive a fragment inside a mutation OR a query response with __typename tasks (this one is added automatically to every query), an id and any other property, then the property will be updated in the local cache and every component will re-render without refetching their own query.
- VE
Let me dig a little deeper into this. Thank you for your insights.
- OS
So you mean that it is enough to include the attributes that we want updated as part of the
returning
-part of the graphql mutation and (if already used) they will be automagically updated (re-render with help of cache) in our interface/frontend? I did not know this was a thing, and caching is not my strongest suit. Thank you for the insight! - OS
I never understood why we were required to return in our mutations. I just did it to confirm changes
- VE
This is the exact confusion I had with
return
vsrefetchQueries
I need to test this once and see from my end - OS
Just before I do that, because this is Next.js related I think
- OS
I can access the image (and so can you I assume): https://klpwjtvaevwyulntbnui.nhost.run/v1/storage/files/aafaeca1-b09d-4798-9a60-fe8cc67cb869
- OS
But I'm getting error thrown from vercel
- OS
When trying to optiimze
- OS
It's weird because I use the same for my blurUrl and that actually works
- OS
but as soon as finished loading it gives me 400
- OS
Any idea? 😄
- OS
Actually, I think it might have to do with images domains (next.config.js)
- OS
Yey, it was that. Forgot I could test against my cloud backend locally. That way I got a clearer error message
- OS
So forget my rambling 🙂 Thank you for inspiring me to take/test a more minimal approach
Last active 7 months ago
58 replies
14 views