Прочтите это, если планируете работать с Next.js

от автора

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

Принципиальным решением всех этих проблем является опенсорсная модель разработки ПО. Если вы пользуетесь софтом, который разрабатывается открыто, то вы (как и кто угодно другой) вправе расширять или модифицировать его на ваше усмотрение, так, как того требует практика. Ещё важнее, что опенсорсное программное обеспечение легко портируется, и именно поэтому разработчики и организации вольны переносить свою инфраструктуру от провайдера к провайдеру, не опасаясь впасть в зависимость от конкретного поставщика.

Именно такие ожидания я связывал с Next.js — опенсорсным фреймворком для веб-разработки, созданным и управляемым компанией Vercel. Vercel — это облачный провайдер, предлагающий управляемый хостинг Next.js как услугу.

Вполне нормально, что компания зарабатывает на опенсорсном ПО, которое сама же и разработала — если это помогает финансировать дальнейшее развитие проекта. На самом деле, в отрасли найдётся множество примеров того, насколько успешна может быть эта модель.

Но я думаю, что устойчиво развиваться такая ситуация может лишь при условии, что границы между компанией и опенсорсным проектом прочерчены предельно чётко. У специалистов по поддержке продукта, хостинг-провайдеров и пользователей должны быть чётко определённые ожидания о том, как и где можно применять каждую конкретную возможность фреймворка.

Хочу объяснить, почему, на мой взгляд, сегодня такая прозрачность отсутствует.

Я не стремлюсь отговорить кого-либо от использования Next.js. Но в этом посте я постараюсь максимально информативно изложить всё, что знаю по теме, так, чтобы разработчики и компании могли принимать информированное решение, выбирая технологический стек.

Заявление о непредвзятости

Для начала немного о себе, чтобы подчеркнуть, что я незаинтересованная сторона:

  • Я работаю в Netlify вот уже более четырёх лет

  • Netlify — это клиентская облачная платформа, поддерживающая в рамках своих коммерческих предложений как Next.js, так и другие веб-фреймворки

  • Netlify и Vercel — прямые конкуренты

Мне важно обозначить всё это по нескольким причинам.

Моя работа связана с выстраиванием инфраструктуры и инструментария, необходимых для поддержки полного набора фич Next.js на Netlify. Благодаря этому я непосредственно имею дело с такими внутренними деталями фреймворка, которые большинство пользователей не видят. С годами я стал замечать удручающие примеры слишком тесной связи между опенсорсным фреймворком и инфраструктурой той компании, которая его развивает.

Именно из соображений профессиональной этики я всегда крайне осторожен при публичном озвучивании такой обеспокоенности. Поскольку я — сотрудник Netlify, я последний человек, которого можно заподозрить в объективной критике Next.js. Скорее вы вправе отмахнуться от моих слов и счесть, что Netlify натравила одного из своих молодчиков на конкурента, чтобы оклеветать Vercel.

Обычно мне не хватало духу вступать в такие дебаты, чтобы не подставлять ни себя, ни компанию, поэтому я всегда предпочитал трудиться, оставаясь в тени. Поддерживал разработчиков, принимавших решение развёртывать свои сайты на Netlify и ограждать их от всех тех сложностей, благодаря которым платформа может нормально работать.

Но потом кое-что случилось.

Недавно Vercel раскрыла информацию о том, что в Next.js обнаружена критически небезопасная уязвимость. Нормально, когда возникают подобные проблемы, но Vercel в этой ситуации повела себя настолько непрофессионально и беспечно, проявив при этом неуважение к сообществу, что этот случай предельно обострил мой негатив относительно того, как ведётся управление этим проектом.

На мой взгляд, всё меняется, если своими решениями вы подставляете людей под риск. Поэтому, извините, накипело.

Открытость и управление

Ниже я вернусь к этому инциденту и расскажу о нём подробнее, но сначала хочу позволить себе некоторую ретроспективу. Давайте заглянем за кулисы. У меня давно уже есть немало вопросов по поводу открытости и управляемости Next.js. Проблемы проистекают из целой последовательности решений, принятых Vercel за годы работы, и из-за этих решений другим провайдерам становится невероятно сложно поддерживать этот фреймворк в полнофункциональном состоянии.

Разберу эти проблемы, изложив ряд фактов об устройстве Next.js. Потом выскажу некоторые собственные соображения о том, насколько эти факты соответствуют нашим ожиданиям, предъявляемым открытому интероперабельному программному продукту, который, по идее, удовлетворяет потребностям большого предприятия.

Факт первый: никаких адаптеров

В большинстве современных фреймворков для веб-разработки известна концепция адаптеров. При помощи адаптеров вывод фреймворка конфигурируется под конкретную платформу, на которой планируется его развёртывать. RemixAstroNuxtSvelteKit и Gatsby — несколько примеров навскидку. Такой подход позволяет разработчику сохранять в неприкосновенности ядро приложения и просто сменить адаптер, если будет решено развернуть это приложение у другого провайдера.

Поддержкой этих адаптеров могут заниматься авторы фреймворка, хостинг-провайдеры, сообщество или все вышеперечисленные сразу. Как правило, фреймворки структурируются таким образом, что каждому под силу написать собственный адаптер, если адаптера для нужного вам провайдера пока в наличии нет.

В Next.js адаптеры отсутствуют как класс, и ранее постулировалось, что поддержки адаптеров в этом фреймворке не будет. Вывод сборки Next.js делается в проприетарном недокументированном формате, используемом в Vercel для предоставления инфраструктуры, обеспечивающей работу приложения.

В качестве альтернативы Vercel предлагала Build Output API, документированную спецификацию выходного формата для тех фреймворков, код из которых планируется развёртывать в Vercel.

Это не адаптерный интерфейс для Next.js, фактически, он не имеет с Next.js ничего общего. В посте с соответствующим анонсом было сказано, что Next.js поддерживает этот формат, но в настоящее время он его уже не поддерживает.

В ноябре 2023 года документацию по Next.js обновили, указав в ней, что Next.js впитает Build Output API в следующей мажорной версии фреймворка (то есть, 15):

Next.js производит стандартный материал, готовый для развёртывания и используемый управляемым фреймворком Next.js на собственном сервере. Так гарантируется поддержка всех функций, независимо от того, каким из двух методов было выполнено развёртывание. В следующей мажорной версии этот вывод будет преобразовываться в соответствии с нашей спецификацией Build Output API.

Next.js 15.0.0 вышел в октябре 2024 года без поддержки Build Output API.

Vercel выстроили Build Output API, желая, чтобы их клиенты могли задействовать богатую экосистему фреймворков, имеющихся в этой нише, но их собственный фреймворк по сей день не поддерживает этого API.

Таким образом, любым хостинг-провайдерам за исключением Vercel приходится выстраивать свой код поверх недокументированных API, в которые без предупреждения могут вноситься разрушительные изменения — в минорных версиях или даже в виде патчей. (Такое уже случалось.)

В конце прошлого года Cloudflare и Netlify присоединились к OpenNext. Это движение различных облачных провайдеров, совместно разрабатывающих опенсорсные адаптеры для Next.js. Вскоре после того Vercel вышла на контакт с этим движением и вызвалась оказать поддержку в разработке адаптеров. Они не взяли на себя никаких обязательств по срокам, но недавно заявили, что активно работают над адаптерами.

Важно помнить, что с момента официального запуска Build Output API прошло почти три года, а фреймворк до сих пор не портируется. Я с осторожным оптимизмом рассчитываю, что на сей раз ситуация изменится к лучшему.

Факт второй: нет официальной поддержки бессерверных вычислений

Официальные методы для эксплуатации Next.js на собственном сервере требуют, чтобы приложение работало с сохранением состояния, как долгоиграющие серверы. Притом, что технически это возможно, очень сложно работать таким образом в любой реальной продакшен-среде, где единственного инстанса всегда мало.

Такая конфигурация должна быть рассчитана на очень быстрое динамическое наращивание, чтобы справляться с внезапными всплесками трафика. В то же время, чтобы эта модель была экономичной, в ней нужно предусмотреть и свёртывание почти до нуля. Последний аспект принципиально важен при работе с серверными компонентами, например, в тех случаях, когда из-за глубокого перепутывания между клиентским и серверным кодом сравнительно старые клиенты могут выходить из строя, если, конечно, все без исключения версии серверного кода, которые когда-либо были развёрнуты, не будут доступны бессрочно.

Есть очевидный способ удовлетворить эти потребности — задействовать бессерверные вычисления. В пользу этого свидетельствует и официальная документация Next.js, в которой подчёркиваются достоинства этой модели:

Бессерверные вычисления способствуют распределению точек отказа, неограниченной масштабируемости, а также их очень легко себе позволить в рамках модели «плати за то, чем пользуешься».

Именно в рамках этой явно выигрышной вычислительной парадигмы Vercel не первый год эксплуатирует сайты с Next.js на базе своей собственной инфраструктуры. Учитывая, что Next.js — свободный фреймворк, логично ожидать, что ту же самую модель мы сможем использовать и при работе с любым другим провайдером бессерверных вычислений. Но всё не так просто.

Когда-то в Next.js был бессерверный режим, который можно было включить при помощи специального конфигурационного свойства. Но этот режим без каких-либо пояснений отключили в октябре 2022 года. Равноценного режима так и не ввели.

В официальной документации по React, с поддержкой которой помогала команда Next.js, сказано, что Next.js можно развернуть на «любом бессерверном хостинге», но это в документации вообще никак не прокомментировано.

Таким образом, любые провайдеры, желающие предложить поддержку Next.js в рамках именно той вычислительной модели, которую продвигает сам фреймворк, приходится буквально пересобрать его от основания и воплотить в собственной реализации.

Факт третий: Vercel-специфичные пути выполнения кода

В Next.js есть такие пути кода, которые выполняются только на тех сайтах, что развёрнуты на Vercel. Яркий пример такого рода — приватный флаг под названием минимальный режим, позволяющий Vercel перенести рабочую нагрузку из фреймворка и выполнить на своей собственной периферийной инфраструктуре.

Это важно и вот, например, почему. В Next 12 появилось промежуточное ПО, опосредующее, в частности, переключение фич, A/B-тестирование и продвинутую маршрутизацию. Сходство всех этих ситуаций в том, что логика должна выполняться по самому оживлённому пути, без привлечения кэша и с минимальной задержкой. По этому поводу было, в частности, анонсировано:

Работает из коробки с использованием next start, а также на платформах для периферийных вычислений, например, на Vercel, использующих Edge Middleware.

На практике это означает, что у вас всего два выхода: либо воспользоваться next start и выполнять как промежуточное ПО, так и всё остальное ваше приложение на сервере-источнике (который обычно охватывает всего один регион, после кэша), либо переходить на «платформу для периферийных вычислений, например, на Vercel», чтобы  промежуточное ПО выполнялось на периферийной инфраструктуре, до кэша. Так вы сможете открыть для себя все те невероятные прикладные случаи, которыми Vercel хвастается в источниках, ссылки на которые содержатся в анонсе.

Формулировка «на платформах для периферийных вычислений, например, на Vercel» явно означает, что существует множество альтернатив, так как другим провайдерам была предоставлена возможность также реализовать промежуточное ПО на периферийной инфраструктуре, правильно? Нет.  

Именно благодаря этому секретному минимальному режиму Vercel удалось открепить промежуточное ПО от остального приложения. После этого, естественно, промежуточное ПО можно гонять на периферийной инфраструктуре, но только Vercel доступна такая возможность.

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

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

Так почему же в Next.js есть эта потайная дверца, ключом от которой владеет только Vercel? Думаю, следует ожидать, что команда по поддержке фреймворка регулярно экспериментирует с фичами перед их полноценным запуском, но нет, с минимальным режимом это не так. Мы говорим о совершенно самостоятельном подходе к эксплуатации фреймворка, который был заложен в базе кода на протяжении многих лет и открывает возможности, зарезервированные компанией-владелицей фреймворка для собственного обогащения.

Представьте себе, что в WordPress есть привилегированный путь выполнения кода, доступный только на тех сайтах, которые развёрнуты со свойствами Automattic. Считался бы он в таком случае надёжным и по-настоящему открытым проектом, и занимал бы сегодня такое господствующее положение, как сегодня?

Что насчёт безопасности

Теперь вернёмся к тому инциденту в области безопасности. В пятницу 21 марта в 10.17 (UTC) Vercel опубликовала CVE о критическом инциденте в области безопасности, серьёзность которого была оценена в 9,1 из 10.

В сущности, кто угодно мог безнаказанно миновать промежуточное ПО Next.js — для этого нужно было просто отправить в запросе нужный заголовок. Это важно, поскольку аутентификация позиционировалась как одна из важнейших практических функций промежуточного ПО. Но этот эксплойт означал, что кто угодно может просочиться сквозь уровень аутентификации и завладеть доступом к защищённым ресурсам.

По мере того, как разворачивалось расследование это инцидента, выяснилось ещё несколько вещей. Во-первых, сообщение об этой уязвимости поступило команде Next.js 27 февраля, но заниматься ею команда начала только 14 марта. Приступив к делу, они стали усиленно фиксить версии Next 14 и Next 15, справившись с работой за пару часов.

Таким образом, уже 14 марта (не позже), Vercel было известно, что у них серьёзная брешь в безопасности. В такой ситуации наиболее ответственно было бы немедленно уведомить об этой уязвимости других провайдеров, чтобы те могли оценить, насколько пострадали их клиенты, а также предпринять все необходимые меры, чтобы как можно быстрее защитить пользователей. Защитить пользователей — наш долг, и в такие моменты он должен считаться приоритетнее любой межкорпоративной конкуренции.  

Но ситуация развивалась иначе. Vercel потребовалось 8 (восемь) дней, чтобы дозвониться до Netlify. За это время они успели пропатчить Next.js, отменить два релиза и даже тиснуть в блог статью, в которой инцидент подавался как какая-то неприятность, от которой клиентов «на упреждение защитил» брандмауэр Vercel. Хотя, их же технический директор позже сказал, что брандмауэр на эту уязвимость никак не влияет.

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

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

Затем Vercel выпустила постмортем, в котором — впервые — было сказано, что 21 марта они смогли «убедиться, что проблема не затронула Netlify и Cloudflare Workers». Почему же тогда их сотрудники сами обратились в Netlify 22 марта и предложили помочь «настроить патч»? Если нас не зацепило, то что тогда пропатчивать?

Такое пренебрежение всеми пользователями, работающими вне Vercel, только растревожило и смутило множество людей. Некоторые провайдеры пытались наспех найти решение, которое затем пришлось частично откатывать. Другие объявили, что уязвимость и не затронула, хотя, на самом деле они пострадали – и т.д.

Прямо сейчас, пока вы это читаете, никто не скажет наверняка, сколько сайтов ещё уязвимы перед этим эксплойтом — а ведь многие из них остались бы в безопасности, если бы к проблеме подошли иначе.

И в самом разгаре этой суматохи у руководства Vercel были… другие приоритеты.

Но ведь Vercel владеет Next.js

Так и есть. Они имеют полное право делать деньги на фреймворке, в который вложили столько труда, таланта, времени, энергии, выстроили его и вырастили. Не спорю с этим.

Но, будучи на такой высоте, ты обязан и держать марку, с чем, на мой взгляд, Vercel уже не в первый раз не справляется.

Иногда спрашивают: «Если Vercel владеет Next.js, то какой им интерес открывать его другим провайдерам?». Мне кажется, вопрос интересный. А зачем  Redis открывать свой софт, коль скоро они владеют Redis Cloud? А почему проект Grafana является свободным, хотя его разработчик владеет Grafana Cloud? То же касается WordPress, ClickHouse и многих других.

Суть в том, что они обязаны так делать, если решили выпустить свой софт как опенсорсный, а не как закрытый проприетарный. Мера их успеха в том, насколько пользователи уверены, что могут по своему усмотрению выбирать провайдера, предоставляющего именно тот набор услуг, который соответствует их потребностям в данный конкретный момент.

Заключение

Не мне вам указывать, каким фреймворком пользоваться. Если вам нравится Next.js, и вы по-прежнему считаете, что этот инструмент лучше всего решает стоящие перед вами задачи – безусловно, вам стоит им пользоваться. Но я надеюсь, что эта статья придаст вам уверенности в принятии решений, к какому бы варианту вы ни склонялись.

Что до меня, я и далее буду помогать пользователям, которые решили развернуть свои сайты на Netlify, независимо от того, какой фреймворк они предпочитают. Безотносительно конкуренции, я искренне хотел бы помочь Vercel сделать Next.js более открытым и интероперабельным фреймворком, участвуя в движении OpenNext.

Апдейт (28 марта): представитель Vercel пообещал «не привносить в продукт никаких новых привилегированных путей кода, а имеющиеся (например, минимальный режим) либо удалить, либо подробно описать в документации». Что касается сроков «есть надежда, что эти задачи удастся решить до конца года».


ссылка на оригинал статьи https://habr.com/ru/articles/898402/