Выживание в JS-экосистеме: Аутентификация, Netlify и новые правила Next.js 16

 · 3 min read

Бэкенд на Python — это предсказуемо и стабильно. Инфраструктура на Google Cloud — это строгие правила и прозрачные логи. Но как только мы шагнули на территорию современного фронтенда, чтобы сделать портал выдачи API-ключей для нашего SaaS, мы оказались на американских горках экосистемы JavaScript.

Surviving Js Ecosystem Clerk Nextjs

Нам нужна была всего одна страница на Next.js, куда мы могли бы встроить компонент <UserProfile /> от Clerk. На бумаге это выглядело как задача на пару часов. В реальности мы потратили день на борьбу с хостингами, устаревшими документациями и неявными конвенциями.

Выбор хостинга: Cloudflare, Vercel или Netlify?

Первой задачей было найти дом для нашего фронтенда (app.flude.guide). Мы выбирали из трех вариантов:

  1. Cloudflare Pages: Был нашим первым кандидатом, ведь там уже успешно крутятся все наши статические сайты, включая блог. Но приложение SaaS — это Server-Side Rendering (SSR). Чтобы запустить Next.js в Cloudflare, нужны Workers и адаптеры вроде OpenNext. Выяснилось, что свежий Next.js 16 и библиотека @clerk/nextjs жестко завязаны на Node-специфичный модуль async_hooks, которого просто нет в рантайме Cloudflare Workers. Сделать же статический экспорт (output: 'export') мы не могли — Clerk требует живого сервера. Вариант отпал.
  2. Vercel: Родная гавань Next.js. Мы могли бы запуститься на бесплатном тарифе (Hobby), но их правила честного использования (Fair Use Guidelines) категоричны: коммерческое использование запрещено. Даже если проект пока не приносит денег, наличие оплачиваемых разработчиков в штате уже нарушает правила. Платный Pro-тариф за $20/мес был бы безопасен, но зачем платить на старте за инфраструктуру страницы с околонулевым трафиком?
  3. Netlify: В отличие от Vercel, их бесплатный тариф официально разрешает коммерческое использование (подтверждено на форумах поддержки). Next.js SSR поддерживается нативно, а комбинация Clerk + Netlify проверена в бою. Мы выбрали их.

Война со сканерами Netlify

Выбрав Netlify, мы настроили пайплайн и отправили код в релиз. Сборка тут же упала с ошибкой безопасности.

Оказалось, встроенный сканер секретов Netlify увидел в конфигурации строку NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY и заблокировал деплой, решив, что мы закоммитили приватный токен. Нам пришлось потратить время на изучение документации, чтобы вручную прописать в netlify.toml исключение SECRETS_SCAN_OMIT_KEYS. Мы буквально доказывали хостингу, что публичный ключ — публичен.

Surviving Js Ecosystem Clerk Nextjs Part 2

Тихая поломка: Next.js 16 и переименование файлов

Решив проблему деплоя, мы приступили к авторизации. Согласно официальной документации Clerk, защита роутов настраивается в файле middleware.ts. Мы всё настроили, залили код, но авторизация просто не работала — страница пускала всех подряд. Никаких ошибок в логах, просто тишина.

Мы убили несколько часов, прежде чем поняли, в чем дело. В Next.js 16 поменялись внутренние конвенции: файл промежуточного ПО (middleware) теперь обязан называться proxy.ts. Стоило нам переименовать файл — и авторизация заработала. Из-за одного измененного слова в конвенции фреймворка безопасность всего приложения молча отключилась.

Surviving Js Ecosystem Clerk Nextjs Part 3

Внезапный deprecation: Гонка за стандартами

В том самом файле proxy.ts мы настроили защиту нашей страницы /account через специальную функцию Clerk — createRouteMatcher. Это был рекомендованный подход.

Но радость была недолгой. Мы случайно обнаружили, что этот паттерн защиты роутов на уровне middleware уже переводится в разряд устаревших (deprecated). Clerk менял философию в пользу “Resource-based auth”.

Нам пришлось экстренно вырезать всю логику роутинга из proxy.ts, оставив там лишь “голый” проброс контекста (export default clerkMiddleware();), и перенести защиту внутрь серверных компонентов. Теперь страница /account/[[...rest]]/page.tsx сама вызывает await auth.protect() перед рендерингом. Вчерашний стандарт “Best Practices” оказался legacy еще до того, как мы успели выпустить проект в релиз.

Что дальше?

С горем пополам мы дожали фронтенд. SaaS обзавелся рабочим биллингом, безопасными облачными воркерами и порталом для получения API-ключей. Архитектура была готова.

Но как только мы расслабились, мы решили переименовать базовый формат экспорта нашего ядра из markdown в hugo_markdown. Это безобидное решение пошло волной по всей распределенной системе, сломав контракты между движком, воркерами и клиентами. О том, как мы устраняли этот «эффект бабочки» — читайте в следующем эпизоде.