Remix ir Next.js: full-stack React

Kodėl visi staiga kalba apie Remix?

Jei sekate React ekosistemą, tikriausiai pastebėjote, kad pastaraisiais metais Remix tapo viena karščiausių temų. Ir tai ne be priežasties – šis framework’as iš tikrųjų atneša šviežio oro į full-stack React pasaulį, kuriame Next.js dominavo beveik neginčijamai. Bet ar Remix tikrai toks revoliucinis, kaip visi kalba? O gal tai tik dar vienas hype traukinys, kuris greitai praeis?

Pirmiausia, reikia suprasti, kad abi šios technologijos sprendžia panašias problemas – kaip sukurti greitą, SEO draugišką ir gerai veikiančią React aplikaciją su serverio pusės galimybėmis. Tačiau jų požiūriai į tai, kaip tai padaryti, gana skiriasi. Next.js yra brandus, gerai dokumentuotas ir turi didžiulę bendruomenę. Remix, nors ir jaunesnis, atneša naujų idėjų, ypač susijusių su duomenų valdymu ir formų apdorojimu.

Aš pats dirbu su abiem šiais framework’ais ir galiu pasakyti, kad pasirinkimas nėra toks paprastas, kaip „vienas geresnis už kitą”. Tai labiau priklauso nuo jūsų projekto specifikos, komandos patirties ir to, kokias problemas bandote išspręsti. Pabandykime išnarplioti, kuo jie skiriasi ir kada kurį verta rinktis.

Architektūros filosofija: fundamentalūs skirtumai

Next.js evoliucionavo per daugelį metų, ir tai matyti. Jis pradėjo kaip paprastas SSR (Server-Side Rendering) sprendimas, paskui pridėjo SSG (Static Site Generation), o dabar su App Router įvedė RSC (React Server Components). Tai reiškia, kad Next.js turi kelias skirtingas paradigmas, kurias galite naudoti viename projekte. Skamba gerai, bet kartais tai sukelia painiavą – ypač naujiems kūrėjams.

Remix nuo pat pradžių buvo sukurtas su aiškia vizija: grįžti prie web’o pagrindų. Jie labai akcentuoja standartines web platformos galimybes – formas, HTTP metodus, URL’us. Remix kūrėjai teigia, kad per daug metų React bendruomenė užmiršo, kaip gerai veikia paprasti HTML formos ir progressive enhancement principai.

Praktiškai tai reiškia, kad Remix aplikacija dažnai veiks net be JavaScript’o (arba kol jis kraunasi). Forma bus submit’inta, duomenys bus apdoroti serveryje, ir gausite atsakymą. Kai JavaScript’as užsikrauna, viskas tampa greitesniu ir sklandesniu, bet bazinė funkcionalumas jau veikia. Next.js su App Router irgi juda šia kryptimi, bet istoriškai jis labiau pasikliovė kliento pusės logika.

Duomenų krovimas: loader’iai prieš fetch’us

Čia prasideda įdomiausia dalis. Next.js tradiciškai naudojo getServerSideProps, getStaticProps ir kitas funkcijas duomenims krauti. Su App Router atsirado naujas būdas – tiesiog naudoti fetch Server Components viduje, ir Next.js automatiškai cache’ins rezultatus. Teoriškai elegantiškas sprendimas, bet praktikoje kartais sunku suprasti, kas ir kada cache’inama.

Remix turi loader funkciją kiekvienam route’ui. Ši funkcija vykdoma serveryje prieš renderinant komponentą, ir jos rezultatas perduodamas komponentui per useLoaderData hook’ą. Labai paprasta ir aiški schema:

export async function loader({ request, params }) {
  const user = await getUser(params.userId);
  return json({ user });
}

export default function UserProfile() {
  const { user } = useLoaderData();
  return
{user.name}
;
}

Kas man patinka Remix požiūryje – jis labai aiškiai atskiria serverio ir kliento logiką. Jūs žinote, kad loader funkcija niekada nepateks į kliento bundle’ą. Next.js su Server Components šiek tiek labiau „maišo” šias ribas, kas gali būti lankstesnis, bet ir painesnis sprendimas.

Dar vienas svarbus skirtumas – Remix automatiškai perkrauna visus puslapyje esančių route’ų loader’ius po mutation’o (po formos submit’o). Tai reiškia, kad jums nereikia rašyti papildomo kodo duomenims atnaujinti – jie tiesiog automatiškai perkraunami. Next.js reikia naudoti revalidatePath arba revalidateTag, kas yra galingesnis, bet reikalauja daugiau rankinio darbo.

Formos ir mutation’ai: kur Remix tikrai šviečia

Jei jūsų aplikacija turi daug formų ir duomenų modifikavimo operacijų, Remix tikrai verta dėmesio. Jų action funkcijos yra analogiškos loader funkcijoms, tik skirtos POST, PUT, DELETE ir kitiems ne-GET užklausoms:

export async function action({ request }) {
  const formData = await request.formData();
  const email = formData.get("email");
  
  await subscribeToNewsletter(email);
  return redirect("/thank-you");
}

export default function Newsletter() {
  return (
  );
}

Pastebėkite Form komponentą su didžiąja raide – tai Remix komponentas, kuris veikia kaip paprasta HTML forma, bet su progressive enhancement. Jei JavaScript’as įsikrovęs, forma submit’inama per AJAX. Jei ne – veikia kaip paprasta forma.

Next.js su Server Actions irgi turi panašų funkcionalumą, bet jis atsirado tik neseniai su App Router. Ir, mano nuomone, jis šiek tiek mažiau intuityvus. Jums reikia naudoti "use server" direktyvą, ir kartais sunku suprasti, kas vyksta kliento pusėje, o kas – serverio:

async function subscribe(formData) {
  'use server'
  const email = formData.get('email')
  await subscribeToNewsletter(email)
  redirect('/thank-you')
}

export default function Newsletter() {
  return (
  );
}

Atrodo panašiai, bet yra subtilių skirtumų, kaip tai veikia po gaubtu. Remix požiūris man atrodo švaresnį ir arčiau tradicinio web’o modelio.

Routing ir nested layouts

Abi platformos palaiko file-based routing, bet su skirtumais. Next.js Pages Router naudojo paprastą sistemą – kiekvienas failas pages kataloge tampa route’u. App Router įvedė sudėtingesnę sistemą su app katalogu, kur page.tsx, layout.tsx, loading.tsx ir kiti specialūs failai turi specifines reikšmes.

Remix naudoja nested routing koncepciją, kuri yra labai galinga. Jūsų failų struktūra tiesiogiai atspindi UI hierarchiją. Pavyzdžiui:

app/
  routes/
    _index.tsx                    // /
    about.tsx                     // /about
    blog._index.tsx              // /blog
    blog.$slug.tsx               // /blog/:slug
    dashboard.tsx                // /dashboard (layout)
    dashboard._index.tsx         // /dashboard (index route)
    dashboard.settings.tsx       // /dashboard/settings

Kas čia vyksta? Failas dashboard.tsx veikia kaip layout visiems dashboard.* route’ams. Tai reiškia, kad galite turėti bendrą navigaciją, header’į ar kitą UI, kuris išlieka keičiantis tarp dashboard puslapių. Ir svarbiausia – kiekvienas nested route’as gali turėti savo loader ir action, kurie kraunami lygiagrečiai.

Next.js App Router irgi palaiko nested layouts per layout.tsx failus, bet sistema šiek tiek kitokia. Kiekvienas katalogas gali turėti savo layout’ą, ir jie automatiškai „įsideda” vienas į kitą. Veikia gerai, bet man asmeniškai Remix failų pavadinimų konvencija atrodo aiškesnė ir lengviau suprantama.

Performance ir optimizacijos

Čia reikalai tampa įdomesni. Next.js turi labai brandžią optimizavimo sistemą. Automatinis image optimization per next/image, font optimization, automatic code splitting, ISR (Incremental Static Regeneration) – visa tai veikia out of the box ir veikia gerai.

Remix požiūris į performance yra šiek tiek kitoks. Jie mažiau dėmesio skiria automatiniam optimizavimui ir daugiau – tam, kad jūsų aplikacija būtų greitai interaktyvi. Jų resource routes koncepcija leidžia labai tiksliai kontroliuoti, kaip kraunami skirtingi resursai. Pavyzdžiui, galite turėti route’ą, kuris grąžina tik JSON duomenis, arba tik CSS failą.

Vienas dalykas, kurį Remix daro puikiai – prefetching. Kai vartotojas užveda pelę ant nuorodos, Remix automatiškai pradeda krauti to puslapio duomenis. Kai vartotojas paspaudžia, puslapis atsidaro beveik akimirksniu, nes duomenys jau pakrauti. Next.js irgi turi prefetching, bet jis veikia šiek tiek kitaip ir ne visada taip agresyviai.

Dėl bundle size, Remix paprastai generuoja šiek tiek mažesnius bundle’us, nes jie labiau pasitiki serverio pusės renderinimu ir mažiau siunčia JavaScript’o į klientą. Next.js su App Router ir RSC irgi juda šia kryptimi, bet istoriškai Next.js aplikacijos būdavo šiek tiek „sunkesnės”.

Developer experience ir ekosistema

Next.js turi didžiulę ekosistemą. Vercel (Next.js kūrėjai) investavo milžiniškas sumas į developer experience. Jų dokumentacija yra puiki, yra daugybė pavyzdžių, tutorial’ų, ir beveik bet kokiai problemai rasite sprendimą Stack Overflow. Taip pat, deployment į Vercel platformą yra beveik trivialus – vienas paspaudimas ir jūsų aplikacija online.

Remix ekosistema yra mažesnė, bet sparčiai auga. Po to, kai Shopify nupirko Remix (ir padarė jį nemokamą), investicijos į platformą išaugo. Dokumentacija yra gera, nors kartais trūksta pavyzdžių sudėtingesnėms situacijoms. Bendruomenė yra labai aktyvi ir draugiška – Remix Discord serveris yra puiki vieta gauti pagalbą.

Dėl tooling, abi platformos palaiko TypeScript, ESLint, Prettier ir kitus standartus įrankius. Next.js turi šiek tiek geresnę integraciją su populiariais CMS sistemomis (Contentful, Sanity, etc.), bet Remix greitai vejasi.

Vienas dalykas, kurį turiu paminėti – Remix mokymosi kreivė man atrodė švelnesnis. Jei suprantate React ir žinote web’o pagrindus (HTTP, formas, URL’us), Remix koncepcijos atrodys labai natūralios. Next.js, ypač su App Router, turi daugiau „magic” dalykų, kuriuos reikia išmokti ir suprasti.

Kada rinktis kurį: praktiniai scenarijai

Gerai, užteks teorijos. Kada realiai turėtumėte rinktis vieną ar kitą?

Rinkitės Next.js, jei:

– Kuriate content-heavy svetainę (blog’ą, naujienų portalą, dokumentaciją). Next.js SSG galimybės čia neįkainojamos.
– Jums svarbu turėti didžiulę ekosistemą ir daug ready-made sprendimų. Norite integruotis su populiariais CMS, analytics, ar kitais įrankiais.
– Planuojate deploy’inti į Vercel ir norite maksimaliai paprasto deployment proceso.
– Jūsų komanda jau turi Next.js patirties ir nėra stiprios priežasties keisti.
– Reikia labai sudėtingų image optimization ar kitų built-in optimizacijų.

Rinkitės Remix, jei:

– Kuriate aplikaciją su daug formų ir duomenų modifikavimo operacijų (dashboards, admin panels, SaaS aplikacijas).
– Jums svarbu progressive enhancement ir aplikacija, kuri veikia net be JavaScript’o.
– Norite aiškesnio ir paprastesnio mental model’io, kaip veikia serverio ir kliento pusės logika.
– Planuojate naudoti nested routing ir sudėtingas layout hierarchijas.
– Jums patinka būti arčiau web’o standartų ir mažiau pasikliauti framework-specific abstrakcijomis.

Aš asmeniškai naudoju Next.js projektams, kurie yra daugiau content-oriented ir kur SEO yra kritinis. Remix renkuosi aplikacijoms, kurios yra labiau interactive ir kur vartotojai daug dirba su formomis ir duomenimis.

Kas laukia ateityje?

Abi platformos aktyviai vystosi, ir konkurencija tarp jų yra sveika – ji skatina inovacijas. Next.js su App Router ir React Server Components bando iš naujo apibrėžti, kaip kuriame full-stack aplikacijas. Remix išlieka ištikimas savo filosofijai – grįžti prie web’o pagrindų ir padaryti juos geresniais.

Įdomu tai, kad abi platformos mokosi viena iš kitos. Next.js pridėjo Server Actions po to, kai pamatė, kaip gerai veikia Remix action’ai. Remix planuoja pridėti daugiau optimizavimo galimybių, matydami Next.js sėkmę šioje srityje.

Mano nuomone, nėra vieno teisingio atsakymo, kurį framework’ą rinktis. Tai priklauso nuo jūsų specifinių poreikių, komandos patirties ir projekto tipo. Gera žinia ta, kad abi platformos yra puikios, ir su bet kuria jų galite sukurti greitą, patikimą ir gerai veikiančią aplikaciją.

Jei dar nesiryžote, mano patarimas – išbandykite abu. Sukurkite mažą projektą su Next.js, paskui tą patį su Remix. Pamatysite, kuris jums labiau patinka ir geriau atitinka jūsų mąstymo būdą. Ir nepamirškite – framework’as yra tik įrankis. Svarbiausia yra suprasti problemas, kurias sprendžiate, ir pasirinkti įrankį, kuris geriausiai padeda jas išspręsti.

Daugiau

Nuxt 3 Nitro server