Comments 6
Переход на Next.js 15 позволил
Судя по статье, это не Next позволил, а разные решения типа кэширования в Redis, которые были вынуждены искать после перехода.
Не совсем.
Мы смогли реализовать много крутых решений благодаря возможностям Next.js и его отличной совместимости с Vercel, особенно с Edge Functions. Это дало нам кучу гибкости и помогло выжать максимум из технологий.
UPD: Также Next.js 15 предоставляет гибридный SSR/ISR/SSG, мощное кеширование через CDN и Redis, отличную поддержку TypeScript, а его интеграция с Gravity UI позволила адаптировать UI под серверный рендеринг. Всё это сделало его идеальным выбором для Hikasami.
Например чистый React:
1. Отсутствие SSR
2. Нет встроенного кеширования
Или возьмем тот же VueJS:
1. ISR не реализован. Он реализован только в NuxtJS (Но наша команда никогда не писала на NuxtJS и вряд ли когда то будет)
2. У Vue довольно слабая экосистема. (Vercel, Cloudflare)
Спасибо за статью, есть вопрос интересный по нексту: как вы делаете и делаете ли вы вообще карту сайта для поисковиков. Сам пытался на нексте это сделать, но закопался. Хотелось бы как-то удобно генерировать все артиклы без заморочек.
Спасибо за вопрос! В Next.js 15 генерация sitemap.xml может быть сложной, особенно если у вас есть динамические страницы, создаваемые по query‑параметрам. Однако, есть несколько способов это реализовать:
1️⃣ Разделение на статические и динамические страницы
Статические страницы (/about, /contact, /privacy) можно вручную добавить в sitemap.
2️⃣ Использование generateStaticParams (если маршруты известны заранее)
Если у вас есть предсказуемые динамические маршруты (/blog/[slug]), можно автоматически получить их во время билда:
export async function generateStaticParams() {
return [{ slug: 'article-1' }, { slug: 'article-2' }];
}
Это отлично работает для предварительно известных маршрутов, но не поможет с query‑параметрами.
3️⃣ Генерация sitemap без БД и API (автоматическое сканирование файлов)
Если маршруты заранее неизвестны, можно автоматически сканировать папку app/, чтобы получить все страницы:
app/sitemap/route.ts
import { NextResponse } from 'next/server';
import fs from 'fs';
import path from 'path';
const SITE_URL = 'https://hikasami.ru';
/**
* Автоматически получает все маршруты из папки `app/`
*/
function getRoutes(dir: string, prefix = ''): string[] {
let routes: string[] = [];
for (const file of fs.readdirSync(dir)) {
const fullPath = path.join(dir, file);
if (fs.statSync(fullPath).isDirectory()) {
if (file.startsWith('[')) {
routes.push(`${prefix}/${file.replace(/\[|\]/g, '')}`);
}
routes = [...routes, ...getRoutes(fullPath, `${prefix}/${file}`)];
}
}
return routes;
}
export async function GET() {
const staticPaths = ['/', '/about', '/contact'];
const dynamicRoutes = getRoutes(path.join(process.cwd(), 'app'));
const allPaths = [...staticPaths, ...dynamicRoutes].map((route) => `${SITE_URL}${route}`);
return new NextResponse(
`<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${allPaths.map((url) => `<url><loc>${url}</loc><lastmod>${new Date().toISOString()}</lastmod></url>`).join('')}
</urlset>`,
{ headers: { 'Content-Type': 'application/xml' } }
);
}
4️⃣ Получение sitemap через API (если маршруты хранятся в базе данных)
Если страницы создаются динамически по API, можно получать их так:
📌 app/sitemap/route.ts (получение через API)
import { NextResponse } from 'next/server';
const SITE_URL = 'https://hikasami.ru';
async function fetchRoutesFromAPI() {
const res = await fetch(`${SITE_URL}/api/articles`);
if (!res.ok) return [];
const articles = await res.json();
return articles.map((article: { slug: string }) => `/blog/${article.slug}`);
}
export async function GET() {
const staticPaths = ['/', '/about', '/contact'];
const dynamicRoutes = await fetchRoutesFromAPI();
const allPaths = [...staticPaths, ...dynamicRoutes].map((route) => `${SITE_URL}${route}`);
return new NextResponse(
`<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${allPaths.map((url) => `<url><loc>${url}</loc><lastmod>${new Date().toISOString()}</lastmod></url>`).join('')}
</urlset>`,
{ headers: { 'Content-Type': 'application/xml' } }
);
}
В чем разница?
generateStaticParams работает только для известных на этапе билда маршрутов (используется в page.tsx).
Сканирование файловой системы (как в коде выше) автоматически добавляет страницы без запроса к БД.
Запрос к API → позволяет обновлять sitemap динамически для контента из базы данных.
Итог
Статические страницы → добавляем вручную.
Динамические страницы с slug → используем generateStaticParams.
Динамические страницы с API → запрашиваем маршруты через fetch.
P.S. Надеюсь, все правильно расписал, только что вернулся домой. Если что-то упустил — буду рад обсудить!
Редактировано: телепортировал сообщение не по адресу.
Next.js 15 в Hikasami: Глубокая оптимизация рендеринга, загрузки данных и производительности