Server Side Rendering (SSR)

¿Qué es el server side rendering?

El Server Side Rendering (SSR), o Renderizado en el Lado del Servidor, es una técnica utilizada en el desarrollo web para mejorar la carga y la velocidad de las páginas. A diferencia del enfoque tradicional de Renderizado en el Lado del Cliente (CSR), donde el navegador descarga el código JavaScript y luego renderiza la página, con SSR, el servidor genera una versión completa de la página y la envía al navegador.

Esta técnica tiene ventajas significativas, como la mejora en el SEO, ya que los motores de búsqueda pueden indexar el contenido directamente. Además, el SSR proporciona una experiencia inicial más rápida para los usuarios, al mostrar contenido en pantalla de manera más rápida.

El Server Side Helper (SSH) de TRPC

El helper de TRPC permite hacer hydrate (prellenado) de los datos que TRPC va a consultar dentro de los componentes, antes de que estos sean requeridos a nivel del cliente.

  1. Abrimos la página del profile src/pages/[slug].tsx y vamos a agregar la función getStaticProps para que los datos sean procesados y enviados con la primera petición de la página.

    import { createServerSideHelpers } from '@trpc/react-query/server'
    import type { GetStaticPropsContext } from 'next'
    import SuperJSON from 'superjson'
    import { appRouter } from '../server/api/root'
    import { prisma } from '../server/db'
    
    // ...
    
    export async function getStaticProps(
        context: GetStaticPropsContext<{ slug: string }>
    ) {
        // inicializar un helper
        const helpers = createServerSideHelpers({
            router: appRouter, // incluir el appRouter
            ctx: { prisma: prisma, userId: '' }, // valores del context
            transformer: SuperJSON, // utilizamos SuperJSON como parser
        })
    
        // obtener el slug desde el path
        const slug = context.params?.slug
    
        if (!slug) {
            throw new Error('No se especificó el slug')
        }
    
        // el slug debe iniciar con un @ seguido entre 3 y 12 caracteres de alfanuméricos
        if (!slug.match(/^@?[a-z0-9]{3,12}$/)) {
            throw new Error('Invalid slug')
        }
    
        // eliminar el arroba del inicio del username
        const username = slug.replace(/^@/, '')
    
        // realizar la lectura previa de los registros requeridos
        await helpers.profile.getUserByUsername.prefetch({ username: username })
    
        return {
            props: {
                // este parse es requerido para evitar un error actual de parseo de SuperJSON
                trpcState: JSON.parse(
                    JSON.stringify(helpers.dehydrate())
                ) as Record<string, unknown>,
                // exportar el username
                username: username,
            },
            revalidate: 1,
        }
    }
    
  2. Agregamos la función getStaticPaths para indicar los paths que van a ser considerados por la función getStaticProps, pero en este caso como aplica para todas las rutas el arreglo se especifica en blanco.

    import type { GetStaticPaths } from 'next'
    
    // ...
    
    export const getStaticPaths: GetStaticPaths = () => {
        return {
            paths: [],
            fallback: 'blocking',
        }
    }
    
  3. Actualizamos el componente PageProps para que realice la consulta.

    import type { InferGetServerSidePropsType } from 'next'
    import Head from 'next/head'
    import { LoadingPage } from '../components/loading'
    import { api } from '../utils/api'
    
    type PageProps = InferGetServerSidePropsType<typeof getStaticProps>
    
    export default function ProfilePage(props: PageProps) {
        const { data, isLoading } = api.profile.getUserByUsername.useQuery({
            username: props.username,
        })
    
        if (isLoading) {
            return <LoadingPage />
        }
    
        if (!data) {
            return <div>Not Found</div>
        }
    
        return (
            <>
                <Head>
                    <title>Profile Page</title>
                </Head>
                <main className="flex h-screen justify-center">
                    <div>
                        <div>User: {data.username}</div>
                        <div>Email: {data.emailAddresses[0]?.emailAddress}</div>
                    </div>
                </main>
            </>
        )
    }
    

    Cuando se realice el despliegue de la página nos podremos dar cuenta que la precarga no iniciara, esto debido a que los datos estarán precargados para mostrarse.

  4. Refrescamos la página y vamos a darnos cuenta que ahora esta mostrando el username y la dirección de correo electrónico obtenida desde Clerk y rendereada directamente desde el servidor.

En esta lección hemos podido utilizar Server Side Rendering utilizando el helper createServerSideHelpers, este nos ha permitido incluirlo dentro de la función getStaticProps de NextJS, para poder echar mano de manera correcta del rendereo del lado del servidor.