Галоўная / Артыкулы / 20 прыглых шаблонаў Next.js для стварэння аплікацыяў у формате App Router высокага ступеня готовасці

20 прыглых шаблонаў Next.js для стварэння аплікацыяў у формате App Router высокага ступеня готовасці

Выучыце 20 аптэкты Next.js высокага рангу, якія абарачваюць дизайн на адпаведнасці сервера, стрімінг, кэшаванне, маршрутызацыю і практыкі павышэння працоўнасці, каб ствараць быстрэйшыя та масштабаваныя прыкладнікі для практычнага вжытку.

2928 слоў

Большасць разрабоў выбірае Next.js. Досвідчаныя інжынеры розумеюць яго філасофію.

Якща вы калі-небудзь пераглядаўы просьбу пра з’еднанне коду ад каго-то, хто выучыў Next.js выключна з відэаурок, вы, верагодна, заўважылі певную законамасць: усё ўпакована ў кліентскі компонент.

Это не ледачасць. Гэта проста тое, як показвалі відэаурокі. useState, useEffect, 'use client' — распаўшыяся па кожным файлу, як стандартная приправа. Гэта працюе. Код можна розмістіць у сервісе. Але чырэз калькі месцаў пакет JavaScript перасягае 400 KB, рэйтынгі Core Web Vitals стаюць червонымі, і каманда не можа з’ясавіць, чаму простая маркетынговая стораніца працюе повольна паўтарыльна да натывнага додатку.

Самэ гэта разлік і ўскладнюе розлік межы людзей, якія выкарыстоўваюць Next.js, і інжынераў, якія справжняя розумеюць яго.

З моменту появы App Router Next.js ператворыўся з фрэймворку React у ўсё бол цяплую да повнайсткай платформы для стварэння аплікацый. Старыя прыпускі больш не практычны. Канцэпцыі, якія ў Next.js 13 считаліся „розвітымі“, тепер є стандартам. А тэхнікі, якія сьогодні визначаюць серйозны, готовы до выкарыстоўвання код — дизайн, спрямованный на сервер, рэштыраныя стратэгіі кэшавання, выконанне на краю сеті, частковая рэндарызацыя — рэдка калі з’являюцца ў навучальных матэрыалах, адзіначаных для пачаткуючых.

Це ўвядзенне у тыя тэхнікі. Адгук 20 шаблонаў, кожны з якіх супроводжваецца поясненням, чаму ён важны.

Частка 1: Думайце пра сервер адначасова з компонентамі, а не толькі пра компоненты

Найважнейшая змена ў мысленні для работы з сучасным Next.js — гэта: сервер павінен быць вашай выходной точкай, а не кліент.

Большасць разрабоўкаў на React спачатку думаюць пра компаненты. Яны інстынктыўна апіраюцца на хукі, стан і логіку з боку прыгледача, таму што так іх спачатку навчалі. App Router суперасцягвае гэты інстынкт. Асалодны вопыт не ў тым, "Чы рэштацый гэты фрагмент патрэбуе інтэрактыўнасці?" — а ў тым, "Чы рэштацый у гэтага фрагмента ёсць які-небудзь прычына выканацца ў прыгледачы?"

Шаблон 1: Серверныя компаненты як стандарт

export default async function Posts() {
  const posts = await db.posts.findMany()
  return <PostList posts={posts} />
}

Тут няма useEffect. Няма запыту да API, які бы стварыўся з боку кліента. Няма індыкатора загрузкі для дадзенняў, якія моглі бы ўжо быць готавыя перад атрыбутаваннем сторункі.

Компаненты сервера означаюць меньшыя за размерам пакеты JavaScript, якія адправляюцца да браузера, адносна вышэйшыя гарантіі безпекі (акулькі паролі да вашай базы дадзеных ніколі не выходзяць за межы сервера), а таксама быстрэйшая загрузка пачатковай сторанкі. Кансэпт прост: якщо элемент інтерфейса не выкарыстоўвае інтэрактыўнасць, нема прычыны, чаму ён павінен выконвацца на стороне кліента.

Шаблон 2: Пашановаўце граніцы сервер/кліент

Гэта тая сфера, дзе разработчыкі часта робяць помылкі. Межа, якая раздзеляе код сервера і код кліента, — гэта не проста канцэптуальны напамінак; система актыўна яе санкцыонуе.

Функціі не можна перадаваць через гэтую межу. Таксама не можна перадаваць экземпляры класоў. З’яўленні да базы дадзеных абсалютна забраняюцца. Толькі даны, якія можна серыялізаваць, магуць пройсці через гэтую межу.

// ✅ Fine — posts is plain JSON
<ClientComponent posts={posts} />

// ❌ Will explode — passing a function as a prop to a client component
<ClientComponent onFetch={db.posts.findMany} />

Якщо з самага пачатку разумець гэтыя правіла, адно это захавае вас ад цэлага класу проблем пад час выканання, якія ўскладнююць адшукаўцю іх прычыны.

Шаблон 3: Стратэгічны падход да 'use client'

Кожны раз, калі вы дадаеце дырэктыву 'use client', вы плаціце певную цену:

  • Больш JavaScript-кода, які падае ў бандл
  • Дадатковая робота пад час запуску сторанкі
  • Дапаможнае спрацоўвання памяці пад час выканання ў браузеры

Падход, на які паслугоўваюць апытныя інжынеры, — ранкі ўсю інтэрактыўную логіку як можна нижэй у дрэве компонентаў, жадацьна ізольаваную ў найменшыя лістовыя компоненты.

Page (Server)
├─ ProductList (Server)
├─ ProductDetails (Server)
└─ AddToCartButton (Client)  ← only what truly needs the browser

Усе інша застаецца на серверы. Гэта не прытворная оптымізацыя — гэта проста правильны архітектурны падход.

Частка 2: Атрыбутаванне, якое не змушвае корыстніка чакаць

Шаблон 4: Інтерфейс з стрімінгам і функцыяю Suspense

Нічага так не паслабляе вражанне прыгучасці, як метод адрасавання дадзеных у формате «водопад». Шаблон знаёмы: порожнія стораніца, пасля чаго спінер, а потым усё выклікаецца на экранах одночасна, калі всі даны готавы.

Next.js рашае гэтыя проблемы за дапамою стрімінгу у поўнасці з викорыстанням меж Suspense.

export default function ProductPage() {
  return (
    <>
      <HeroSection />  {/* renders immediately */}
      <Suspense fallback={<Skeleton />}>
        <ProductList />  {/* streams in */}
      </Suspense>
      <Suspense fallback={<ReviewSkeleton />}>
        <Reviews />  {/* streams in independently */}
      </Suspense>
    </>
  )
}

Адвіцэнты отрымаюць візуальную адпаведнасць за частку секунды. Інтерфейс складаецца па часткам, а не зупініцца на самай медленнай запытке.

Вважаеце гэты падход стандартным для будзь-якага компонента, який залежыць ад запыткі да базы дадзеных чыста вантарнага API.

Шаблон 5: Частковая прадзеявка (PPR)

Частковая прадзеявка ўваходзіць у число найболей прыемных ідэй, якія команда Next.js запроставала апошнім часам.

Раней было неабяжна выбраць адну з двух пазылкі: абсалютна статычная сторанцы, якія завантажваюцца быстра, але могу паказваць застарэлыя данні, або абсалютна дынамічная сторанцы, якія застаюцца актуальнымі, але завантажваюцца медленней. PPR усунуў гэты выбор «або-альбо». Адна траекторыя можа сумешваць оба режымы — часткі, якія не зменяюцца, перадаюцца через CDN, а тые, якія зменяюцца, стрімуюцца жыва з сервера.

┌─────────────────────────────────┐
│  Hero (static shell — CDN)      │
│  Navbar (static shell — CDN)    │
├─────────────────────────────────┤
│  User Dashboard (dynamic)       │  ← streamed from server
│  Recommendations (dynamic)      │  ← streamed from server
└─────────────────────────────────┘

Статычны фарш паказваецца мгновэна, а дынамічныя часткі заполняюць яго па мере ўсунення прычын іх недаступнасці. Для пользователя сторанца здаецца быстрой. З боку інфраструктуры большая частка кантэнта выдаецца дарожча через кэшаванне. Оба цялі выпалоўваюцца адразу.

Частка 3: Траектарыі за межамі базавых прыемаў

Траектарыі на адной з файлаў ёсць загальна ведамым дакументам сярод разработчыкаў Next.js. Знaczна меньшае колькість людзей даследзіла, чым на самае працэс траектарызацыі можна ўпрынцыпе скорыстацца, калі перайдзеш за межы базавых прыемаў.

Шаблон 6: Групы маршрутаў для раздзелення домэнаў

Групы маршрутаў дазволяюць структураваць папкі вашага проекту так, каб яны не выказваліся ў URL. Весь механізм заключаецца у тым, што назву папкі пакладаюць у кантэнеры.

app/
├─ (marketing)/
│   ├─ page.tsx       → /
│   └─ about/page.tsx → /about
├─ (dashboard)/
│   └─ analytics/     → /analytics
└─ (auth)/
    └─ login/         → /login

Кожная група можа маты свойі власныя структуры, станы завантажэння і межы адлічэння памылак. Гэта не проста спосаб размяркованасці — у большым кодавом базе гэта тое, што запобегае змешанню разных домэнаў прыкладнення.

Шаблон 7: Паралельныя маршруты для складных структураў

Інтерфейсы у стылі панелі керування часта выклікаюць патрэбу ў кансолькіх незалежных джерелах дадзеных, якія трэба адрасаваць адразу. Паралельныя маршруты створаны самэ для такіх ситуацый.

app/dashboard/
├─ layout.tsx
├─ @metrics/
│   └─ page.tsx
├─ @activity/
│   └─ page.tsx
└─ @notifications/
    └─ page.tsx

Кожны атрыбут з ім’ям запрашоўвае та відображае даны за свайм графікам. Повольна завантажуваемы контент у аднам атрыбуте не будзе споваліваць іншыя, таму корыстувальнікі бачаць кожны фрагмент даных як толькі ён стае доступным.

Шаблон 8: Перехопленне маршруту для модальных шаблонав

Это механізм, які стоіць за вяроятна знайомым вам функціоналам у Instagram, Pinterest та безлічы інтэрнет-магазінаў: як толькі вы натыкаецеся на мініатюру товара, пад якой ап’являецца модальне вікно на верхній частцы текущай стороніцы. Але як толькі вы перезавантажыце тую ж стороніцу, вы практычна бачыце повную, самостойную адпраўку товара. Той жа URL, але два розныя відображэння залежна ад таго, як вы тут опінаваліся.

Click product card → modal overlay (fast, in-context)
Refresh / share URL → full product page (SEO-friendly)

Такая поведэнчнасць — це перехопленне маршруту. Это тэхніка, якая робіць дапрыемным та плавным викорыстанне прыстрою, а не такім, дзе кожны клік перазначае ваш контэкст та пераводзіць вас на абсалютна новую стороніцу.

Частка 4: Кэшаванне з намерам, а не випадкова

Кэшаваннее ў Next.js раней спанукала людзей да памылак, таму што вяліка частка яго адбывалася непазірна. Інодзе вы отрымвалі застарелыя даны, калі спакоюваліся на свежыя рэзультаты, а інодзе — наадворна: базовая логіка не была зрозумела з напісанага вам коду.

Сучасны падход дозволяе кэшаваць даны намерова, на высокай ступені дзеярожнечы. Якша опанаваўце гэтыя два патерны, большая частка тых старых памылак знікне.

Патерн 9: Розумна кэшаванне падчас запытам

// Fresh every 60 seconds
fetch('/api/posts', { next: { revalidate: 60 } })

// Never cache — always fresh
fetch('/api/user', { cache: 'no-store' })

// Static — cache forever until manually invalidated
fetch('/api/config', { cache: 'force-cache' })

Спрыяйце гэтаму як да свядомага рашэння, а не як до стандарту, які вы залишаеце без змян. Пытанне, якое трэба задаць, — гэта наскількі застареласці можа вытрымаць даны, прычым яны не стануць справжнім проблемам для корыстніка; цяжарэчкай, якая дае адказ на гэта пытанне, і будзе ваша настройка revalidate.

Патерн 10: Анулюванне кэша на аднойчыні

Калі фрагменты дадзейнаў залежаць адзін ад другога, тонкай нарадзе выкарыстоўванне недзейнасці є правым адпаведнікам. Дадзіце тагі да своих запытанняў fetch, а потым чыстаце кэш для конкрэтнага тагу кожны раз, калі змянююцца падлеглыя дадзеныя.

// Tag the fetch
fetch('/api/posts', { next: { tags: ['posts'] } })

// Later, in a Server Action after a post is created:
revalidateTag('posts')

Правильная недзейнасць кэша є сапраўдзіцца складной проблемай у будзь-яй распадзёнай системе. Next.js даў вам надзейны элемент для ўсунення яе — выкарыстоўваце його, а не прабуяце обходзіць яго.

Частка 5: Мутацыі, дизайн API і месца размешчэння логікі

Шаблон 11: Адзінкі дзеяння сервера заместо маршрутаў API

Работа з такім простым ўздоўжнем, як адправка формы, раней вымагала сінхронной работы калькі элементаў: кліентскага компонента, запытання fetch у ям, аддзельнага працоўніка POST для приймання гэтага запытання, а таксама обробкі паказакоў, якая была дублювана на обох сторонах.

Сэгодні весь гэты процес спраўляецца за дапамогою значна меншага колькіства коду:

'use server'

export async function createPost(data: FormData) {
  await db.post.create({ title: data.get('title') })
  revalidateTag('posts')
}

Вы вызываеце гэта безпосередзя з усередзібы компонента. Не трэба визначаць окольны маршрут API і няма падобных структураў — фрэймворк сам абавядаецца праблемамі, зв’язанымі з HTTP-зв’язкамі.

Прычынная перавага — не толькі меншая канцэнтрацыя на набіранні тэксту. Гэта таксама зменшывае колькасць мест, дзе можа выйсці проблема. Менш файлоў і менш элементаў, якія трэба кераваць, адразу прыводзіць да меншага колькасці бягов.

Шаблон 12: Оптымістычны UI

Інтерфейс, які здаецца повольным, зазвычай ў тым сенсе, што чакае на адпаведны адказ з сервера пры выкананні будзь-яых змян. Рашэнне заключаецца у простай последовасці: адразу апডейтаваць UI, на заднім плане падтвердзіць змяны на серверы, а якщо падтверджэнне не выйде — вернуць UI у пачатковы стан.

User clicks Like
↓
UI updates instantly (optimistic)
↓
Server Action runs
↓
Success → confirm | Failure → rollback

Хораша ідея – такая тэхніка дае веб-дзеянням атмасферу, падобную да натывных. Але якщо ўжо не прабачаць належны спосаб рывка назад, гэта пагубнае – корыстнікі почынаюць з’являць увагу, калі тое, што яны бачаю на экране, не падходзіць да таго, што фактычна было захаванае, і гэта несуразнасць разрушае довер’е да дзеяння.

Шаблон 13: Роут-хэндлеры як шар API

Server Actions – не найлепшы інструмент для кожной задачы. Webhooks, інтеграціі з сервісамі трэціх сторон і мобільныя кліенты ўсе чакаюць стандартных REST-канцаў, і самэ гэта і дае Роут-хэндлеры.

// app/api/posts/route.ts
export async function GET() {
  const posts = await db.posts.findMany()
  return Response.json(posts)
}

Заказваць Server Actions трэба толькі для мутацый, якія запускаюцца з власнага UI. Калі трэба, каб ўсё, што знаходзіцца за межамі вашага Next.js дзеяння, звяжалася з яго, вам патрэбны Роут-хэндлеры.

Частка 6: Выконавчая спроможнасць – не дагэнуты элемент

Шаблон 14: Edge Runtime для задач, чульных да затрымкі

Сервісы аутентыкацыі, персоналізацыя, функцыйныя флагі — усё, што павінна выконвацца з кожным прыходзячым запитам, выгадвае, калі працюе на серверы, які знаходзится фізычна поблізу від адвярцеля. Самэй гэта і дае рантайм на краю сеті.

export const runtime = 'edge'

Разглядзім адвярцеля ў Мумбаі: падключэнне да вузла на краю сеті ў Сінгапуре проты падключэння да сервера-выконавця ў Вірджыніі стварае разлік прыблізна 20 мс проты 200 мс. Якщо такія парадкі будуць у великай колькасці трафіку, гэты разлік пачне вплываць на колькасць перакрыцэнняя.

Проблема заключаецца у тым, што рантайм на краю сеті падтрымае значна меньшы набор API. Натыўныя модулі Node.js не падтрымваюцца, і немае доступу да файловай системы. Пераканайцеся, што ваш код дэйсна працуе там, перш чым паспелагацца на яго.

Шаблон 15: Сервісы проміжнага програмавання для спяльных задач

Мідлвэр выпалюецца раней, чым адрадзіваецца які-небудзь маршрут, таму ён становіць ідеальную базу для пераконтроўкі аутанацыі, логіки керавання функцыямі, перэнаправленняў з урахоўваннем локалізацыі і маршрутацыі для тэставання типу A/B.

export function middleware(req: NextRequest) {
  const token = req.cookies.get('auth-token')
  if (!token) return NextResponse.redirect(new URL('/login', req.url))
}

Логіку ў мідлвэре трэба заставляць мінімальной. Паколькі ён запускаецца з кожным запитам, будь-што складнае, што вы там дадзеце, прызведае да збільшэння затрымкі ў всім вашым дапаможным працоўніку.

Шаблон 16: API дадзеных мета-інфармацыі для эфектывага SEO

Рэндарынг з боку кліента раней быў негатыўны для SEO — заголовкі аднойчы зменяліся за дапамогою document.title пасля таго, як сторана завантажылася, а мета-тагі дадаваліся пасля цього, — і краўлеры або ўвогуле праігноравалі гэтыя змены, або індексавалі неоднаковыя версіі стораны.

API дадзеных мета-інфармацыі пераносіць гэту адпаведнасць назад на сервер, дзе ёй і месца.

export const metadata = {
  title: 'Product Name | Store',
  openGraph: {
    title: 'Product Name',
    description: 'Product description',
    images: ['/og-image.jpg'],
  },
}

// Or dynamic:
export async function generateMetadata({ params }) {
  const product = await getProduct(params.id)
  return { title: product.name }
}

Якщо ваш дапаможны працоўнік базуецца на контэне, спрыяваць гэтам як неабавязковым практычна немагчыма.

Шаблон 17: Кантроль веб-віталіяў

Нельзя парадыктуваць тое, што ніколі не меряеце. Next.js аднаёт вам вбудованы хук для збору данных пра выконвальную спроможнасць у рэальным часе працы з браузераў корыстнікаў.

export function reportWebVitals(metric) {
  // Send to your analytics platform
  analytics.track(metric.name, { value: metric.value })
}

Тры паказнікі, якія варта стежыць, — это LCP (што такое швальна адобразуецца большы элемент, які ўжо відразу видны), FID (што такое швальна стораніца рэагуе на першую дзейнасць корыстніка) і CLS (насколькі элементы перамешваюцца пасля завантажэння). Гугл урахоўвае самэ гэтыя паказнікі пад час ранжавання у пошуку, і самэ гэтая спроможнасць або медлівасць відчуваюць корыстнікі.

Шаблон 18: Аналіз пакетаў

Перш чым прабаваць парадыктуваць выконвальную спроможнасць, пераканайцеся, што насправды адправляецца у браузер.

ANALYZE=true next build

Рэзультаты частаца дывуюц каманды. Частае явішчэнне — дуплікаванне залежнасцяў, код, які ніколі не выкананы на критычным шляху, або важкія бібліятэкі, якія маюць легкія альтернатывы. Напрыклад, імпорт moment.js можа дадаць 70KB да пакета, які за рэалістычныя расчытанні павінен складаць 30KB. Вы не знаеце гэтага, пакуль фактычна не пераглядзіце.

Частка 7: Архітэктура у масштабе

Шаблон 19: Структура Monorepo для вялікіх каманд

Калі база коду Next.js пачынае служыць для колькіх продуктов — напрыклад, додатку для публічных корыстнікаў, внутрашняй панелі адарботчыка і сайту дакументацыі — вы сталкваліся з выборам. Вы можете трываць кожны продукт у сваёй сабе репазітарыі, што быстра становіцца проблемай для сінхронізацыі, але можаце таксама аб’еднаныць усё ў одны Monorepo, што дае вам аб’еднанаяе кераванне залежнасцямі, спакуеныя бібліятэкі компонентаў і адну лінію CI.

apps/
├─ web/          → customer app
├─ admin/        → internal tools
└─ docs/         → documentation

packages/
├─ ui/           → shared component library
├─ config/       → shared TS/ESLint/Tailwind config
└─ types/        → shared TypeScript types

Спалучыце гэты лейаут з Turborepo для кэшавання рэзылтатаў будовання і з PNPM для калектывавання працоўных прастораў. Наладка гэтага праблематыкі карыць працой апошні дзень, але за гады ёна компенсуецца завяршэнням павтаральной працы і усуненнем расхіднасцей между проектамі.

Шаблон 20: Мышленне па дизайну систем

Гэта тое, што насправдзе адразняе высокакваліфікаванага інжынера Next.js ад менее кваліфікаванага: гэта майже не стосуецца таго, чыі ў ягох запам’яталіся межы Suspense чы синтаксіс Server Actions. Найболей спроможныя развіцелі можуць быстра выучыць гэты синтаксіс.

Тое, што насправдзе іх адразняе, — гэта спосаб, якім яны разумеюць систему в цэлыя.

Аптэктыраныя інжынеры разрабатваюць стратэгію кэшавання яшчэ до таго, як пісаць логіку запрашэння дадзей. Яны вяршыцьяюць, дзе знаходзіцца межа сервера/кліента, пры стварэнні компонентав. Яны визначаюць ліміты прыдатнасці яшчэ перад тым, як пачаць працаваць з JavaScript. Їхнёй стандартным запытам є "дзе і чаму трэба выконваць гэты код?", а не проста паводле звычкі.

Next.js выйшаў за межы простага фрэймворка для рэндаравання — тепер ён выступае як платформа для архітектуры прыемоў. Вы можете безпасэродзей практыкаваць рашэнні, стосуемыя всей структуры прыема, у ягоўскай складовай: дзе вядуцца вычысленні, калі апошнія дадзеныя аднаўляюцца, як рэндаруецца кожная стораніца. Няма прычыны складваць з разных бэкенд-сервісаў ўніверсальны рашэння, каб практыкаваць такі контроль.

Это выражае рэальныя змены ў тым, што включае ў сябе інжынерыя фронтэнду. Разработчыкі, якія ўсвойць гэта, ствараюць системы, якія працуюць быстрэй, коштаюць менш на аператыўнае выкананне і лёгчэй падтрымваюцца з часам. Тыя, хто гэтага не робіць, часта вжываюць кліентскія компоненты ў всіх месцах, а пасля дзівуцца, чаму програма працюе повольна.

Куды далей

Гэтыя двадцать шаблонаў не прызначаны як спіс пунктав, якія трэба адзначыць. Яны ствараюць спакойную лексыку.

Калі вы зможаце точна обсудзіць межы сервера і кліента, спроекаваць падход да кэшавання для стороннікай у контенте або обґавардаваць выбор рантайму на краю заместо функцыі без сервера, вы працуеце на правильным роўні мышлення.

Наступным крокам не ёсць запам’ятовваць дадзейшыя шаблоны. Це — ствараць ўсё рэальнае, выкорыстоўваючы іх у рэальных умовах — з жорсткімі термінамі, супернікаючымі працоўнымі прапорцамі, кодам, які нельга проста перапісаць. Самэ такая среда дазволяе прабавіць вашы ментальныя моделі пад тэнзам і дапамагае сформаваць адпраўныя рашэння.

Выберыце тры шаблоны, якія ўсё болей значныя для таго, над чым вы зараз працуеце. Застосавайце іх цялеспрямована. Потым перейдзіце да наступных трох.

Гэта справжні шлях да таго, каб стаць высокакваліфікаваным інжынерам — не ведаючы кожной можлівай тэхнікі, але маючы глыбокое розумэнне тых, якія дзейсна маюць значэнне.

Спадзяючыся літаратура