vue.jsnuxt.jsserver-side-rendering

Fetching data with nuxt - direct vs. proxy access


I'm a Vue developer building SPAs but new in the Nuxt universe with SSR. I have now familiarised myself with the subject and I know some patterns. However, my thoughts revolve around some best practices with SSR and data fetching.

Given is an SPA using supabase as a backend. Developing clientside only is easy, I have to fetch all my data from the supabase rest api via the client.

Now Nuxt is introducing an additional layer with its nitro server and api server routes. Here I'm struggling where I should put my code and which api client i should use. For clarification I give you an example:


The app is a standard recipe app. Lets say the Homepage is displaying a list of recipes. For an clientsideonly SPA I'll fetch the data using supabase-js lib inside my Homepage.vue.

<script setup lang="ts">
    await supabase.from('recipes').select(...)
</script>

As I understand, if I now want to use SSR I need to fetch the data with the nuxt composables $fetch/useFetch/useAsyncData.

<script setup lang="ts">
    useFetch("$supabase-server/api/recipes")
</script>

I cannot use the supabase-js lib anymore.

To solve this problem I could proxy this request using the nitro-server:

// server/api/recipes.
export default defineEventHandler(async (event): Promise<Recipe | null> => {
   ...
   await supabase.from('recipes').select(...)
   ...
})

And then it is possible in the Homepage.vue to use the nuxt composables for fetching again.

<script setup lang="ts">
    useFetch("$nitro-server/api/recipes")
</script>

So problem solved? Not at all. After the initial request and rendering I need to fetch data from the clientside again. And here is my knots in the head.

Whats best practice? Or is the answer as usual: "It depends"?


For a better understanding I drawed a little picture: enter image description here


Solution

  • To avoid the fetching twice problem you can use useAsyncData.

    <script setup lang="ts">
        const { data } = useAsyncData(async () => {
            return await supabase.from('recipes').select(...)
        }
    </script>
    

    When run in SSR this will serialize the response in the returned HTML and the client-side hydration will deserialize it rather than re-sending the request. If the page is navigated to through a client-side navigation the request will be sent from the browser.

    In this case I don't think you need to worry about proxying. Proxying is useful if your SDK is node-only, if there are tokens or code you want to keep private or if you want to exclude the SDK from your client-side bundle. But if you were fine with using the supabase SDK from the client before, there's no need to change that.