Tilbake

Introduksjon til NextJs

Av Sondre Slåttedal HavellenPublisert 15/6-22

Hva er NextJs

NextJs er et rammeverk for å bygge raske statisk-genererte og serverside-genererte webapplikasjoner med React. Rammeverket er utviklet og vedlikeholdt som et åpen-kildekode løsning med Vercel som lead.

Hvorfor

I en vanlig React-app så starter man gjerne med en tom HTML-side og legger til React som en JS-skript for å rendre siden og alle interaksjoner. I NextJs derimot bruker man spesielle funksjoner for å generere HTML før det når en nettleser. Med dette får man raskere nettsider (statiskgenererte sider har en drøss med optimiseringer som ikke er mulig i vanlig React) og bedre SEO da all tekst og informasjon er tilgjengelig on-demand. Utover det kan man skrive en helt vanlig React-app med NextJs, dvs. NextJs dekker så og si alle use-caer som vanlig React gjør.

NextJs-applikasjoner kjøres på en Node-server og krever litt spesielt oppsett for å distribueres. I en vanlig React-app trenger man gjerne bare en index-fil (og kanskje script om man ikke embedder), mens her trenger man en spesiell Node-server. Serveren sørger for at en kan prefetche data før det når brukeren og står for Incremental Static Generation om en skal rehydrere siden.

Begreper

  • Static Site Generation - En React-side blir prerendret ved bygg-tid og kan serves til bruker som vanlig HTML. En SSG-side vil typisk være lik for alle brukere.
  • Server Side Render - En React-side blir generert on demand og kan bli skreddersydd for en egen bruker. Dette er nyttig for innloggede sider eller søkesider (basert på SSR som for eksempel /posts på denne siden)
  • Incremental Static Regeneration - En SSG-side kan med jevne mellomrom regenereres. Dette gjør at en side som har vært bygget kan oppdateres med nytt innhold. Regenerering fungerer ved at en side har et revaliderings-parameter som sier noe om når en skal sjekke for nytt innhold. Hvis timeren har gått ut hentes ny data fra API mens den gamle sendes til bruker. Ved neste request vil siden da inneholde siste informasjon.
  • Client-Side Rendering - Dette er det som typisk er brukt ved vanlige React-applikasjoner. Helt standard client-side rendering er fint mulig med NextJs, men det er ønskelig å bruke SSG så langt det lar seg gjøre. Med CSR kan en for eksempel ikke kjøre siden uten Javascript og en må ofte belage seg på spinnere og "sent innhold".

SSR og SSG

Et eksempel på et oppsett for en helt standard SSG-side kan se slik ut.

1import {GetStaticPropsContext, InferGetServerSidePropsType} from "next";
2
3export const getStaticProps = async (context: GetStaticPropsContext) => {
4
5  const data = await fetch("example.com")
6  
7  return {
8    props: {
9      data
10    },
11    revalidate: 60
12  }
13};
14
15
16export default function (props: InferGetServerSidePropsType<typeof getStaticProps>) {
17  return (<pre>
18    {JSON.stringify(props.data, undefined, 4)}
19  </pre>)
20}

Her henter vi data fra et API og render ut innholdet i siden. Denne siden vil fungere uten JS når en bruker henter den fordi innholdet allerede er pre-generert. getStaticProps kjøres bare ved ISA (ved bygg eller ved regenerering). Innholdet bruker mottar er cachet ved hver brukerrequest.

En SSR-side kan se slik ut.

1import {GetServerSidePropsContext, InferGetServerSidePropsType,} from "next";
2
3export const getServerSideProps = async (
4  context: GetServerSidePropsContext
5) => {
6  /* I context har du tilgang på headere (hvis en for eksempel trenger auth) og query-params */
7
8  const query = context.query.search;
9
10  const data = await fetch(`example.com/search?searchString=${query}`, {
11    headers: { authorization: context.req.headers.authorization },
12  });
13
14  return {
15    props: { data },
16  };
17};
18
19export default function (
20  props: InferGetServerSidePropsType<typeof getServerSideProps>
21) {
22  return <pre>{JSON.stringify(props.data, undefined, 4)}</pre>;
23}
24

Her har en tilgang til headers og query params. For hver request vil getServerSideProps kjøre.

Det som gjør at NextJs vet om det er SSR eller SSG er hvilken av disse to funksjonene som er inkludert. I tillegg til disse er det en default-eksport. Her definerest JSX-en og det brukeren til slutt ser. Ved SSG/SSR kjøres denne JSX-en med props fra tilhørende funksjoner. Det første resultatet lagres som HTML og gis til bruker.

Statiske stier og filstruktur

Routingen i en NextJs-app er avhengig av filstrukturen i kodebasen. Det en typisk gjør er å opprette en pages-mappe som inneholder enten index-filer eller navngitte filer og mapper. I tillegg har en dynamiske SSG-sider på formen [id].tsx , [...id].tsx eller [[...id]].tsx. Disse krever en spesiell funksjon som heter getStaticPaths. NextJs bruker denne til å hente ut et sett med stier for SSG. Eksempel kan man se under

1import { GetStaticPathsContext, GetStaticPathsResult } from "next";
2import { ParsedUrlQuery } from "querystring";
3
4interface StaticPathType extends ParsedUrlQuery {
5  id: string;
6}
7export const getStaticPaths = async (
8  context: GetStaticPathsContext
9): Promise<GetStaticPathsResult<StaticPathType>> => {
10  const paths = await fetch<{ id: string }[]>(`example.com/paths`);
11
12  return {
13    paths: paths.map(({ id }) => ({ params: { id } })),
14    fallback: "blocking",
15  };
16};
17

Denne funksjonen kjøres bare ved byggtid (mulig jeg tar feil her). blocking gjør at hver id som ikke finnes vil bli sendt til getStaticProps allikevel og man kan generere nye sider on-demand.

Det som er verdt å merke seg er at mapper også kan være dynamiske - gitt at de har en index.tsx under seg med getStaticProps.

NextJs hosting

NextJs må kjøres via en spesiell node-server - eller hver statiske side kan bli eksportert ut og serves som helt standard HTML. Man kan enten sette opp dette selv via npm run build && npm start eller bruke en tjeneste som Vercel. Vercel er etter min erfaring veldig bra for NextJs da det kan kobles rett mot Github og fungerer relativt sømløst. Denne siden er for eksempel det.