Բոլոր դասերը
FrontendՄիջին15 րոպե ընթերցումԻմ ստեկում

Next.js

React framework արագ, SEO-friendly կայքերի համար՝ App Router, server rendering և caching։

  • App Router
  • SSR / SSG / ISR
  • Caching
  • Metadata
  • Image & fonts
Քայլ 1/5
CSR՝ սերվերն ուղարկում է համարյա դատարկ HTML «կմախք» և JavaScript-ի մեծ փաթեթ։ Բրաուզերը պտտեցնում է spinner-ը և գործի անցնում։

30 վայրկյանում

Next.js-ը React-ի վրա կառուցված framework է, որը քո փոխարեն կազմակերպում է routing-ը, server rendering-ը, data fetching-ը, caching-ը, նկարներն ու տառատեսակները։ Էջերը կարող են գեներացվել նախապես, render լինել յուրաքանչյուր հարցման համար կամ երկուսի համադրությամբ, այնպես որ օգտատերերը ստանում են արագ HTML, իսկ որոնողական համակարգերը տեսնում են իրական կոնտենտ։ Դու գրում ես React կոմպոնենտներ, իսկ Next.js-ը որոշում է, թե ինչպես դրանք build անել, մատուցել և cache անել։

Ինչու եմ օգտագործում

  • Խանութներ, մարքեթինգային կայքեր և վեբ հավելվածներ կառուցում եմ Next.js-ով, որովհետև այն տալիս է server-rendered, SEO-friendly էջեր՝ առանց React-ի կոմպոնենտային մոդելից հրաժարվելու։
  • Մեծ գործակալության կայքը վերագրեցի հին Pages Router-ից App Router-ի, ուստի գիտեմ երկու մոդելն էլ և դրանց միջև migration-ի ճանապարհը։
  • Գնահատում եմ, որ արտադրողականության հնարավորությունները (նկարների օպտիմիզացիա, self-hosted տառատեսակներ, code splitting, streaming) լռելյայն միացված են՝ յուրաքանչյուր նախագծի համար ձեռքով կառուցվելու փոխարեն։
  • Next.js-ը production-ում աշխատեցնում եմ իմ սեփական Linux սերվերների վրա nginx-ի հետևում, ուստի հասկանում եմ, թե framework-ին ինչ է պետք managed հարթակից դուրս։

Ինչպես է աշխատում

01App Router. ֆայլերը դառնում են route-ներ

App Router-ում app/-ի ներսի թղթապանակները սահմանում են URL-ի սեգմենտները, իսկ հատուկ ֆայլերը սահմանում են, թե ինչ է ցույց տալիս յուրաքանչյուր սեգմենտ։ page.tsx-ը route-ը դարձնում է հանրային հասանելի։ layout.tsx-ը փաթաթում է սեգմենտը և նրա բոլոր երեխաներին և մնում է mount արված, երբ օգտատերերը նավիգացիա են անում երեխա էջերի միջև, ուստի header-ները, sidebar-ները և state-ը պահպանվում են։ loading.tsx-ը ցուցադրվում է անմիջապես, քանի դեռ էջը stream է լինում (այն Suspense boundary է), error.tsx-ը բռնում է այդ սեգմենտի սխալները, իսկ not-found.tsx-ը render է անում 404 կոնտենտ։ Դինամիկ սեգմենտներն օգտագործում են քառակուսի փակագծեր, օրինակ՝ [slug]. կլոր փակագծերով route group-երը, օրինակ՝ (shop), կազմակերպում են ֆայլերը՝ առանց URL-ը փոխելու։ route.ts-ը ստեղծում է API endpoint (route handler)՝ GET կամ POST ֆունկցիաներով։ Նավիգացիան օգտագործում է <Link> կոմպոնենտը, որը route-ները prefetch է անում ֆոնային ռեժիմում, որպեսզի click-երն ակնթարթային թվան։ Next.js 15-ից սկսած params-ը և searchParams-ը promise-ներ են, որոնք պետք է await անես։

text
app/
  layout.tsx              // root layout: <html>, <body>, fonts
  page.tsx                // "/"
  (shop)/
    layout.tsx            // shared shop layout, URL unchanged
    products/
      page.tsx            // "/products"
      loading.tsx         // streamed skeleton
      [slug]/
        page.tsx          // "/products/blue-shoe"
        not-found.tsx
  api/
    health/route.ts       // GET /api/health
  sitemap.ts              // /sitemap.xml
  robots.ts               // /robots.txt

02Server և Client Component-ներ Next.js-ում

app directory-ի յուրաքանչյուր կոմպոնենտ լռելյայն Server Component է։ Այն աշխատում է սերվերում, կարող է լինել async, կարող է query անել տվյալների բազան կամ կանչել ներքին API գաղտնիքներով և բրաուզերին իր սեփական JavaScript-ը չի ուղարկում։ Երբ ինտերակտիվություն է պետք (state, effect-ներ, event handler-ներ, բրաուզերի API-ներ), ստեղծիր Client Component՝ ֆայլի վերևում դնելով "use client"։ Այդ directive-ը սահման է նշում. ֆայլը և այն ամենը, ինչ այն import է անում, դառնում են client bundle-ի մաս։ Ուստի "use client"-ը իջեցրու ծառի մեջ որքան հնարավոր է ցածր, օրինակ՝ client կոմպոնենտ դարձրու միայն «Add to cart» կոճակը, ոչ թե ամբողջ ապրանքի էջը։ Server Component-ները կարող են Client Component-ներին փոխանցել serialisable props (string-ներ, թվեր, պարզ օբյեկտներ, promise-ներ) և կարող են server-rendered կոնտենտը դրանց մեջ փոխանցել որպես children։ Mutation-ների համար Server Action-ները ("use server"-ով նշված ֆունկցիաներ) մշակում են ձևերի submit-ները՝ առանց ձեռքով գրված API route-ի։

tsx
// app/products/[slug]/page.tsx  (Server Component)
import { notFound } from "next/navigation";
import { AddToCart } from "./add-to-cart"; // has "use client" at the top
 
export default async function ProductPage({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const res = await fetch(`https://api.example.com/products/${slug}`);
  if (!res.ok) notFound();
  const product: { id: string; name: string; description: string } = await res.json();
 
  return (
    <article>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      <AddToCart productId={product.id} />
    </article>
  );
}

03Rendering ռազմավարություններ. SSG, SSR, ISR և streaming

Next.js-ը որոշում է, թե ինչպես render անել յուրաքանչյուր route։ Static generation-ը (SSG) HTML-ը կառուցում է build-ի ժամանակ. սա ամենաարագ տարբերակն է և մատուցվում է CDN-ից, իդեալական է մարքեթինգային էջերի և բլոգի գրառումների համար։ generateStaticParams-ը Next.js-ին ասում է, թե որ դինամիկ էջերը, օրինակ՝ ապրանքների slug-երը, նախապես կառուցել։ Server-side rendering-ը (SSR) render է անում յուրաքանչյուր հարցման ժամանակ, ինչը պետք է, երբ էջը կախված է cookie-ներից, header-ներից կամ օգտատիրոջ տվյալներից։ Incremental Static Regeneration-ը (ISR) միջին տարբերակն է. մատուցիր ստատիկ էջ և այն վերագեներացրու ֆոնային ռեժիմում որոշ ժամանակ անց (export const revalidate = 3600) կամ երբ կոնտենտի փոփոխությունից հետո կանչում ես revalidatePath կամ revalidateTag։ Streaming-ը թույլ է տալիս սերվերին անմիջապես ուղարկել էջի shell-ը և ավելի դանդաղ մասերը լրացնել հետո՝ Suspense boundary-ների և loading.tsx-ի միջոցով։ Partial Prerendering-ը համադրում է երկուսը. ստատիկ shell գումարած դինամիկ «անցքեր», որը Next.js 16-ում միացվում է Cache Components մոդելի միջոցով։

tsx
// app/blog/[slug]/page.tsx
export const revalidate = 3600; // ISR: regenerate at most once an hour
 
export async function generateStaticParams() {
  const posts: { slug: string }[] = await fetch("https://cms.example.com/posts")
    .then((r) => r.json());
  return posts.map((p) => ({ slug: p.slug })); // pre-built at build time
}
 
// app/actions.ts
"use server";
import { revalidatePath } from "next/cache";
 
export async function publishPost(slug: string) {
  // ...save to the CMS or database...
  revalidatePath(`/blog/${slug}`); // refresh that page on the next request
}

04Caching և revalidation, և ինչ փոխվեց Next.js 16-ում

Caching-ն այն տեղն է, որտեղ Next.js-ի տարբերակներն ամենաշատն են տարբերվում։ Next.js 14-ը լռելյայն cache էր անում fetch հարցումները, ինչը զարմացրեց շատ թիմերի։ Next.js 15-ը սա շրջեց. fetch-ը, GET route handler-ները և client-side էջերի նավիգացիաներն այլևս լռելյայն cache չեն արվում, և դու opt-in ես անում fetch(url, { next: { revalidate: 60, tags: ['products'] } })-ով, unstable_cache-ով կամ route segment-ի տարբերակներով։ Next.js 16-ը ներկայացրեց Cache Components, որը միացվում է cacheComponents: true-ով։ Գուշակելու փոխարեն, թե ինչն է ստատիկ, cache արվող աշխատանքը նշում ես բացահայտ՝ "use cache" directive-ով ֆունկցիայի, կոմպոնենտի կամ էջի վրա, դրա կյանքի տևողությունը սահմանում ես cacheLife-ով և պիտակավորում cacheTag-ով. այն ամենը, ինչ cache չի արվում, պետք է լինի Suspense boundary-ի ներսում և render է լինում հարցման ժամանակ։ Invalidation-ը նույնպես փոխվեց. revalidateTag-ն այժմ որպես երկրորդ արգումենտ ընդունում է cacheLife profile (stale-while-revalidate), նոր updateTag-ը Server Action-ի ներսում անմիջապես expire և refresh է անում (read-your-writes), իսկ refresh()-ը թարմացնում է client router-ը։

ts
// next.config.ts (Next.js 16)
// const nextConfig = { cacheComponents: true };
 
// lib/products.ts
import { cacheLife, cacheTag } from "next/cache";
 
export async function getProducts() {
  "use cache";
  cacheLife("hours");          // built-in profile
  cacheTag("products");
  const res = await fetch("https://api.example.com/products");
  return res.json();
}
 
// app/admin/actions.ts
"use server";
import { revalidateTag, updateTag } from "next/cache";
 
export async function onCatalogImport() { revalidateTag("products", "max"); } // background refresh
export async function onPriceEdit() { updateTag("products"); } // admin sees change now

05Metadata և SEO

Որոնողական համակարգերը և սոցիալական ցանցերը կարդում են HTML-ի <head>-ը, և App Router-ը այն գեներացնում է քո կոդից։ Ցանկացած layout-ից կամ page-ից export արա ստատիկ metadata օբյեկտ կամ դինամիկ էջերի համար async generateMetadata ֆունկցիա։ Root layout-ում դիր title template ("%s | Example Shop"), որպեսզի յուրաքանչյուր էջ ստանա հետևողական վերջածանց, և մեկ անգամ դիր metadataBase, որպեսզի Open Graph նկարների հարաբերական URL-ները դառնան բացարձակ։ Յուրաքանչյուր էջի համար տուր եզակի title և description, canonical URL՝ կրկնվող կոնտենտից խուսափելու համար, և alternates.languages (hreflang)՝ թարգմանված տարբերակների համար։ Մնացածը ծածկում են ֆայլային պայմանավորվածությունները. sitemap.ts-ը, robots.ts-ը և opengraph-image.tsx-ը գեներացնում են այդ ֆայլերը build-ի կամ հարցման ժամանակ։ Ավելացրու structured data (JSON-LD, օրինակ՝ Product կամ Article) որպես script tag էջում, որպեսզի որոնողական համակարգերը կարողանան ցույց տալ rich result-ներ։ Քանի որ HTML-ը server-rendered է, crawler-ները տեսնում են ամբողջական կոնտենտը՝ առանց JavaScript աշխատեցնելու։

tsx
// app/products/[slug]/page.tsx
import type { Metadata } from "next";
 
export async function generateMetadata({
  params,
}: {
  params: Promise<{ slug: string }>;
}): Promise<Metadata> {
  const { slug } = await params;
  const product = await fetch(`https://api.example.com/products/${slug}`).then((r) => r.json());
  return {
    title: product.name, // root layout template adds " | Example Shop"
    description: product.summary,
    alternates: {
      canonical: `/products/${slug}`,
      languages: { en: `/en/products/${slug}`, ru: `/ru/products/${slug}` },
    },
    openGraph: { images: [product.imageUrl] },
  };
}

06Նկարներ, տառատեսակներ և ինչու են Next.js կայքերն արագ

Մեծ նկարները և վեբ տառատեսակները դանդաղ էջերի և layout shift-ի սովորական պատճառներն են։ next/image-ը նկարները չափափոխում և փոխակերպում է ժամանակակից ֆորմատների, ինչպես WebP-ն կամ AVIF-ը, ըստ պահանջի, գեներացնում է srcset, որպեսզի հեռախոսները փոքր ֆայլեր ներբեռնեն, lazy-load է անում fold-ից ներքև գտնվող նկարները և տեղ է պահում width-ի և height-ի միջոցով (կամ fill՝ չափ ունեցող ծնողով), որպեսզի layout-ը չցատկի։ Hero նկարը, որը սովորաբար Largest Contentful Paint-ն է, նշիր eager բեռնման համար. Next.js 15-ում՝ priority, որը Next.js 16-ում փոխարինվել է preload-ով։ next/font-ը Google-ի կամ լոկալ տառատեսակները ներբեռնում է build-ի ժամանակ և մատուցում քո սեփական domain-ից՝ առանց runtime-ում Google-ին հարցման, և գեներացնում է size-adjusted fallback, որպեսզի տեքստը չվերադասավորվի, երբ տառատեսակը հասնի։ Server rendering-ի, յուրաքանչյուր route-ի ավտոմատ code splitting-ի, link prefetch-ի և streaming-ի հետ միասին սա է պատճառը, որ Next.js կայքերը Core Web Vitals-ում լավ արդյունքներ են ցույց տալիս հենց տուփից։

tsx
// app/layout.tsx
import { Inter } from "next/font/google";
const inter = Inter({ subsets: ["latin", "cyrillic"], display: "swap", variable: "--font-main" });
 
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={inter.variable}>
      <body>{children}</body>
    </html>
  );
}
 
// app/page.tsx
import Image from "next/image";
export default function Home() {
  return (
    <Image src="/hero.jpg" alt="Fresh coffee beans" width={1600} height={900}
      sizes="100vw" preload /> // Next.js 15: use priority instead of preload
  );
}

07Deployment-ի տարբերակներ և Next.js 15-ն ընդդեմ 16-ի

Vercel-ը՝ Next.js-ի հետևում կանգնած ընկերությունը, առաջարկում է zero-configuration hosting՝ CDN-ով, serverless ֆունկցիաներով և նկարների օպտիմիզացիայով։ Այլ հարթակներ (Netlify, Cloudflare՝ OpenNext-ի միջոցով, AWS Amplify) աջակցում են այն adapter-ների միջոցով. Next.js 16.2-ը դրա համար Build Adapters API-ն դարձրեց stable։ Կարող ես նաև self-host անել. next build-ից հետո next start-ը աշխատեցնում է Node.js սերվեր, որը սովորաբար կառավարվում է pm2-ով կամ container-ով և տեղադրվում nginx-ի հետևում՝ TLS-ի և սեղմման համար։ output: "standalone"-ը արտադրում է մինիմալ թղթապանակ, որը իդեալական է Docker image-ների համար։ Մի քանի instance-ով self-host անելիս կարգավորիր ընդհանուր cache handler, որպեսզի ISR տվյալները մնան հետևողական։ Next.js 16-ի հիմնական փոփոխությունները 15-ի համեմատ. Turbopack-ը լռելյայն bundler-ն է dev-ի և build-ի համար, middleware.ts-ը վերանվանվել է proxy.ts (Node.js runtime), params-ի և cookies()-ի սինխրոն հասանելիությունը հեռացվել է, պահանջվում է Node.js 20.9+, next lint-ը այլևս չկա, իսկ next/image-ի լռելյայն արժեքներն ավելի խիստ են (միայն quality 75 և ավելի երկար նվազագույն cache ժամանակ)։

ts
// next.config.ts - self-hosted build for Docker
import type { NextConfig } from "next";
 
const nextConfig: NextConfig = {
  output: "standalone",
  images: {
    remotePatterns: [{ protocol: "https", hostname: "cdn.example.com" }],
  },
};
export default nextConfig;
 
// Build and run:
//   npm ci && npm run build
//   node .next/standalone/server.js   (copy public/ and .next/static/ alongside)
// Behind nginx: proxy_pass http://127.0.0.1:3000;

Օգտագործեք, երբ

  • Հանրային կայքեր, որտեղ SEO-ն և առաջին բեռնման արագությունը կարևոր են. e-commerce խանութներ, մարքեթինգային կայքեր, բլոգներ, փաստաթղթավորում։
  • Պրոդուկտներ, որոնք ստատիկ կոնտենտը խառնում են անհատականացված կամ դինամիկ մասերի հետ, օրինակ՝ cart-ով և account բաժնով խանութ։
  • Թիմեր, որոնք արդեն օգտագործում են React և ուզում են routing-ի, rendering-ի և արտադրողականության պայմանավորվածություններ՝ դրանք ձեռքով հավաքելու փոխարեն։
  • Full-stack հնարավորություններ թեթև backend-ով. ձևեր, webhook-ներ և փոքր API-ներ Server Action-ների և route handler-ների միջոցով։

Մի՛ օգտագործեք, երբ

  • Login-ի հետևում գտնվող ներքին dashboard-ներ՝ առանց SEO կարիքների, որտեղ մաքուր React + Vite single-page app-ը ավելի պարզ է կառուցել և host անել։
  • Ծանր backend domain-ներ (բարդ բիզնես կանոններ, queue-ներ, բազմաթիվ ինտեգրացիաներ). պահիր առանձին API (Laravel, NestJS) և Next.js-ն օգտագործիր որպես frontend։
  • Թիմեր, որոնք ոչ մի տեղ չեն կարող Node.js աշխատեցնել և միայն ստատիկ էջեր են պետք. Astro-ի պես static site generator-ը կարող է ավելի թեթև լինել։

Այլընտրանքներ

  • Remix / React Router 7

    Վեբ ստանդարտների, loader-ների և action-ների վրա կենտրոնացած React framework. ուժեղ է տվյալներով ծանր հավելվածների համար։

  • Astro

    Content-first կայքեր, որոնք լռելյայն զրո JavaScript են ուղարկում՝ React-ի, Vue-ի կամ Svelte-ի «կղզիներով»։

  • Nuxt or SvelteKit

    Համարժեք full-stack framework-ներ Vue-ի և Svelte-ի համար։

  • React + Vite (SPA)

    Միայն client-side React. ամենապարզն է authenticated հավելվածների համար, որոնց SEO պետք չէ։

Լավագույն պրակտիկաներ

  1. Կոմպոնենտները լռելյայն պահիր սերվերում և "use client" ավելացրու միայն ինտերակտիվ «տերևներին»։
  2. Caching-ի հարցում եղիր բացահայտ. յուրաքանչյուր տվյալների աղբյուրի համար որոշիր, թե որքան թարմ պետք է լինի և ինչպես է invalidate արվում (tag-եր, path-եր)։
  3. Յուրաքանչյուր հանրային էջի համար գեներացրու metadata, canonical URL-ներ, hreflang, sitemap և robots։
  4. Յուրաքանչյուր նկարի և տառատեսակի համար օգտագործիր next/image ճիշտ sizes-ով և next/font. preload արա միայն hero նկարը։
  5. Դանդաղ տվյալները փաթաթիր Suspense boundary-ներում, որպեսզի shell-ը stream լինի անմիջապես։
  6. Server Action-ներում և route handler-ներում մուտքը վալիդացրու ճիշտ այնպես, ինչպես ցանկացած API-ում. դրանք հանրային endpoint-ներ են։
  7. Ամրագրիր major տարբերակը և 15-ից 16 անցնելիս հետևիր պաշտոնական upgrade guide-ին և codemod-ներին։

Տարածված սխալներ

  • "use client"-ը էջի կամ layout-ի վերևում դնելը, ինչը ամբողջ ծառը քաշում է բրաուզերի bundle-ի մեջ։
  • Ենթադրելը, որ տվյալները cache են արվում (կամ չեն արվում)՝ առանց քո Next.js տարբերակի կանոնները ստուգելու։
  • Root layout-ում cookies() կամ headers() կարդալը և պատահաբար յուրաքանչյուր էջ դինամիկ դարձնելը։
  • Առանց չափերի պարզ <img> tag-եր օգտագործելը, ինչը առաջացնում է layout shift և չափից մեծ ներբեռնումներ։
  • Server Action-ներին որպես մասնավոր ֆունկցիաներ վերաբերվելը և authentication-ն ու վալիդացիան բաց թողնելը։

Խորը վերլուծություն

08RSC payload-ը, client router-ը և դրա cache-ը

Next.js էջի պատասխանը պարունակում է երկու բան. HTML՝ առաջին նկարման համար, և RSC payload՝ Server Component-ների ծառի կոմպակտ serialised նկարագրություն՝ placeholder-ներով այնտեղ, որտեղ գալիս են Client Component-ները, գումարած հղումներ դրանց JavaScript ֆայլերին։ Առաջին բեռնման ժամանակ բրաուզերը ցույց է տալիս HTML-ը, հետո React-ը payload-ով hydrate է անում Client Component-ները։ Հետագա նավիգացիաների ժամանակ <Link>-ով Next.js-ը ընդհանրապես HTML չի բերում. այն պահանջում է միայն նոր route segment-ների RSC payload-ը և միացնում այն ընթացիկ ծառին, այնպես որ ընդհանուր layout-ները պահպանում են իրենց state-ը և re-render չեն լինում։ Prefetch արված և այցելված segment-ները պահվում են հիշողության մեջ գտնվող client router cache-ում։ Next.js 15-ից page segment-ները լռելյայն չեն վերաօգտագործվում այդ cache-ից (layout-ները և loading վիճակները՝ դեռ այո), ինչը խուսափում է հնացած էջերից. experimental.staleTimes-ը կարգավորում է սա։ Mutation-ից հետո կանչիր revalidatePath կամ updateTag սերվերում, կամ router.refresh() client-ում, որպեսզի client cache-ը հնացած տվյալներ ցույց չտա։ Այս բաժանումը հասկանալը բացատրում է, թե ինչու է էջի լրիվ reload-ը երբեմն «ուղղում» բագը. այն դեն է նետում client cache-ը։

tsx
"use client";
import { useRouter } from "next/navigation";
import { useTransition } from "react";
 
export function MarkShippedButton({ orderId }: { orderId: string }) {
  const router = useRouter();
  const [isPending, startTransition] = useTransition();
 
  async function markShipped() {
    await fetch(`/api/orders/${orderId}/ship`, { method: "POST" });
    startTransition(() => router.refresh()); // refetch RSC payload, keep client state
  }
 
  return <button onClick={markShipped} disabled={isPending}>Mark shipped</button>;
}
 
// next.config.ts (optional): experimental: { staleTimes: { dynamic: 30, static: 180 } }

09Server Actions-ը և route handler-ները որպես անվտանգության սահման

Server Action-ը ֆունկցիայի կանչի տեսք ունի, բայց կոմպիլյացվում է public POST endpoint-ի, որը ցանկացած մեկը կարող է կանչել ցանկացած արգումենտներով։ Next.js-ը որոշ պաշտպանություն է ավելացնում. action-ները ստանում են անգուշակելի id-ներ, չօգտագործվող action-ները հեռացվում են build-ից, closure-ով բռնված փոփոխականները գաղտնագրվում են client-ին ուղարկվելուց առաջ, և Origin header-ը համեմատվում է host-ի հետ՝ cross-site request forgery-ն արգելափակելու համար։ Եթե deploy ես անում այլ host-ով proxy-ի կամ CDN-ի հետևում, նշիր այն experimental.serverActions.allowedOrigins-ում՝ ստուգումն անջատելու փոխարեն։ Request body-ները լռելյայն սահմանափակված են 1 MB-ով (serverActions.bodySizeLimit)։ Սրանցից ոչ մեկը չի փոխարինում քո սեփական ստուգումներին. յուրաքանչյուր action-ում authenticate արա օգտատիրոջը, authorise արա կոնկրետ գրառման հասանելիությունը և արգումենտները վալիդացրու schema-ով՝ ճիշտ ինչպես REST controller-ում։ Տվյալների հասանելիության կոդը պահիր առանձին մոդուլում՝ նշված import 'server-only'-ով, որպեսզի այն երբեք պատահաբար չհայտնվի client կոդի bundle-ում։ Մի քանի instance աշխատեցնելիս բոլորի վրա սահմանիր նույն NEXT_SERVER_ACTIONS_ENCRYPTION_KEY-ը, որպեսզի գաղտնագրված արժեքները պահպանվեն սերվերների միջև։

ts
"use server";
import "server-only";
import { z } from "zod";
import { updateTag } from "next/cache";
import { getSession } from "@/lib/auth";
import { db } from "@/lib/db";
 
const Input = z.object({ productId: z.string().uuid(), price: z.number().int().positive() });
 
export async function updatePrice(raw: unknown) {
  const session = await getSession();
  if (!session?.user.isAdmin) throw new Error("Forbidden"); // authorise every call
  const { productId, price } = Input.parse(raw);             // never trust arguments
  await db.product.update({ where: { id: productId }, data: { price } });
  updateTag(`product-${productId}`);
}

10Proxy, runtime-ներ և request-ի ժամանակ կատարվող աշխատանք

Next.js 16-ում middleware.ts-ը վերանվանվել է proxy.ts, իսկ դրա export արվող ֆունկցիան կոչվում է proxy։ Այն աշխատում է routing-ից առաջ յուրաքանչյուր համընկնող request-ի համար՝ Node.js runtime-ի վրա, և նախատեսված է թեթև որոշումների համար՝ redirect-ներ, rewrite-ներ, locale-ի հայտնաբերում, header-ների սահմանում կամ արագ ստուգում, որ session cookie-ն գոյություն ունի։ Այն չպետք է լինի authorisation-ի քո միակ շերտը, որովհետև սխալ կարգավորված matcher-ը կամ բագը կարող է այն բաց թողնել. թույլտվությունները նորից ստուգիր տվյալներին մոտ։ Պահիր այն արագ, որովհետև այն latency է ավելացնում յուրաքանչյուր համընկնող request-ին, և matcher config-ով բացառիր ստատիկ ֆայլերն ու նկարները։ Proxy-ից բացի մի քանի API route-ը դինամիկ են դարձնում՝ cookies(), headers(), connection() և searchParams։ Դրանք root layout-ում կանչելը ամբողջ կայքը դարձնում է request-time rendered, ուստի կարդա դրանք ծառում հնարավորինս խորը և այդ մասը փաթաթիր Suspense-ով։ after()-ը թույլ է տալիս պլանավորել աշխատանք, օրինակ՝ logging կամ analytics, որը կաշխատի պատասխանն ուղարկելուց հետո, այնպես որ այն չի դանդաղեցնում օգտատիրոջը։

ts
// proxy.ts (Next.js 16; was middleware.ts)
import { NextResponse, type NextRequest } from "next/server";
 
export function proxy(request: NextRequest) {
  const hasSession = request.cookies.has("session");
  if (!hasSession && request.nextUrl.pathname.startsWith("/account")) {
    const url = new URL("/login", request.url);
    url.searchParams.set("next", request.nextUrl.pathname);
    return NextResponse.redirect(url);
  }
  return NextResponse.next();
}
 
export const config = {
  matcher: ["/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)"],
};

11Self-hosting մասշտաբով՝ ընդհանուր cache-եր, version skew և bundle-ի չափ

Մեկ Next.js սերվերը մեկ մեքենայի վրա պարզ է։ Load balancer-ի հետևում մի քանի instance-ը երեք խնդիր է առաջացնում։ Cache-ի հետևողականություն. լռելյայն յուրաքանչյուր instance իր ISR և data cache-ը պահում է լոկալ դիսկում և հիշողության մեջ, այնպես որ օգտատերերը կարող են տեսնել էջի տարբեր տարբերակներ՝ կախված նրանից, թե որ սերվերն է պատասխանում։ Կարգավորիր custom cacheHandler՝ Redis-ի կամ այլ ընդհանուր պահոցի հիման վրա, և անջատիր in-memory cache-ը cacheMaxMemorySize: 0-ով, եթե յուրաքանչյուր կարդալ պետք է անցնի դրա միջով։ Version skew. rolling deploy-ի ընթացքում հին JavaScript պահող բրաուզերը կարող է կանչել նոր սերվերը։ Build արա մեկ անգամ և նույն artefact-ը ուղարկիր յուրաքանչյուր instance, սահմանիր deploymentId (կամ NEXT_DEPLOYMENT_ID), որը Next.js-ը ավելացնում է asset-ների URL-ներին և cache key-երին, և նախորդ build-ի ստատիկ ֆայլերը որոշ ժամանակ հասանելի պահիր, իդեալական դեպքում՝ CDN-ում։ Bundle-ի չափ. Next.js 16.1+-ում next experimental-analyze-ը ուսումնասիրում է Turbopack-ի production bundle-ները, այնպես որ կարող ես տեսնել, թե որ import-ն է մեծ գրադարան բերել client component-ի մեջ։ /_next/static-ը cache արա ագրեսիվ, որովհետև այդ ֆայլերը content-hash արված են։

ts
// next.config.ts - multi-instance self-hosting
import type { NextConfig } from "next";
 
const nextConfig: NextConfig = {
  output: "standalone",
  deploymentId: process.env.GIT_SHA,              // same value on every instance
  cacheHandler: require.resolve("./cache-handler.mjs"), // shared store, e.g. Redis
  cacheMaxMemorySize: 0,                          // no per-instance memory cache
};
export default nextConfig;
 
// nginx: content-hashed assets can be cached for a year
// location /_next/static/ { proxy_pass http://app; add_header Cache-Control "public, max-age=31536000, immutable"; }
 
// Inspect client bundles (Next.js 16.1+):
//   npx next experimental-analyze

Իրական իրավիճակներ

01

Ապրանքների գները թարմանում են admin-ում, բայց ոչ խանութում

Խնդիր

Խմբագիրները փոխում են գինը admin panel-ում, բայց ապրանքի էջը մինչև մեկ ժամ շարունակում է ցույց տալ հին գինը։ Երբեմն refresh-ը ցույց է տալիս նոր գինը, իսկ հաջորդ refresh-ը՝ հինը։

Ինչպես լուծել

Այստեղ երկու խնդիր է համադրվում։ Էջը cache արված է ժամանակի վրա հիմնված revalidate-ով, և փոփոխության դեպքում ոչինչ այն invalidate չի անում, ուստի ավելացրու cacheTag յուրաքանչյուր ապրանքի համար և կանչիր revalidateTag (կամ updateTag Server Action-ի ներսում), երբ admin-ը պահպանում է. եթե admin-ը առանձին backend է, տրամադրիր փոքր authenticated route handler, որը այն կարող է կանչել որպես webhook։ Հին և նոր գների միջև «ճոճվելը» նշանակում է լոկալ cache-երով մի քանի instance։ Redis-ում կարգավորիր ընդհանուր cacheHandler, որպեսզի բոլոր instance-ները կարդան նույն գրառումները, և ամենուր սահմանիր նույն deploymentId-ն։ Հետո ստուգիր՝ գինը պահպանելով և load balancer-ի միջով բազմիցս reload անելով։

02

Զամբյուղի badge ավելացնելուց հետո ամբողջ կայքը դինամիկ դարձավ

Խնդիր

Ծրագրավորողը header-ում ավելացրեց զամբյուղի counter՝ root layout-ում կարդալով cookies()։ Build output-ը հիմա բոլոր route-երը ցույց է տալիս որպես դինամիկ, time to first byte-ը կրկնապատկվել է, և CDN caching-ը դադարել է աշխատել։

Ինչպես լուծել

Root layout-ում cookie-ներ կարդալը բոլոր էջերը տեղափոխում է request-time rendering-ի։ Cookie-ի կարդալը տեղափոխիր փոքր CartBadge կոմպոնենտի մեջ և render արա այն Suspense boundary-ի ներսում՝ չեզոք fallback-ով, օրինակ՝ դատարկ badge-ով։ Cache Components-ը միացված լինելու դեպքում ստատիկ shell-ը, ներառյալ header-ը, այդ ժամանակ prerender է լինում, իսկ badge-ը stream է լինում յուրաքանչյուր request-ի համար (Partial Prerendering)։ Առանց Cache Components-ի այլընտրանք է client component-ը, որը բեռնումից հետո քանակը բերում է route handler-ից։ Նորից ստուգիր build output-ը. ապրանքների և բովանդակության էջերը պետք է լինեն ստատիկ կամ ISR, իսկ դինամիկ՝ միայն badge-ի, զամբյուղի և account-ի route-երը։

03

Self-hosted deploy-ը կոտրում է նավիգացիան ակտիվ օգտատերերի համար

Խնդիր

Յուրաքանչյուր release-ից հետո որոշ օգտատերեր, որոնց մոտ կայքը բաց էր, link-երի վրա սեղմելիս կամ ձևեր submit անելիս սխալներ են տեսնում, մինչև reload անեն։ Log-երը ցույց են տալիս 404-ներ JavaScript chunk-երի համար և ձախողված Server Action կանչեր։

Ինչպես լուծել

Սա version skew է. հին էջերը պահանջում են chunk-եր կամ action id-ներ, որոնք նոր build-ն այլևս չունի։ Build արա մեկ անգամ CI-ում և նույն artefact-ը deploy արա ամենուր։ deploymentId-ն սահմանիր git commit-ից, որպեսզի Next.js-ը կարողանա հայտնաբերել անհամապատասխանությունը և անհրաժեշտության դեպքում reload անել էջը։ Նախորդ build-երի /_next/static ֆայլերը մի քանի օր հասանելի պահիր, օրինակ՝ upload անելով դրանք CDN կամ object storage assetPrefix-ով, որպեսզի հին էջերը դեռ կարողանան բեռնել իրենց chunk-երը։ Release-ների և instance-ների միջև սահմանիր ֆիքսված NEXT_SERVER_ACTIONS_ENCRYPTION_KEY։ Server Action-ների signature-ներում նախընտրիր ավելացնող փոփոխություններ և յուրաքանչյուր release-ից հետո հետևիր /_next/static-ի 404-ներին։

Արագ ուղեցույց

Սկսել նոր հավելված
npx create-next-app@latest my-app --ts --app
Թարմացնել պաշտոնական codemod-ներով
npx @next/codemod@canary upgrade latest
Տեսնել, թե որ route-երն են ստատիկ կամ դինամիկ
npm run build // read the route table in the output
Ուսումնասիրել client bundle-ները (16.1+)
npx next experimental-analyze
Կոմպոնենտը բացահայտ տեղափոխել request time
import { connection } from "next/server"; await connection();
Աշխատանք կատարել պատասխանն ուղարկելուց հետո
import { after } from "next/server"; after(() => logView(id));
Մոդուլը հեռու պահել client bundle-ներից
import "server-only";
Թարմացնել սերվերի տվյալները client-ից
router.refresh() // from next/navigation
Թույլատրել Server Actions-ը proxy domain-ի հետևում
experimental: { serverActions: { allowedOrigins: ["shop.example.com"] } }
Հետևողական build-եր instance-ների միջև
deploymentId: process.env.GIT_SHA

Իմ իրական նախագծերում

  • Գործակալության կայքի ամբողջական վերագրման հիմնական contributor-ն էի՝ Pages Router-ից App Router Next.js 15-ի վրա, որը կառուցվում էր զուգահեռ մոտ մեկուկես տարի, իսկ հետո փոխարինեց հինը։
  • Կենդանիների ապրանքների խանութն աշխատում է Next.js 16-ով՝ next-intl-ով երեք լեզվի համար, յուրաքանչյուր էջի SEO-ով և sitemap-ով, իսկ հետևում Laravel API է։
  • Սրճարանների ցանցի careers կայքն աշխատում է Next.js 16-ով՝ custom server-ով անվտանգության և cache header-ների համար, գումարած գեներացված sitemap, robots և Open Graph նկարներ։
  • Իմ սեփական սերվերներում Next.js հավելվածներն աշխատում են pm2-ի տակ nginx-ի հետևում՝ դրանց սնուցող Laravel API-ների կողքին։

Հարցեր և պատասխաններ

Q1Ո՞րն է SSR-ի, SSG-ի և ISR-ի տարբերությունը։

Դրանք տարբերվում են նրանով, թե երբ է HTML-ը գեներացվում։ SSG-ն էջերը render է անում build-ի ժամանակ, ուստի յուրաքանչյուր այցելու ստանում է նույն նախապես կառուցված ֆայլը CDN-ից. սա ամենաարագ տարբերակն է և հարմար է հազվադեպ փոխվող կոնտենտի համար։ SSR-ը render է անում յուրաքանչյուր հարցման ժամանակ, ինչը պետք է անհատականացված էջերի կամ ամեն անգամ թարմ լինելիք տվյալների համար՝ յուրաքանչյուր այցի համար սերվերի աշխատանքի գնով։ ISR-ը համադրում է դրանք. էջերը ստատիկ են, բայց վերագեներացվում են ֆոնային ռեժիմում որոշ ժամանակահատվածից հետո կամ ըստ պահանջի, երբ կոնտենտը փոխվում է՝ revalidatePath-ի կամ revalidateTag-ի միջոցով։ App Router-ում հազվադեպ ես ռեժիմն ընտրում անունով. այն բխում է քո օգտագործած տվյալներից, caching-ի կարգավորումներից և դինամիկ ֆունկցիաներից, ինչպես cookies()-ը։

Q2Ինչպե՞ս են Server և Client Component-ները միասին աշխատում Next.js-ում։

app directory-ում ամեն ինչ Server Component է, եթե այլ կերպ նշված չէ։ Server Component-ները render են լինում սերվերում, կարող են անմիջապես fetch անել տվյալներ և գաղտնիքներն ու ծանր գրադարանները հեռու պահել բրաուզերից։ "use client"-ով սկսվող ֆայլը դառնում է client boundary. այն և դրա import-ները bundle են արվում բրաուզերի համար, hydrate են լինում և կարող են օգտագործել state, effect-ներ և event-ներ։ Server Component-ները կարող են render անել Client Component-ներ և դրանց փոխանցել serialisable props կամ server-rendered children, բայց Client Component-ները չեն կարող անմիջապես import անել Server Component-ներ։ Նպատակը ինտերակտիվ մասերը փոքր պահելն է, որպեսզի էջերն ավելի քիչ JavaScript ուղարկեն՝ միևնույն ժամանակ լիովին ինտերակտիվ լինելով այնտեղ, որտեղ պետք է։

Q3Ինչո՞ւ են Next.js կայքերը լավ SEO-ի համար։

Հիմնականում այն պատճառով, որ crawler-ները ստանում են ամբողջական HTML։ Ստատիկ կամ server rendering-ի դեպքում վերնագրերը, տեքստը, հղումները և structured data-ն առկա են սկզբնական պատասխանում, ուստի որոնողական համակարգերը ստիպված չեն JavaScript աշխատեցնել՝ կոնտենտը տեսնելու համար։ Դրանից բացի, Next.js-ը տալիս է ներկառուցված գործիքներ տեխնիկական SEO-ի մնացած մասի համար. Metadata API՝ title-ների, description-ների, canonical URL-ների, hreflang-ի և Open Graph tag-երի համար, ֆայլային պայմանավորվածություններ sitemap.xml-ի և robots.txt-ի համար, գեներացված սոցիալական նկարներ և ուժեղ Core Web Vitals՝ նկարների օպտիմիզացիայի, տառատեսակների մշակման, code splitting-ի և streaming-ի շնորհիվ։ Լավ SEO-ին դեռ պետք է լավ կոնտենտ և կառուցվածք, բայց framework-ը հեռացնում է տեխնիկական խոչընդոտների մեծ մասը։

Q4Ի՞նչ փոխվեց caching-ում Next.js 14-ի, 15-ի և 16-ի միջև։

Next.js 14-ը լռելյայն cache էր անում fetch-ի արդյունքները և route handler-ները, ինչը տվյալներն անսպասելիորեն հնացած էր դարձնում։ Next.js 15-ը շրջեց այդ լռելյայն արժեքները. fetch-ը, GET route handler-ները և դեպի էջեր client նավիգացիաները cache չեն արվում, եթե opt-in չես անում revalidate-ով, tag-երով, unstable_cache-ով կամ segment config-ով։ Next.js 16-ը ավելացնում է Cache Components՝ cacheComponents: true-ի հետևում, որտեղ caching-ը բացահայտ է. ֆունկցիաները կամ կոմպոնենտները նշում ես "use cache"-ով, կյանքի տևողությունը սահմանում ես cacheLife-ով, իսկ պիտակները՝ cacheTag-ով, և cache չարվող տվյալները պետք է լինեն Suspense-ի ներսում։ revalidateTag-ն այժմ պահանջում է cacheLife profile, updateTag-ը Server Action-ներում տալիս է read-your-writes թարմացումներ, իսկ Partial Prerendering-ը միացվում է այս մոդելի միջոցով։

Q5Արժե՞ արդյոք Next.js 15-ից upgrade անել 16-ի։

Սովորաբար այո, բայց որպես պլանավորված առաջադրանք։ Next.js 16-ը բերում է Turbopack-ը որպես լռելյայն bundler՝ շատ ավելի արագ build-երով, stable React Compiler տարբերակը, վերամշակված router՝ ավելի թեթև prefetch-ով, React 19.2-ի հնարավորությունները և Cache Components մոդելը։ Breaking փոփոխությունները կառավարելի են. Node.js 20.9 կամ ավելի նոր, միայն async params, cookies() և headers(), middleware-ը վերանվանված proxy, հեռացված next lint, ավելի խիստ next/image լռելյայն արժեքներ և revalidateTag-ի նոր signature։ Պաշտոնական codemod-ը մշակում է սրա մեծ մասը։ Upgrade անում եմ առանձին branch-ում, աշխատեցնում եմ codemod-ները, ստուգում եմ custom webpack config-ը և նկարների օգտագործումը, հետո թեստավորում եմ կրիտիկական հոսքերը։ 15 տարբերակը դեռ ստանում է backport արված ուղղումներ, ուստի շտապելու կարիք չկա։

Q6Ինչպե՞ս կdeploy անես Next.js հավելվածը Vercel-ից դուրս։

Build արա output: "standalone"-ով, որն արտադրում է մինիմալ Node.js սերվեր՝ միայն անհրաժեշտ dependency-ներով, հետո աշխատեցրու այն Docker container-ում կամ pm2-ի պես process manager-ի տակ։ Առջևում դիր nginx՝ TLS-ի, սեղմման և անփոփոխ /_next/static ֆայլերի caching-ի համար, իսկ անհրաժեշտության դեպքում դրանից առաջ՝ CDN, ինչպես Cloudflare-ը։ Environment փոփոխականները սահմանիր runtime-ում, գաղտնիքները հեռու պահիր NEXT_PUBLIC_ փոփոխականներից և ավելացրու health-check route։ Նկարների օպտիմիզացիան աշխատում է սերվերում, բայց բեռի տակ CDN-ը օգնում է։ Եթե աշխատեցնում ես մի քանի instance, կարգավորիր ընդհանուր cache handler, օրինակ՝ Redis-ում, որպեսզի ISR-ը և cache արված տվյալները մնան հետևողական դրանց միջև։

Սենիոր մակարդակի հարցեր

S1Ինչպե՞ս կնախագծես caching-ը Next.js-ով կառուցված մեծ e-commerce կայքի համար։

Թարմությունը որոշում եմ ըստ տվյալների աղբյուրի, ոչ թե ըստ էջի։ Կատեգորիաների և ապրանքների բովանդակությունը կարելի է cache անել ժամերով և invalidate անել tag-երով, երբ կատալոգը փոխվում է՝ backend-ից եկող webhook-ի միջոցով։ Գներն ու պաշարը ավելի հաճախ են փոխվում և ավելի կարևոր են, ուստի ստանում են կարճ կյանքի տևողություն կամ բերվում են request-ի ժամանակ՝ Suspense-ով փաթաթված փոքր կոմպոնենտում՝ էջի մնացած մասը ստատիկ պահելով։ Զամբյուղը, account-ը և checkout-ը միշտ դինամիկ են և երբեք cache չեն արվում ընդհանուր շերտերում։ Cache Components-ի դեպքում սա ուղղակիորեն համապատասխանում է "use cache"-ին՝ cacheLife-ով և cacheTag-ով, գումարած Partial Prerendering shell-ի համար։ Self-hosted ենթակառուցվածքում ընդհանուր cache handler-ը instance-ները հետևողական է պահում, իսկ CDN-ը cache է անում ստատիկ asset-ները և public էջերը։ Փոխզիջումը բարդությունն է. յուրաքանչյուր cache արված տարր պետք է ունենա հստակ տեր և invalidation-ի ուղի, այլապես հնացած գները դառնում են support-ի խնդիր։

S2Ե՞րբ չէիր օգտագործի Server Actions և փոխարենը կօգտագործեիր route handler-ներ կամ առանձին API։

Server Actions-ը հիանալի են քո սեփական Next.js UI-ից նախաձեռնված mutation-ների համար, հատկապես ձևերի, որովհետև ինտեգրվում են transition-ների, progressive enhancement-ի և cache invalidation-ի հետ։ Դրանք վատ են տեղավորվում, երբ այլ client-ների նույն գործողությունն է պետք. մոբայլ հավելվածին, գործընկերային ինտեգրացիային կամ webhook-ին պետք է կայուն, փաստաթղթավորված HTTP պայմանագիր, որը տրամադրում են route handler-ները կամ նվիրված backend-ը։ Action id-ները կախված են կոնկրետ build-ից, ուստի դրանք public API չեն։ Լռելյայն դրանք նաև մեկ client-ից աշխատում են հաջորդաբար, ուստի իդեալական չեն տվյալների զուգահեռ ստացման համար. տվյալների կարդալը Server Components-ի գործն է։ Երբ բիզնես domain-ը մեծ է՝ queue-ներով, պլանավորված job-երով և բազմաթիվ ինտեգրացիաներով, այդ տրամաբանությունը պահում եմ առանձին API-ում՝ Laravel կամ NestJS, իսկ Server Actions-ը թողնում եմ որպես բարակ wrapper-ներ, որոնք կանչում են այն։

S3Vercel, թե self-hosting. ինչպե՞ս ես խորհուրդ տալիս հաճախորդին։

Սա փոխզիջում է շահագործման ջանքերի և արժեքի ու վերահսկողության միջև։ Vercel-ը տալիս է հնարավորությունների ամբողջական հավաքածուն՝ առանց կոնֆիգուրացիայի. գլոբալ CDN, նկարների օպտիմալացում, preview deployment-ներ, skew protection և մասշտաբավորում։ Այն իդեալական է փոքր թիմերի և պիկերով տրաֆիկի համար, բայց ծախսերն աճում են bandwidth-ի, ֆունկցիաների ժամանակի և նկարների ձևափոխությունների հետ, իսկ data residency-ն կամ առկա ենթակառուցվածքը կարող են այն բացառել։ Self-hosting-ը VPS-ի կամ container-ների վրա՝ nginx-ով և CDN-ով, կայուն տրաֆիկի դեպքում ավելի էժան է և ամեն ինչ մի տեղում է պահում, բայց թիմը պատասխանատու է այն մասերի համար, որոնք Vercel-ը ավտոմատացնում է՝ TLS, zero-downtime deploy-ներ, instance-ների միջև ընդհանուր cache-եր, version skew, log-երի հավաքում և մոնիթորինգ։ Adapter-ներ օգտագործող այլ պլատֆորմները գտնվում են մեջտեղում։ Առկա սերվերային թիմով և կանխատեսելի տրաֆիկով հաճախորդի համար թեքվում եմ դեպի self-hosting, իսկ փոքր մարքեթինգային թիմի համար սովորաբար հաղթում է managed պլատֆորմը։

Բառարան

RSC payload
Server Component-ների serialised ծառը, որը client router-ն օգտագործում է էջը թարմացնելու համար՝ առանց HTML բերելու։
Client router cache
Prefetch արված և այցելված route segment-ների հիշողություն բրաուզերում, որն օգտագործվում է նավիգացիան ակնթարթային դարձնելու համար։
Dynamic API
cookies(), headers() կամ connection() ֆունկցիաների նման ֆունկցիա, որը պարտադրում է request-time rendering այնտեղ, որտեղ օգտագործվում է։
Partial Prerendering
Prerender արված ստատիկ shell-ի անմիջական սպասարկում և դինամիկ մասերի stream՝ Suspense-ի «անցքերի» մեջ, յուրաքանչյուր request-ի համար։
Cache tag
Cache արված տվյալներին կցված պիտակ, որպեսզի այդ պիտակով բոլոր գրառումները կարելի լինի միասին invalidate անել։
Proxy (proxy.ts)
Middleware-ի անունը Next.js 16-ում. կոդ, որն աշխատում է routing-ից առաջ՝ redirect, rewrite անելու կամ header-ներ սահմանելու համար։
Server Action
Client-ից կանչվող server ֆունկցիա, որը կոմպիլյացվում է POST endpoint-ի. պետք է ինքը վալիդացնի և authorise անի։
Version skew
Հին build-ի կոդով աշխատող բրաուզերը խոսում է նոր build աշխատեցնող սերվերների հետ, ինչը բացակայող chunk-երի կամ action-ների է հանգեցնում։
Standalone output
Build ռեժիմ, որը պատճենում է միայն սերվերը աշխատեցնելու համար անհրաժեշտ ֆայլերն ու կախվածությունները. իդեալական է Docker-ի համար։
Cache handler
Միացվող մոդուլ, որը պահում է Next.js-ի cache գրառումները, օրինակ՝ Redis-ում, և ընդհանուր է բոլոր instance-ների համար։

Պրոդուկտի գաղափար ունե՞ք։Եկեք ստեղծենք այն։

Պատմեք ձեր գաղափարի, պրոդուկտի կամ թիմի մասին։ Սովորաբար պատասխանում եմ մեկ աշխատանքային օրվա ընթացքում։