amorgunov
1.85K subscribers
16 photos
1 video
101 links
Пишу о JavaScript и его экосистеме (TypeScript, React, NextJS), о процессе разработки и архитектуре.

Блог: https://amorgunov.com
По всем вопросам (рекламу не продаю): @saaaaaaaaasha
Download Telegram
И кстати, сейчас проходит одна из самых больших конференций по JS в ру-сегменте - HolyJS. Завтра (11/11) community-день, который будет бесплатным (чтобы получить доступ, нужно просто зарегистрироваться).

Я бы не сказал, что будут какие-то громкие доклады, но есть интересные темы, про PWA, опыт использования эффектора (стейт-менеджер, который мне не зашел), свой рендерер (react-reconciler) на примере игры, очередной доклад про то, как улучшать перформанс приложения. Полное расписание (и там же есть кнопка для регистрации) доступно по ссылке: https://holyjs.ru/schedule/days/2/ .

А на youtube канале HolyJS выложили доклады с весенней конференции, держите ссылку на плейлист. Я еще не добрался посмотреть, но по списку, там много крутых спикеров выступало, должно быть интересно.
Привет, друзья. Вижу по реакциям, что анонс бесплатного дня HolyJS не зашел. А вообще, хотели бы на канале видеть анонсы различных конференций или оставить это новостным каналам?

Например, недели две назад прошла конференция perfnow() 2022 (https://perfnow.nl/speakers), посвященная веб перфомансу и метрикам. Я конечно же ее пропустил, но по описанию были крутые доклады. В паблике пока доступны записи двух из них (ссылка на плейлист).

1️⃣ «What’s new in performance?» - обзор новых фичей для оптимизации веба.
Back/forward cache для быстрого перехода через браузерные кнопки вперед/назад, про приоритет загрузки ресурсов Priority Hints, новый (относительно новый) HTTP статус 103 Early Hints, новую метрику Interaction to Next Paint, браузерное API isInputPending(), который возвращает true, если пользователь взаимодействует со страницей (например, вводит символ в инпут), и функцию postTask, которая позволяет планировать вызовы функций (задач) с нужным приоритетом. И еще про новый способ замера метрик производительности не просто для загрузки страницы, а для прохождения пользовательского сценария через puppeteer и Lighthouse.

2️⃣ «Early Learnings for Early Hints at Shopify» про оптимизацию с помощью Early Hints (http статус 103, который позволит браузеру предзагружать ресурсы до отдачи index.html). Например, пока на сервере подготавливается страница, браузер может предзагрузить шрифты или установить DNS-соединение с CDN. Все это можно сделать и сейчас с помощью атрибутов preconnect и preload, но уже после получения html-страницы (в отличие от Early Hints). По замерам из доклада, Early Hints + preconnect показывает хорошие результаты и уже сейчас улучшает показатель метрики Largest Contentful Paint (LCP), хоть и незначительно (на 1-2%). Основная проблема - сложность на стороне сервера научиться возвращать нужный статус и заголовки, указывающие, какие ресурсы нужно предзагружать. Ну и пока эту фичу поддерживает только Chrome.

Кстати, там же выступал Иван Акулов (@iamakulov_channel) с материалом про новый параллельный режим работы React-а (пока к сожалению без записи).

В общем, давайте проголосуем:

👍 - Скидывать все анонсы конференций, которые посчитаю нужным
👎 - Не скидывать
👌 - Скидывать точечные анонсы профильных конференций и обзоры интересных докладов
Что нового в NextJs 13 - Layouts

Все же хочу завершить серию постов про NextJS, ждите еще пару в ближайшее время. В этот раз про новую (13) версию NextJS. И если в прошлый раз я писал про Turbopack, то сегодня про другое нововведение. Turbopack, кстати, продолжают активно обсуждать в твиттере, автор Vite/Vue (Эван Ю) запускает бенчмарки у себя и находит странные детали, что не такие уж бенчмарки и честные.

Неделю назад я рассказывал про RSC - серверные компоненты. Используя их, а также, Transition и Suspense API, стриминговый рендеринг (фичи из последних версий реакта) реализовали новую версию Layouts (пока только в beta). Простыми словами - систему навигации по приложению.

Придумали новый механизм работы со страницами, лайаутами (включая вложенные) и загрузкой данных. На конференции был 23-минутный доклад, где продемонстрировали новый подход (посмотреть можно на youtube). Теперь все страницы по умолчанию - это RSC. По сути это асинхронные функции, которые рендерятся только на стороне сервера и в которых можно делать запросы за данными через async-await (правда в NextJS пока это реализовано через экспериментальный хук use).

С одной стороны, круто, что команда NextJS пытается внедрить фичи из React, а не реализовывать их с нуля. Теперь в NextJS можно использовать RSC (*), потоковый ренденринг, роутинг с частичной гидрацией (сам лайаут страницы статичен, и обновляется только контент внутри) и собирать все это в продакшен-бандлы из коробки. Ден Абрамов в твиттере написал тред после конференции и сказал, что 13 версия - это наиболее полная попытка реализовать новую архитектуру React, соединяя все части вместе.

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

Моя личная боль - для работы с новым подходом опять использовали файловый роутинг (только теперь все это лежит не в директории pages, а в директории app). В каждом приложении должна появиться такая директория, в которой будут описаны страницы, например:

app/
movies/
[id]/
page.ts
layout.ts
page.ts
error.ts // ошибка
layout.ts // лайаут
loading.ts // лоадер
page.ts // сама страница


Для небольших проектов или проектов с SSG (Static Site Generation, которые полностью генерируются на этапе сборки) выглядит удобно, но для больших проектов с десятками страниц нужно намного больше гибкости.

Серверные компоненты могут жить только в этой директории, тем самым приложение разделяется на две части - клиентскую и серверную (которую не можем переиспользовать на клиенте). Например, есть модуль "Auth", все его составляющие лежат в features/Auth, а его серверные компоненты должны жить в app, что выглядит как минимум странно. Я всегда борюсь с тем, чтобы компоненты в приложении были разбиты не по страницам, а по доменным сущностям, но здесь мы откатываемся назад.

Если в RSC нужно использовать какую-то внешнюю библиотеку, у которой явно не прописана директива "use client" в начале файла, то при подключении возникнет ошибка и нужно создать свой "клиентский" компонент враппер. Если нужно использовать какой-нибудь хук (useEffect, useContext), то же самое, создавайте враппер - хуки не работают в RSC. И это только проблемы, которые лежат на поверхности.

У команды из NextJS очень сложная задача по дальнейшему развитию этой фичи. Нужно активно собирать фидбек, думать над улучшением DX, так как в текущем виде реализация очень спорная. Посмотрим, что будет дальше.

Бандлер Turbopack в альфе, Layouts в бете, есть ли смысл использовать новую версию NextJS? На самом деле есть, и на рабочем проекте мы это сделаем из-за еще одной фичи. Но о ней в следующий раз.
Серверная часть NextJS

Любой фреймворк, поддерживающий SSR из коробки, можно считать «фуллстек» фреймворком. У таких решений помимо клиентской части есть и серверная. NextJS не исключение, у него под капотом есть встроенный сервер (на основе NodeJS-модуля http), запускающийся при вызове команды next dev или next start).

Если мы работаем над энтерпрайз приложением, то, вероятно, встроенный в NextJS сервер уже не подойдет из-за ограниченного функционала. Поэтому обычно запускают свой (express, fastify), внутри которого программно создают экземпляр NextJS-приложения (https://nextjs.org/docs/advanced-features/custom-server). В рамках этого сервера обрабатывают все необходимые инфраструктурные и не только задачи (кеширование ответов, работа с метриками для мониторинга, настройка ручек «живости» контейнера, предзагрузка данных).

Тут хочется сказать пару слов про подход BFF (Backend for frontend), под которым обычно подразумевают легковесный веб-сервер. На нем можно проксировать запросы в бекенд(ы), сетить куки и http-заголовки, маппить данные с разных источников, обрабатывать редиректы, обрабатывать SSR и т.д. Это своего рода API Gateway, используемый под конкретный тип клиентского приложения (например, мобильного или веб-приложения). Кастомный сервер для NextJS, это тот же BFF.

Еще из особенностей, за BFF обычно ответственны фронтенд разработчики (правда не всегда).

В NextJS 12 появился встроенный механизм миддлвар (сеттинг кук и заголовков, редиректы), позволяющий не настраивать свой сервер. Но в таких миддлварах нельзя было вернуть свой ответ, т.е. нельзя было отдать готовую html-страницу (или данные) из кеша и отправить ее пользователю, из-за чего все равно приходилось поднимать свой сервер.

А уже в 13 версии появился функционал, позволяющий возвращать кастомный ответ из миддлевар. И мы можем отказаться от программного запуска NextJS, так как теперь есть все для полной обработки запроса.

Собственно из-за этой фичи у меня есть желание мигрировать проект с 12 версии на 13 (благо это будет не сложно, так как мы еще не в продакшене и нестрашно будет что-то сломать в процессе) и попробовать реализовать BFF чисто на встроенном механизме миддлвар. Единственная проблема, что для готовых веб-серверов (express) уже написано много библиотек, которые не получится переиспользовать.
Трофей тестирования

В прошлом году я выступал на нескольких митапах, где рассказывал про тестирование фронтенда. Одна из самых интересных вещей на мой взгляд - это трофей тестирования и слои, из которых он состоит.

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

В общем это модифицированная пирамида тестирования, но только для фронтенда. Аккумулировал знания по трофею в виде отдельного поста в блоге: https://amorgunov.com/posts/2023-04-01-testing-trophy/

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

Мое первое впечатление о NextJS сложилось еще полгода назад, когда я написал пост: «Почему я не использую NextJS» (читайте на блоге: https://amorgunov.com/posts/2022-10-14-why-i-am-not-using-nextjs/). Название кликбейтное, но на самом деле хотелось поделиться проблемами, которые, казалось бы, не должно возникать у фреймворка такого масштаба.

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

Прошло полгода и я могу сформулировать еще одну крупную проблему. NextJS в режиме SSR (или ISR, Incremental Static Regeneration, где тоже нужен сервер) не приспособлен к деплою на self-hosted машины. А если быть точнее, ничего не доступно из коробки. Метрики отправлять можно только через кастомный сервер (подключив поверх express или fastify), который не рекомендуют использовать. Нет гибких методов кеширования, кроме http-кеширования на уровне страницы. Логгер можно подключить только через monkey-patching. Никаких оптимизаций для отказоустойчивости и боль при работе с картинками (расскажу отдельно). Кстати, что касается метрик, то нет публичного API, чтобы мерить время серверного рендеринга JSX → HTML.

Если приложение деплоить на серверах Vercel (компания, которая разрабатывает NextJS), то там многие проблемы решены (так как настроена инфраструктура). Еще есть готовые решения мониторинга и аналитики сервера, типа https://newrelic.com/, которые так же закрывают часть проблем. Однако, (1) это дорого, (2) в текущих реалиях нельзя использовать и (3) тот же NewRelic, например, для сбора метрик тупо патчит внутренние методы NextJS (тут можете подробнее по изучать).

Возможно часть пунктов, перечисленных выше, и не должны решаться в рамках NextJS. Но я был крайне удивлен, что информацию приходилось собирать по кусочкам со всего интернета. Полноценных примеров/руководств, о том, как настраивать все это для NextJS - попросту нет. Если бы у меня и моих коллег в команде не было опыта работы с NodeJS, то было бы в разы сложнее.

Я не первый раз ругаю NextJS, но все же признаю, что в нем много крутых фич, о которых расскажу далее.
tailwindcss - 🔥 or 💩?

В последнее время часто встречаю посты о модном молодежном CSS-фреймворке tailwindcss (да что посты, уже вакансии появляются с «хорошо было бы знать»). Для тех, кто не знаком, это библиотека с огромным количеством написанных css-классов, используя которые в 99% случаев не нужно писать CSS вручную. На гитхабе у него аж 66 тысяч звездочек.

Но я не понимаю такого восторга. Огромное количество css-классов в коде (в className может прокидываться до 30-40 значений, если у вас несколько тем или адаптивная верстка). Высокий порог вхождения (там просто сотни классов, которые нереально помнить).

И самое больное (в сердечко) - это обезличенные компоненты. DOM-дерево превращается в портянку безликих дивов, даже в примерах на главной странице не всегда понятно, что в коде (карточка товара или слайдер, что за кнопка, блок и т.д.). Можете посмотреть примеры кода по ссылке https://tailwindcss.com . Кто бы как не относился к БЭМ-у, но он очень хорош в плане компонентной архитектуры CSS. Есть блок (= компонент), есть элементы блока и модификаторы. По исходному коду (или девтулзам) сразу понятно: футер (.footer), бургер меню в шапке (.header__burger-menu), сайдбар в раскрытом состоянии (.sidebar_opened).

Недавно посмотрел доклад с митапа по этой теме: https://www.youtube.com/watch?v=GMID4_t3EXU В презентации был выделен ряд проблем, включая те, которые я описал выше, а также возможные варианты их решения. Например, группировка классов по брейкпоинтам через classnames, использование test-id атрибутов для задания названий компонентов, инкапсуляция части стилей в свой класс для переиспользования. Еще подключить ESLint и VSCode плагины, чтобы было все по красоте. Посыл заключается в том, что нужно уметь правильно работать с tailwind и будет не все так плохо. Но зачем все это, когда можно использовать css-модули или тот же css-in-js?

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

Если кто-то из чата уже использовал (или использует) tailwindcss на рабочих проектах, поделитесь своим опытом и фидбеком. Возможно нужно больше времени, чтобы все настроить и проникнуться идеей. Я пока придерживаюсь следующего – заверстать небольшой лендинг или пет-проджект – возможно подойдет. Но никак не для большого проекта.
Будущее React

Наткнулся на комментарий Дэна Абрамова в пул реквесте документации реакта, в котором популярный ютубер Тео Браун (t3gg) предложил заменить Create React App (CRA), инструмент для создания проекта на React от разработчиков самого реакта, на Vite для новых проектов.

Дэн подробно описал мнение команды о том, как они видят использование React в будущем. CRA был создан в качестве коробочного решения, которое (1) упрощает развертывание нового приложения на React и в котором (2) собраны лучшие практики DX (горячая перезагрузка, красный экран с ошибками в рантайме, простое обновление версий реакта). Все это сложно настраивается с нуля.

В настоящее время CRA в текущем виде умер (те, кто сидит в твиттере, наверняка видели твиты типа «CRA is dead»). Это произошло не из-за того, что под капотом используется webpack (медленный по сравнению с альтернативами), или из-за того, что за почти год в нем не было никаких правок и новых фич, несмотря на огромное количество ишьюсов (хотя из-за этого тоже). Просто команда реакта не видит в качестве целевой картины использование чистого React для новых приложений (только для ограниченного количества кейсов). Под чистым реактом я имею в виду client-only приложения, другими словами Single page application (SPA). А CRA умеет собирать только такие приложения. Дэн описал проблемы SPA: (1) долгая загрузка и белый экран, (2) размер бандла и (3) network waterfalls (когда первый запрос за данными может отправиться только после полной загрузки JS-кода).

Мое мнение о CRA всегда было довольно негативным из-за того, что у него не было возможности расширить функциональность без использования eject (функция для выноса всех внутренних конфигов наружу). И мне не попадался ни один проект на CRA, в котором не использовался eject. Следовательно, главное преимущество (коробочное решение) пропадало, и оставались тонны конфигов, которые нужно было поддерживать уже самим.

И по итогу Дэн отмечает, что сейчас проблемы выше решаются на уровне фреймворков, которые так же предоставляют другие фичи (SSR или SSG, код-сплиттинг, (пред)загрузка данных, роутинг, навигация с сохранением клиентского UI стейта - лайауты и т.д.). А сам реакт будет помогать фреймворкам, развивая слой рендеринга (из последнего, это suspense, transition, серверные стриминг и компоненты). Теперь при старте проекта официально рекомендуется использовать именно один из фреймворков в режиме SSR/SSG и не использовать подход SPA (чистый реакт на том же Vite). А из CRA возможно сделают CLI-инструмент, который будет выбирать подходящий инструмент под вашу задачу.

Извините за такое количество аббревиатур, легко запутаться, но когда во фронтенде было по другому. Что забавно, CRA удалили из документации по реакту, Vite - не добавили. Сейчас там красуются NextJS, Remix и Gatsby (https://react.dev/learn/start-a-new-react-project).

Что касается SPA (на том же Vite), я кстати совсем не согласен, что это всегда хуже использования фреймворков, но об этом как-нибудь в следующий раз.
Будущее React (2)

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

Для тех, кто не читал предыдущий пост, то core-команда React-а задепрекейтила CRA (create react app) и думает развиваться в сторону UI-слоя для мета-фреймворков. В документации остались только мета-фреймворки (NextJS, Remix), и теперь там нет ни одного официального решения для запуска в рамках SPA.

Я вижу две ветки развития:

1⃣ Реакт развивается не как самостоятельный фреймворк, а как UI движок того же NextJS. Плюсы очевидны: фичи, над которыми команда разработчиков работала последние годы, будут полностью раскрыты, а так же решены проблемы SPA, что приведет к еще более производительному фронтенду. Не побоюсь сказать, к следующему этапу эволюции фронтенда, когда часть вычислений переносится на сервер. И несмотря на то, что я к этому скептически отношусь, это звучит многообещающе и довольно амбициозно.

Но есть и некоторые проблемы. Во-первых, резко вырастет кривая обучения до кривой мета-фреймворков. Сейчас для старта всего лишь нужно с помощью CRA/Vite развернуть проект и можно начинать знакомство. Зачем новичков погружать в SSR, RSC, особенности внешних решений? Часть людей это просто отпугнет, а у другой потеряется фокус на изучении именно реакта, и как с ним эффективно работать на стороне клиента (а реакт требует не мало ручных оптимизаций, чтобы быть производительным).

Во-вторых, сообщество разделится на два лагеря, поскольку большая часть разработчиков продолжат использовать реакт в качестве самостоятельного решения для SPA. И как следствие, часть туториалов/документации будет актуальна только для мета-фреймворков (например, серверные компоненты), другая - только для SPA приложений.

В-третьих, это зависимость от внешних решений. У руководства NextJS (Vercel) есть свои интересы. У них есть свои облачные сервера, на которых некст отлично работает. Я уже упоминал, как трудно запустить приложение на своих серверах (из-за закрытого API самого некста, плохой документации по серверной части и большой работе по настройке инфраструктуры). По сути рекомендованная схема будет такой: или используйте NextJS на серверах Vercel, или не используйте вовсе. Но разве это хорошо для опенсорс решения?

И последнее, если React станет большую часть времени уделять именно поддержке мета-фреймворков, то он сильно проиграет с точки зрения клиентского опыта альтернативным решениям (привет, SolidJS).

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

По какому пути пойдет команда реакта?
В прошлом месяце я начал работать над пет проектом на стеке React/Redux-Toolkit/Vite, используя методологию Feature Sliced (FSD). Вы можете посмотреть на него здесь: https://github.com/noveogroup-amorgunov/nukeapp

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

Сейчас я экспериментирую именно с FSD. Это архитектурная методология для фронтенда, которая говорит, как правильно должны быть расположены директории в проекте, а модули взаимодействовать друг с другом. Внутри себя FSD объединяет различные лучшие практики, такие как вертикальные слайсы, публичный API, композиция модулей, чистая архитектура, low coupling high cohesion. На мой взгляд это лучшее, что сейчас есть на рынке. Но по ряду причин методология часто используется не верно, а порой приносит больше вреда, чем пользы (мало примеров, много ситуаций, которые FSD никак не регламентирует, да и в общем архитектура - всегда сложно).

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

В общем, если вам будет интересно посмотреть на Feature Sliced в бою, то заглядывайте в репозиторий. Кстати, ссылку на проект добавили в примеры на официальный сайт методологии (https://feature-sliced.design/examples), поэтому проект уже принес небольшую пользу сообществу, пополнив шоукейс методологии.
Всем привет! С того момента, как я опубликовал предыдущий пост, количество звездочек у репозитория на гитхабе выросло на 140%, почти догнав все официальные примеры по Feature Sliced методологии. Спасибо за поддержку ❤️

Ниже хочу поделиться некоторыми техническими моментами, которые открыл для себя, делая этот пет проект:

- Насколько же приятно работать с бандлером Vite. У меня есть ассоциации с Vue (на котором я очень давно не писал, но это был очень приятный опыт с точки зрения разработки). Так вот так же и Vite, очень быстрый запуск, горячая перезагрузка, CLI стартер под нужный стек. Я ничего не могу сказать про большие проекты, на сколько в них Vite стабилен, но для небольших - работает отлично. Интересно в будущем попробовать SSR плагин в связке с React-ом.

- С помощью плагина eslint-plugin-boundaries можно (делать настоящую магию) задавать кастомные правила линтера для импортов внутри проекта. Для простых кейсов есть правило no-restricted-imports, для сложных - рекомендую именно этот плагин (на основе этого плагина сделано правило для импортов по FSD, которое я немного расширил для кросс-импортов в рамках слоя).

- Попробовал библиотеку zod для валидации runtime-структур. Описывайте схему объекта, с помощью которой можно и TypeScript тип вывести, и провалидировать данные. Можно проверять все то, что на момент компиляции типа unknown (переменные окружения, формы, параметры URL, ответы API и т.д.). Тоже рекомендую.

- Узнал, как работать с темным режимом. У меня на практике ни на одном проекте не было тем. Был приятно удивлен поддержкой браузеров (например, атрибут color-scheme), возможностями css-переменных для довольно простого переопределения цветовой палитры. А так же всяким UX штукам, что толщину шрифта на темных темах нужно делать меньше или накладывать фильтры на картинки, чтобы они были не такие яркие.

- И пару вещей про гитхаб: (1) бейджи для README можно генерировать в https://shields.io/ (куча интеграций и кастомные темы), (2) для светлой/темной тем можно отображать различные картинки в markdown файлах, добавив в ссылку на изображение специальный хеш: #gh-dark-mode-only или #gh-light-mode-only (подробнее в блоге самого гитхаба: https://github.blog/changelog/2021-11-24-specify-theme-context-for-images-in-markdown/).
ts-reset

Вы знали, что в TypeScript-е методы JSON.parse и response.json() внутри fetch по умолчанию неявно возвращают тип any? Мы и правда не можем знать, какая структура данных находится в строке или придет с бекенда в рантайме. Но вместо того, что вернуть unknown и явно сказать, что тип неизвестен, TypeScript для поддержки обратной совместимости возвращает any.

И таких небольших моментов довольно много: filter(Boolean) не сузит тип, Array.isArray или Array.from так же вернут any[], многие методы массива (includes, indexOf) будут некорректно работать с const assertions.

Мэтт Покок (на ютубе ведет канал про TypeScript) собрал такие кейсы в виде небольшой библиотеки ts-reset, которую можно подключить на свой проект в виде деклараций типов (d.ts файл). Все, что делает библиотека, переопределяет встроенные в TS интерфейсы (declaration merging). В issues можно посмотреть еще на ряд случаев, когда TypeScript плохо или странно выводит типы.

Подключив ts-reset к проекту, вы вряд ли получите какой-то вау эффект, но определенно сделаете типы на встроенные интерфейсы в языке лучше.
Валидация переменных окружения

Валидацией форм или параметров запроса никого не удивить, а вот на переменные окружения часто забивают и используют их напрямую. В чем проблема такого подход? Все переменные окружения в нашем коде будут типа string или undefined, даже если переменная описывает какой-нибудь булеан флаг или число. Поэтому часто в коде можно встретить конструкции типа process.env.IS_ENABLED === 'true' (здесь true - это строка) или parseInt(process.env.DELAY_MS, 10). И в каждом месте использования нужно не забыть сделать такую проверку.

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

1. Все переменные можно считывать в одном месте (например, в каком-нибудь src/env.ts файле), трансформировать/валидировать данные под нужный формат, а во всех остальных местах использовать уже подготовленные переменные. Как бонус можно запретить использование process.env.* за пределами этого файла с помощью eslint.

2. Я недавно писал про библиотеку zod, которая позволяет описывать схемы валидации. Она также позволяет трансформировать данные, а в одном из последних релизов появилась возможность приведения (coerce) примитивных типов. Например, в процессе валидации преобразовать входные данные к нужному примитивному типу (в нашем случае для переменных окружений, которые представляют собой числовое значение, преобразовать строку в число). Эта библиотека отлично решают задачу подготовки переменных.

Что нам дают эти два пункта? Приводим переменные окружения к нужному типу, валидируем их и не даем запустить проект при отсутствии обязательных.

Пример валидации env переменных с помощью zod можно посмотреть тут.
Всем привет! На выходных дописал пост в блог про архитектуру проектов на основе вертикальных слайсов: https://amorgunov.com/posts/2023-05-28-vertical-sliced-architecture-in-frontend/

Получилось немного сумбурно, но по итогу удалось сформировать универсальную структуру фронтенд проекта. Сейчас нет смысла собирать структуру с нуля (можно использовать тот же Feature Sliced), однако понимать архитектурные подходы, которые используются внутри, нужно. Особенно, если вы запускаете новые проекты или занимаетесь рефакторингом текущих (или планируете это делать в будущем). Вертикальные слайсы - один из таких подходов.
Друзья, всем привет! Почти год ничего не писал, и за это время накопилось большое количество тем, которые хочется с вами обсудить. Пора оживлять канал, поэтому в ближайшее время ждите посты про NextJS (RSC и React конечно же), про Feature-Sliced Design, про фронтенд платформу, про обзоры технических книг, которые я прочитал за последнее время и про многое другое, что каким-то образом связано с разработкой.

Для новеньких буквально пару слов о себе (а таких за год появилось довольно много, за что отдельное спасибо Виталию @web_platform, который собрал папку с фронтенд группами и добавил этот канал, вас стало чуть ли не в два раза больше). Меня зовут Александр, живу в Питере, работаю над клиентским веб приложением Самоката в роли техлида. До этого работал в Яндексе и аутсорсе. Иногда выступаю с докладами, периодически занимаюсь менторингом (много лет назад в Яндексе даже офлайн курс по фронтенду организовывал). Здесь публикую контент для уровня мидл и выше, совсем о базе почти не пишу. В любом случае всем рад, добро пожаловать!)

Кстати, на этих выходных (уже завтра) буду на конференции CodeFest в Новосибирске, после сделаю выжимку самых интересных докладов, которые получится послушать. Если вдруг тоже будете там, подходите пообщаться, большую часть времени буду у стенда Samokat_tech.
В марте выступал на MoscowJS и рассказывал про NextJS, о чем стоит знать, если вы хотите использовать его в своем проекте. Доклад всего на 20 минут, но краткую выжимку сделаю ниже.

Что важно знать про NextJS? У него сейчас доступны две архитектуры для разработки: Page Router (архитектура, реализующая стандартный SSR подход, которая считается устаревшей, но формально поддерживаемая разработчиками, на самом деле нет) и пришедшая на замену - App Router (доступна с 13 версии, вносит кучу новых фич, типа Streaming render, RSC, selective hydration, partial prerendering, все то, что было недоступно ранее). Эти архитектуры разделяют NextJS на два разных фреймворка (даже вся документация разбита на два независимых раздела).

Далее рассказывал про темные стороны (проблемы):

1️⃣ Серверная составляющая. Довольно важная тема, которую редко обсуждают - конфигурируемость и гибкость сервера, чем NextJS не может похвастаться. Нельзя без манки-патчинга собирать логи, без кастомного сервера собирать http-метрики (и даже с ним внутренние метрики рендеринга остаются недоступными), нет никаких инструментов для борьбы с отказоустойчивостью и работы с кэшированием. Получаем черную коробку с очень скудным публичным API для работы с сервером.

Справедливости ради, в App Router есть возможность работать с кэшем, но без него (и с RSC) приложение выжирало бы абсолютно все ресурсы серверов даже при небольшой нагрузке.

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

НО, приложение можно запустить на облачных серверах Vercel, и многие пункты выше станут неактуальными (кэширование/логирование/сбор метрик). И тут мы переходим ко второй проблеме.

2️⃣ Вендорлок. У сообщества создалось впечатление, что разработчики NextJS разрабатывают и проектируют фичи в первую очередь под запуск на серверах Vercel (логично, компания этим зарабатывает деньги), и уже после для запуска на своей инфраструктуре. А деплой на своей инфре из-за «бедного» сервера совсем не тривиальный. И все бы ничего, но одновременно React сильно привязался к NextJS. Многие последние фичи реакта поддержаны именно в нексте, что создает неявную связь, хочешь использовать реакт, будь готов деплоиться на Vercel.

3️⃣ Будущее. Тут я рассказывал про RSC (серверные компоненты реакта), о которых уже писал ранее. Чтобы их использовать (доступны только в App Router), нужно сильно переписать проект, если он изначально был на Page Router, из-за чего многие отказываются мигрировать (мы у себя тоже пока решили жить на старой архитектуре). И здесь проблема в том, что Page Router тихо перестают поддерживать и развивать, а многие ишьюсы просто закрывают с комментами "решено в App Router - используйте его".

А если проект начинать на App Router, то имеем другую пачку открытых ишьюсов уже в App Router, в части которых ребята из кортимы рекомендуют использовать Page Router (например баг с useParams в режиме SSG). Получаем замкнутый круг.

Какое дальнейшее развитие я вижу? Разработчики NextJS не смогут усидеть на двух стульях и поддерживать две архитектуры, и от App Router отказываться точно не будут. Поэтому первое, что сейчас важно сделать команде некста, это активно закрывать баги в новой архитектуре и в какой-то момент официально задепрекейтить старую (это точно негативно воспримет часть сообщества, но других вариантов я не вижу). И второе, работать над расширяемостью и кастомизацией серверной части, чтобы уменьшить поток критики по поводу вендорлок-стратегии.

Бонусом собрал немного полезного материала про NextJS, который использовал в ходе подготовки к докладу.
Завтра буду выступать на конференции «Я люблю фронтенд» от Яндекса и рассказывать про архитектурную методологию Feature-Sliced Design. Сделаю общий экскурс, разберу основные понятия, подробно остановлюсь на нескольких слоях (сущности, фичи и виджеты). Разберу проблемы, с которыми столкнулся на рабочем проекте: взаимодействие модулей на разных уровнях, кросс-импорты и нехватка слоев. Для каждой проблемы конечно же расскажу о возможных вариантах решения.

Если вы тесно работаете с методологией, то я вряд ли открою для вас что-то новое. Но если вы только планируете использовать FSD или просто тема интересна для вас, то присоединяйтесь к трансляции на ютубе. Сама конференция будет с 11:00 до 18:00, я начну вещать с 13:15 по МСК (запись тоже будет доступна).

P.S. На фото репетиция выхода на сцену (все серьезно) и финальный домашний прогон. Пока уложиться в 30 минут, отведенные организаторами на выступление, не особо удается, но буду стараться попасть точно в тайминги)
Неделю назад прошла конференция «Я 💛 Фронтенд 2024», на которой я в качестве спикера рассказывал про архитектурную методологию Feature-Sliced Design.

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

Уже давно хочу поделиться некоторыми мыслями насчет конференций (за последний год был на нескольких митапах, FrontendConf и CodeFest), что движение идет куда-то не в ту сторону. Часть с докладами уходит на второй план и уступает стендам партнерских компаний и охотой за мерчем. В ближайшее время соберу все вместе и закину свои рассуждения на этот счет.

Что касается моего выступления. Рассказал что из себя представляет методология FSD (= архитектурные паттерны + правила по неймингу структуры проекта), основные сложности при использовании (= нужно знать архитектурные принципы, многие вещи методология не регламентирует, интегрировать в существующий проект практически нереально). Далее на примере разобрали основные слои и перешли к проблемам: кросс-импорты, зависимости на разных слоях (которые решаются инверсией), нехватка слоев.

Несколько вещей, которые хочется отметить отдельно:

1️⃣ Было много хороших вопросов в чате, на какую-то часть ответил со сцены, на другие постарался ответить в чате конференции. Про микрофронты, про редакс со своим моностором, про внедрение в существующие проекты, про внедрение в компанию в целом, про то, можно ли замерить эффективность использования FSD. Может как-нибудь соберу все вместе и сделаю контрибьют в документацию FSD в раздел вопросов/ответов.

2️⃣ В чате написали, что как будто доклад про то, почему FSD не стоит использовать, сильно много проблем, которые приходится решать. На самом деле посыл был не такой. Проблемы есть у каждой методологии/фреймворка, FSD не исключение. Я мало говорил о достоинствах (и возможно зря), так как был сильно ограничен таймингами. Хотелось поделиться именно сложностями на основе реального опыта (считаю это самой интересной частью) и путями их решения. Через расширение методологии (местами через экспериментальные фичи) можно решить практически все, поэтому как минимум к изучению методологию точно рекомендую 👍

3️⃣ Про новый линтер. Пару недель назад core-команда анонсировала новый архитектурный линтер steiger, который выложили на гитхаб через несколько дней после выступления. Проект еще в статусе активной разработки, но у него очень большой потенциал. Его можно использовать и за пределами FSD, или использовать только те правила, которые релевантны для вас. Каждое правило - это обычная функция, в которой с помощью готовых хелперов можно делать самые разные проверки на директории, файлы или импорты внутри (например, правило проверки отсутствия публичного API у слоев https://github.com/feature-sliced/steiger/blob/master/packages/steiger-plugin-fsd/src/no-layer-public-api/index.ts#L5-L19). ESLint сильно ограничен по словам ребят, поэтому решили делать с нуля.

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

P.S. Все ребята, которые были офлайн и подходили задавать вопросы, подискутировать по FSD и в целом про фронтенд, спасибо вам! Был очень рад со всеми пообщаться)
Что нового во фронтенде

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

1️⃣ Серверные компоненты/экшены

В настоящее время идет довольно сильный мейнстрим на перенос части логики приложений на сервер (лучшие метрики типа TTFB/TTI за счет того, что часть JS-кода можно вообще не загружать на клиенте или загружать лениво). В React - это серверные компоненты, которые выполняются только на сервере и не попадают в клиентский бандл.

Сюда же отношу серверные экшены, которые реализуют RPC (remote procedure call) и позволяют исполнить код на сервере прямыми вызовами из клиентских компонентов. Раньше думал это чисто история в рамках NextJS, но как оказалось они уже много где реализованы.

Я до сих пор убежден, что 90% проектам все это не нужно и достаточно обычных SPA, но core-команда того же React сильно продвигает эти идеи, делая большой упор на серверные оптимизации, что подхватывают и другие.

2️⃣ Мета-фреймворки

У каждого фреймворка (React, Vue, Svelte, SolidJS, Angular) есть свой мета-фреймворк (NextJS, NuxtJS, SvelteKit, SolidStart, Analog), который отвечает за сборку, роутинг, загрузку данных, кеширование и различные режимы работы (SSR/SSG и т.д.). Кажется время, когда мы собираем все по кусочкам подходит к концу, и скоро старт любого нового проекта будет начинаться с использованием мета-фреймворка.

Хотя опять же считаю, что набор из Vite в качестве сборщика, роутера (ReactRouter), пакеты для работы с состоянием (Zustand+ReactQuery) будет достаточно для большинства проектов.

3️⃣ Серверные рантаймы

С учетом того, что сервер сильно интегрируется во фронденд приложения (серверные компоненты/экшены, смотри 1️⃣👆), то возникает вопрос: на чем и где его запускать? Раньше у нас был единственный выбор - NodeJS. Но сейчас ежегодно появляются различные решения, типа Deno (на самом деле появился уже давно), Bun или Egde Runtime для NextJS от Vercel. И скорее всего будут побеждать библиотеки, которые умеют работать на различных рантаймах и деплоиться на различные облачные сервисы. Например, SolidStart (метафреймворк для SolidJS) и NuxtJS (для VueJS) используют для серверной части Nitro, который как раз таки супер универсальный и может запускаться на любом ~холодильнике~ рантайме.

4️⃣ Island (островная) Architecture - архитектура, которую уже давно много кто реализует у себя, получила особую популярность вместе с фреймворком Astro. Идея простая: рендер всего приложения на сервере, кроме динамических частей (так называемых виджетов). Они возвращаются с сервера в виде пустых слотов (их еще называют плейсхолдерами) и уже после гидрируются на клиенте как независимые модули (типа отдельных приложений), получая для себя HTML так же с сервера. Подходы partial hydration, progressive hydration, streaming rendering как раз таки лежат в основе «островов».

NextJS пошел дальше и представил фичу Partial Prerendering (демка: https://www.partialprerendering.com), которая подготавливает статичную часть на момент сборки. Про это подробно писал SuperOleg.

5️⃣ Сигналы появились кажется уже везде (кроме React-а). Даже есть предложение на добавление сигналов в стандарт ECMAScript. Сигнал - это контейнер для значения (от примитивов до сложных структур данных), который может уведомлять потребителей об изменении этого значения. Другими словами сигнал обеспечивает отслеживание зависимостей при чтении и срабатывание эффектов при мутации (реактивный подход). Крутость в том, что на основе сингалов можно описать состояние и связать его напрямую с DOM-элементом без подписки на ререндер компонента. На таком подходе например построен компилятор SolidJS, который не полагается на виртуальный DOM, а делает биндинги напрямую к нативным элементам, что сильно улучшает перфоманс (условно изменение глобального провайдера контекста не будет вызывать перерендер всего поддерева).

Кажется все, но если что-то упустил, пишите в комментариях, сделаем вторую часть)