Спустя полгода адаптации к OpenSource выпускаю еще две библиотеки из моего рабочего контура в одном npm‑пакете — ARFA Generator и api‑contract‑check. В этой статье расскажу про первый инструмент, а второй презентую в рамках отдельной статьи.
Когда‑то давно я уже писал статью про удобство использования файловых генераторов, интегрированных в долгоживущий процесс dev‑сборки, однако за несколько лет развития и обкатки в реальных проектах концепт существенно расширился. Удобнее всего оказалось сместить бандлер с центрального места в один из сайд‑эффектов после стабилизации кодовой базы, а разнородные инструменты проверки качества объединить в единый пайплайн с инкрементальным watch‑режимом.
В статье не буду пересказывать документацию на русском и английском, а расскажу, как я пришел к такой схеме, насколько она улучшает DX, помогает людям быть продуктивнее, LLM‑агентам сжигать меньше токенов, а кодовой базе не расползаться со временем и проще мигрировать между архитектурами.
1. Бандлеры захватывают цикл разработки
Во времена Gulp процесс бандлинга воспринимался как последовательная серия трансформаций исходного кода, результат которой — подготовленные для браузера файлы:
browserify('./index.js').bundle() .pipe(source('bundle.min.js')) .pipe(buffer()) .pipe(terser()) .pipe(gulp.dest('dist'))
Сервер для разработки и перезагрузка браузера настраивались отдельными программами. Впоследствии Webpack / Vite решили скрыть процедурный пайплайн за декларативной конфигурацией и внедрили сервер + HMR, получив название «бандлеры». Со временем именно они стали дефолтной точкой входа в процесс разработки, однако роль инструмента не изменилась — это «часть пайплайна, которая упаковывает артефакты для браузера», то есть просто операции над стабилизированным исходным кодом.
Мысль: у библиотек для сборки есть давно определенная роль, и их вполне можно встраивать в более широкое ядро разработки, учитывая, что сейчас и дев‑сервер, и перезагрузка браузера по SSE пишутся в несколько строк и не являются ограничением.
2. Исходный код — тоже артефакт
Иногда создается ложное ощущение, что наш код — истина в конечной инстанции. Да, конечно он трансформируется транспилятором, фреймворками (особенно это видно по шаблонам jsx или vue), переименовывается минификатором, но у программиста остается полный контроль и единоличная ответственность.
Однако то, что мы называем «тулингом» давно и прочно вошло в разработку. Eslint, Prettier, Oxc, Biome получили возможность не только давать рекомендации по исправлению кода, но и напрямую его редактировать. TSC, bun check, tsrs — контролируют корректность типизации и заставляют переписать код. Есть и много других детерминированных анализаторов и инструментов, которые напрямую влияют на вид и содержание кода, включая codegen‑утилиты.
Это хороший тренд — ответственность теперь не только на одном разработчике, а «коллективная» — насколько качественно настроишь инструменты, настолько это снизит пространство ошибок в программе и улучшит условно‑измеримые характеристики исходного кода вроде «согласованности между всеми разработчиками в команде» и «понятности для коллег». Но, к сожалению, все эти библиотеки — отдельные cli инструменты, и не имеют общего канала предоставления отчетов.
С приходом LLM у исходного кода появился еще один редактор с непредсказуемыми изменениями и собственными ограничениями, часть которых компенсируется именно детерминированными инструментами.
Мысль: на исходный код влияет множество участников с разной степенью контроля и предсказуемости, но они не объединены в единый пайплайн и не имеют общей обратной связи или истории внесенных изменений.
3. Бойлерплейт и пустая трата времени
Возможности детерминированного контроля исходного кода в настоящее время сильно недооценены. В процессе разработки любого проекта возникают рутинные задачи:
при написании нового редюсера нужно его добавить в общий файл и написать экшен
если в проекте договорились импортировать утилиты из одной точки, добавленный getTime.ts нужно не забыть добавить в реэкспорты
новые тексты в интерфейсе нужно синхронизировать с облачной системой переводов, не забывая удалять неиспользуемые ключи
присланные бэкендом данные необходимо валидировать и очищать от лишнего, чтобы не сломался Object.keys в легаси‑коде
при изменениях нужно поддерживать актуальность документации и тому подобное
Я привел лишь небольшое количество сценариев — в документации ARFA Generator приведены решения для десятков типовых задач: из структуры файлов, их наименования и контента можно вывести большое количество потенциально автоматизируемых операций. Сегодня разработчики вынуждены выполнять их вручную из‑за отсутствия подходящих инструментов, времени для их создания, или потому что «здесь всегда так делали».
Мысль: можно значительно сократить ручную работу и уменьшить когнитивную нагрузку и без использования LLM‑агентов.
4. Архитектура — тоже артефакт
Существует множество определений «архитектуры», но применительно к фронтенду обычно подразумевают «структуру файлов и модулей, включая именование», «границы ответственности» и «организацию потока данных». Часто это содержится только в устных договоренностях или документации, но может закрепляться в статическом анализе вроде eslint boundaries или даже выбрасывать исключение в рантайме (что часто делают в React при попытке подключиться к недоступному контексту).
Однако эти механизмы не дают целостного представления, и с ростом кодовой базы становится все сложнее отслеживать расхождения и дублирование. Для меня же основные критерии качества архитектуры — то, что ее можно сериализовать из кода, восстановив большую часть исходных правил; при необходимости без особых сложностей заменить на другую; детерминированно проверять соответствие принципам в едином пайплайне:
Первый инструмент проверяет, что экспортируемая функция / константа / стор именованы согласованно с названием файла
Второй строит сводную карту слоев (например, всех сторов, экшенов, роутов) или модулей / фич, по которой легко проверить дубляжи, несогласованный нейминг или случайно появившиеся лишние сущности
Третий проверяет соблюдение границ импортов
Четвертый по шаблону создает бойлерплейт или каркас новых модулей в соответствии с выбранным подходом
Пятый строит карты рантайма, показывающие, например, какие сущности доступны на конкретной странице. Это упрощает ревью и в ряде случаев позволяет быстрее найти проблемы
Шестой автоматически актуализирует документацию
При этом пайплайн должен уметь показывать и при необходимости удалять автоматически контролируемые файлы, позволяя изменить правила и легче мигрировать на другую архитектуру.
Мысль: фиксировать соглашения удобнее не в документах, а в детерминированных правилах с общей историей нарушений и списком контролируемых файлов.
5. Единый пайплайн
Итак, все предыдущие мысли наводят к закономерному выводу: ядром процесса должен быть не бандлер, который просто делает одну из операций, а реактивный инструмент, объединяющий разрозненный тулинг в единый процесс. Тут и выходит на сцену ARFA Generator, которым я пользуюсь в крупных проектах уже много лет, и который заиграл новыми красками после распространения ИИ. Он работает со следующими слоями:
Плагины — это мутирующие исходный код инструменты. Они запускаются итеративно — в цикле каждый из плагинов получает данные о модификациях, проведенных другими плагинами, пока кодовая база не стабилизируется. Могут писать, модифицировать и удалять файлы
Чекеры — это немутирующие исходный код инструменты, например tsc / eslint / test‑runner / AST rules enforcer. Выполняются после плагинов одним проходом — здесь нет необходимости в каскадных итерациях
afterCheckers — немутирующий исходный код колбэк, подходит для запуска бандлера в едином пайплайне
vite.build / esbuild.build / bun.build, то есть для превращения стабилизированного и проверенного кода в другую форму — для браузера, документации или внешнего анализаafterFinish — потенциально мутирующий код колбэк. Получает логи всех предыдущих этапов для вывода в консоль, а также здесь оптимально вызывать перезагрузку браузера или сигнализировать другим системам, что процесс полностью прошел. Можно вызвать и LLM‑агента, который изменит файлы и дальше запустит новый полный цикл
Этот пайплайн можно вызывать единожды (для CI) или в watch‑режиме для локальной разработки. Для LLM‑агентов также есть отдельная точка входа в виде команды cli, через которую можно получить информацию о последнем цикле в markdown‑формате с дефолтными инструкциями «исправлять первую значимую ошибку». При этом в самом пайплайне уже зафиксирован вызов определенных инструментов для каждого файла — ИИ не нужно это предсказывать, а человеку — задумываться при разработке.
Также слежение за всем исходным кодом, включая добавление новых файлов, позволяет сразу их включать в архитектуру, в отличие от watch‑режима бандлера, который не следит за файлами, отсутствующими в графе импортов (или следит, но никак не учитывает и не встраивает в известный граф).
6. Почему единый пайплайн стал возможным
За недолгое время существования веб‑разработки тулинг значительно развился. Раньше мысль о подобном пайплайне скорее пугала — ведь внедрение всех этих операций в цикл разработки означал бы не только 40 условных секунд пересборки на Webpack, а плюс столько же времени работы каждого из инструментов. Поэтому большинство разработчиков использовало схему дев‑разработки через watch режим бандлера — это давало хоть немного приемлемую производительность, а остальные инструменты запускались на pre‑commit или в CI.
Однако сейчас инструменты становятся настолько быстрыми, что эта схема является устаревшей. Сейчас пайплайн из плагинов + bun check / tsgo + Biome + bun test + esbuild для проектов размером около 100 страниц на Реакте занимает меньше 2 секунд (по замеру на ряде проектов, которые делал), а кроме того ARFA Generator дает механизмы их запуска только с изменившимися файлами, что еще больше ускоряет операции. Таким образом, и человек, и LLM‑агент очень быстро получают фидбек ото всех инструментов без дополнительной когнитивной нагрузки / сжигания токенов на то, какой инструмент сейчас стоило бы вызвать.
7. Пропущенный этап развития тулинга
Верхнеуровнево для меня процесс обучения веб‑разработке и в целом глобальное развитие подходов в разработке выглядит так:
Обучение с нуля, все пишется руками. В мире это означало отсутствие готового тулинга и были только базовые примитивы в виде языков программирования и browser API
Изучение готовых фреймворков и библиотек. Это время становления экосистемы и разделения мира фронтенд‑разработчиков по фреймворкам, развитие tsc / eslint и другого тулинга
Понимание ограничений и написание своих библиотек, решающих ряд необходимых задач эффективнее. В мире увеличивается количество разработчиков, инструментов, создается много компактных альтернатив раздутым «традиционным» решениям
Детерминированная автоматизация вроде ARFA Generator для гибкого объединения инструментов и избавления от надоевшего ручного бойлерплейта
Эпоха недетерминированной генерации на основе уже достаточно проработанных и стабильных исполняемых правил в проекте
И вот четвертый этап во фронтенде почему‑то недопрошли — его мало кто применяет в реальности и еще меньше тех, кто о нем пишет или публикует библиотеки. При этом проблемы, перечисленные в этой статье никуда не делись, а ИИ через фразу указывает на отсутствие формализованных правил и механизма их передачи. Уже приевшийся термин harness пытается это решить «текстовыми описаниями архитектуры в md файлах», «правилами, какой инструмент вызывать при изменениях», «описанием loop до исчезновения всех ошибок» и тому подобное. Но все понимают, что это мягко говоря неэффективно при работе с недетерминированными и часто меняющимися LLM.
Когда я столкнулся с LLM, долго не понимал куда его применить, учитывая что тогда ее возможности были ограниченны:
«Избавить от ручного бойлерплейта» — я и так пишу только значимую бизнес‑логику, остальное детерминированно, бесплатно и быстро генерируется
«Набросать черновики» — очень специфичная задача, как правило после груминга в голове уже выстраивается карта необходимого решения с учетом специфики проекта и мнений коллег, а в компаниях производящих «экспериментальные микро‑mvp для быстрой проверки гипотез» я не работал
«Написать бизнес‑логику» — задачи часто приходят с недостаточным описанием, и куда быстрее написать код самому, чем продумать и создать полноценное «описание кода на естественном языке»
Сейчас возможности моделей и агентов сильно улучшились, поэтому добавил в ARFA Generator cli‑режим фидбека, хотя в продакшене все еще очень мало им пользовался — все еще быстрее написать руками, чем читать много чужого текста и кода, но возможно кому‑то будет полезно.
Для быстрой проверки, чем эта библиотека может быть полезна в вашем проекте — передайте ИИ llms.md, это единый файл с документацией и примерами, чтобы не тратить токены на Vitepress html разметку. Вот ссылка на репозиторий, а я пойду неспешно писать статью про следующий выложенный инструмент — он тоже довольно интересный и концептуальный.

