Материал подготовлен на основе практического опыта команды Compo Soft и посвящён развитию корпоративной платформы Compo B2B Platform — зрелого B2B‑решения, используемого десятками компаний в ежедневных бизнес‑процессах.
Это интервью — разбор реального опыта миграции фронтенда Compo B2B Platform с Angular 13 на актуальные версии фреймворка (в итоге — Angular 19). Команда Compo Soft прошла путь через несколько мажорных апдейтов, замену и переписывание зависимостей, рефакторинг архитектуры и внедрение новых возможностей Angular — от Standalone Components до Vite и non‑destructive hydration.

Ниже — честный рассказ о том, что сработало, где возникли сложности и какие выводы стоит сделать тем, кто только планирует подобное обновление. На вопросы отвечает ведущий фронтенд‑разработчик Compo Soft Дмитрий Федоренко.
Проект: какая область, сколько пользователей, клиентов, фронтенд‑архитектура?
Это B2B‑платформа, ориентированная на задачи средних и крупных предприятий.
Бэкенд написан на Java Spring, фронтенд — на Angular. Монорепозиторий фронтенда содержит два основных приложения:
административную панель;
клиентский кабинет.
Оба приложения используют общую библиотеку компонентов и утилит.
Исторически в проекте накопилось большое количество зависимостей в package.json, и именно это стало одной из ключевых проблем перед миграцией. На старте у нас был следующий набор UI‑ и вспомогательных библиотек:
Nebular;
Taiga UI;
Angular Material;
ngx‑formly;
Bootstrap CSS 4;
ngx‑easy‑table;
tslib.
Какая версия Angular использовалась до обновления?
Мы застряли на версии Angular 13.3, выпущенной весной 2022 года. На тот момент она была стабильной, поэтому мы пропустили несколько мажорных релизов с важными оптимизациями и архитектурными изменениями.
Почему вы решили обновиться именно сейчас — это был бизнес‑ или технический драйвер?
Причины лежали на стыке бизнеса и разработки.
С бизнес‑точки зрения основной запрос заключался в унификации интерфейса. Со временем один и тот же функционал начал выглядеть и работать по‑разному в разных частях приложения: кнопки, иконки, поля форм отличались от страницы к странице. Это типичная проблема большого и долго развивающегося фронтенда.
Параллельно мы исправляли устаревшие UI/UX‑решения и паттерны, которые регулярно вызывали жалобы клиентов.
С технической стороны назрела необходимость масштабного рефакторинга. Кодовая база страдала от дублирования: вместо переиспользования и наследования компонентов часто создавались копии, отличающиеся одной‑двумя строками.
Однако главной болью стала скорость разработки. Даже небольшие правки в вёрстке или логике требовали ждать 3–6 секунд, пока Ivy‑компилятор пересобирал проект. Холодный старт dev‑сервера и постоянные задержки при работе с UI делали разработку утомительной.
Именно это стало главным мотиватором перехода на актуальные версии Angular с поддержкой Vite.
Какие шаги вы предприняли перед началом миграции? Был ли аудит кода?
Мы начали с простого: создали отдельную ветку и попробовали выполнить ng update. Глубокого аудита на старте не было — и это оказалось ошибкой.
У команды не было достаточной экспертизы в подобных масштабных обновлениях, и мы не до конца понимали риски. Ключевые вопросы, на которые не было ответов:
выживут ли основные библиотеки (Nebular, Taiga UI);
удастся ли вообще собрать проект;
не проще ли начать всё с нуля.
Первая попытка обновления закончилась неудачей: проект начал «ломаться» в самых разных местах. В процессе стало очевидно несколько важных вещей.
Нужен ESLint вместо устаревшего TSLint
Мы настроили ESLint с максимальным набором правил для Angular и шаблонов. Часть правил перевели в режим warn, второстепенные — отключили. В проекте исторически было много any, и переписывать всё сразу мы не планировали, поэтому тонкая настройка линтера оказалась критичной. Среда разработки (у нас IntelliJ IDEA) должна корректно отображать ошибки линтинга в реальном времени.AOT‑компиляцию необходимо включать уже в dev‑режиме
Если этого не сделать, проект может успешно собираться, но фатальные ошибки будут возникать уже в браузере во время работы приложения.Нужно отказаться от ‑legacy‑peer‑deps
Исторически зависимости устанавливались именно с этим флагом. При обновлении Angular это привело к неразрешимым конфликтам версий. Попытки продолжить работу с legacy peer deps вызывали хаотичные и трудно воспроизводимые баги. Перед миграцией зависимости пришлось привести в порядок, даже ценой обновления второстепенных библиотек.
Какой подход использовался: big bang, поэтапная миграция, feature toggle?
Подход напрямую зависит от количества и качества внешних зависимостей.
Если библиотек немного, можно обновляться сразу до последней версии. В нашем случае это было невозможно: мы последовательно прошли через Angular 15, 17 и в итоге дошли до версии 19.
Не все сторонние библиотеки поддерживали новые версии фреймворка. Часть из них пришлось заменить на более современные open‑source‑аналоги, что‑то написать с нуля, а от некоторых устаревших решений — отказаться полностью.
Много времени заняло обновление Taiga UI с версии 2 до версии 4. API библиотеки значительно изменился: методы, помеченные как deprecated в третьей версии, были полностью удалены в четвёртой.
Также важно учитывать связку версий Angular и TypeScript. Каждая версия Angular требует определённую версию TypeScript, и она может быть несовместима с используемыми библиотеками. При миграции приходится тщательно подбирать комбинацию Angular + TypeScript + сторонние зависимости.
Мы выбрали гибридный подход, который условно можно назвать «поэтапным Big Bang»:
в основной ветке подготовили кодовую базу (обновили второстепенные зависимости, начали использовать Standalone Components в новых модулях, минимально отрефакторили проблемные места);
создали отдельную long‑lived ветку, где последовательно выполнили ng update через несколько мажорных версий;
изменения вливали в основную ветку не целиком, а логическими блоками — с использованием feature‑флагов.
Какие зависимости оказались блокирующими для перехода?
Наибольшие сложности возникли с Taiga UI и ngx‑formly.
В случае с Taiga UI причиной стала большая разница между версиями 2 и 4. С ngx‑formly пришлось переписать около двух десятков кастомных типов полей, чтобы привести их в соответствие с новой версией библиотеки.
В остальном Angular демонстрирует хорошую обратную совместимость, а автоматические миграции, встроенные в Angular CLI и сторонние schematics, значительно упрощают обновление. Например, ng update @taiga‑ui/cdk закрывает часть проблем автоматически.
Были ли моменты, когда приходилось временно откатываться? Как организовали fallback?
Полноценных откатов не было — изменений оказалось слишком много, и частичные rollback«и не имели смысла.»
Всего получилось три крупных merge‑запроса с более чем тысячей изменений каждый, затрагивающих весь проект. Сначала мы обновили внутренние тестовые среды (PIM и CRM). Это позволило организовать длительный этап внутреннего тестирования: сотрудники активно работали с новой версией интерфейса и оперативно сообщали о проблемах, не затрагивая клиентов.
Как изменилась сборка и CI/CD‑пайплайн?
Существенных изменений не потребовалось. Единственное — в CI пришлось обновить Node.js до версии 22 LTS, чтобы корректно работали настройки module=ES2022 и moduleResolution=bundler в TypeScript.
Какие breaking changes оказались наиболее критичными?
Сам Angular показал себя очень стабильным: даже при обновлении через несколько мажорных версий изменения в коде минимальны.
Основные проблемы, как и ожидалось, были связаны со сторонними библиотеками, поддержка которых либо замедлилась, либо прекратилась вовсе. В таких случаях приходилось искать альтернативы или писать собственные решения.
Какие инструменты и ресурсы оказались наиболее полезны?
Официальный Angular Update Guide — основной ориентир при миграции.
ESLint с правилами @angular‑eslint — помог автоматически исправить множество проблем.
Репозитории и документация библиотек на GitHub — часто приходилось заглядывать в исходный код Nebular и Taiga UI.
DeepSeek — использовался как «лектор» для быстрого поиска ответов на точечные вопросы.
GitHub Copilot в агент‑режиме пробовали применять для миграций и рефакторинга SCSS, но на практике он часто генерировал код, ломающий вёрстку. В итоге ручная работа оказалась быстрее и надёжнее.
Как изменилась производительность, размер бандла и скорость разработки?
Результаты оказались заметными:
холодный старт ng serve сократился примерно с 25 секунд до менее чем 6;
HMR с Vite теперь отрабатывает менее чем за секунду вместо 3–6;
время production‑сборки (ng build ‑configuration=production) уменьшилось примерно на 35%;
размер основного бандла сократился незначительно (около 5%), так как основные «тяжеловесы» — сторонние библиотеки, но tree‑shaking собственного кода стал эффективнее.
Что сработало особенно хорошо и что бы вы посоветовали другим командам?
Инвестировать время в подготовку: привести в порядок зависимости и отказаться от legacy‑peer‑deps.
Заранее продумать стратегию тестирования — внутренний beta‑тест оказался самым эффективным вариантом.
Работать в изолированной ветке и не делать миграцию напрямую в основной.
Максимально использовать автоматические миграции и линтеры.
Не спешить с внедрением новых возможностей Anrular вроде signals — сначала убедиться, что команда к этому готова.
Внимательно читать release notes и changelogs. В них часто содержится критически важная информация.
Какие риски вы недооценили и что бы сделали иначе?
Мы недооценили риск, связанный с кастомными форками библиотек. В следующий раз мы бы либо заранее искали альтернативы, либо планировали замену таких зависимостей до обновления ядра фреймворка. Также стоило сразу внедрить более строгие линтеры для нового синтаксиса.
Были ли проблемы с SSR, hydration и компонентной архитектурой?
С SSR (Angular Universal) сложности действительно были. Новая non‑destructive hydration потребовала адаптации: мы сталкивались с ошибками NG0500 из‑за несовпадения DOM на сервере и клиенте.
Основные причины:
прямые манипуляции с DOM через document или ElementRef в ngOnInit;
использование setTimeout без корректной обработки на сервере;
сторонние библиотеки без поддержки SSR.
Проблемы решались аудитом кода и оборачиванием таких операций в isPlatformBrowser. Переход на Standalone Components, напротив, прошёл очень гладко и стал одним из самых позитивных изменений за всё время миграции.
Каковы перспективы работы на Angular 19 и дальнейшие шаги?
Vite‑сборка, Signals, новый control flow, Standalone API и обновлённый синтаксис шаблонов делают код более декларативным и понятным. Мы планируем аккуратно наращивать опыт работы с signals, полностью отказаться от NgModules и глубже поработать с SSR и гидратацией. После этой миграции мажорные релизы Angular перестали пугать.
Практический чек-лист: обновление проекта до Angular 19
В завершение интервью — краткий практический чек‑лист, сформированный на основе опыта команды Compo Soft. Он не заменяет официальную документацию, но помогает структурировать процесс обновления и избежать типовых ошибок, с которыми сталкиваются команды в крупных проектах.
Шаг 1. Ознакомьтесь с примечаниями к выпуску Angular 19
Изучите release notes и журнал изменений, чтобы понять, какие новые возможности появились, какие API объявлены устаревшими и какие изменения могут нарушить обратную совместимость.
Шаг 2. Создайте резервную копию проекта
Убедитесь, что проект находится под контролем версий и текущее состояние зафиксировано перед началом миграции.
Шаг 3. Обновите глобальную версию Angular CLI
Выполните команду:
npm install ‑g @angular/cli@19
Шаг 4. Обновите Angular в проекте
Запустите обновление основных пакетов:
ng update @angular/cli@19 @angular/core@19
Шаг 5. Обновите версию TypeScript
Установите рекомендованную версию:
npm install typescript@5.6 ‑save‑dev
Шаг 6. Обновите остальные зависимости Angular
Проверьте и обновите связанные пакеты:
ng update @angular/forms @angular/router @angular/material
Шаг 7. Актуализируйте сторонние зависимости
Выполните npm outdated и обновите устаревшие пакеты с помощью npm install package‑name@latest, уделяя особое внимание совместимости с Angular 19.
Шаг 8. Разберите breaking changes и устаревшие API
Последовательно устраните критические изменения, связанные со Standalone Components, новым control flow и системой гидратации.
Шаг 9. Запустите и протестируйте приложение
Проверьте проект с помощью ng serve, ng test и ng e2e, уделяя внимание SSR и клиентской гидратации, если они используются.
Шаг 10. Оптимизируйте конфигурации сборки
Обновите angular.json и tsconfig.json в соответствии с рекомендациями Angular 19.
Шаг 11. Выполните production‑сборку
Запустите:
ng build ‑configuration=production
и проверьте время сборки, размер бандлов и предупреждения.
Шаг 12. Развертывание и мониторинг
Выкатите обновлённую версию в рабочую среду и в первые дни внимательно отслеживайте ошибки и показатели производительности.
Комментарии (13)

dananaprey
18.12.2025 09:14Спасибо за интересную статью! Подскажите, насколько я понял вы ещё не перешли на Vite? Мы попробовали, но новый сборщик стал дробить весь код на очень маленькие чанки, а приложение не малое и по итогу скорость загрузки уменьшилась (особенно на низкой скорости), так как у браузера не бесконечное количество потоков. Вы с таким пока не столкнулись?

bazzzman
18.12.2025 09:14Здравствуйте. Мы на Vite и маленькие чанки это прекрасно.
Плюсы stand alone и небольших чанков
Возможность использовать lazy load компонентов прям в роутинге https://angular.dev/reference/migrations/route-lazy-loading
Tree shaking сильно эффективнее работает с мелкими чанками
Один большой модуль даст вам более быструю полную загрузку приложения, но доступным для действия пользователя приложение станет заметно позже. Т.е. в браузере долгое время будет отображаться процесс загрузки, вместо (пусть даже частично) доступного интерфейса. Stand alone даёт более быстрый интерактив в браузере
Так же маленькие чанки дают возможность локально использовать Hot Module Replacement (HMR) для стилей и шаблонов. Это значительно ускоряет обновление в браузере при активной работе со стилями или html
Что делать если есть проблемы с исчерпанием лимита соединений
Смотрите детально почему вы загружаете много всего при старте. Это в самом деле необходимо?
Можно использовать супер-крутую штуку @defer - https://angular.dev/guide/templates/defer для lazy load части компонентов. Вы можете совсем не грузить код с которым пользователь не работает и делается это элементарно, без сложное конфигурации. У @defer есть разные стратегии загрузки кода - idle, viewport, interaction, hover, ... Возможно сможете перенести часть функционала на отложенную загрузку и облегчите приложение в целом.
В итоге мое мнение - чем меньше будут чанки тем лучше. Даже если их будет много.

dananaprey
18.12.2025 09:14Спасибо за подробный ответ) Насколько у вас большое приложение и используете ли вы preloading чанков?
Мы как раз сейчас движемся в сторону оптимизации загрузки, пока вернулись на webpack. Оптимизировали размеры основных чанков, standalone с lazy routing уже настроен, добавили defer, настроили Service Worker и перестали грузить то, в чём не было необходимости. В ближайшее время, думаю, снова попробуем Vite, должно стать получше, но уверен нужны будут ещё оптимизации, спасибо за совет!

bazzzman
18.12.2025 09:14У нас два приложения на 4+ и 5+ мегабайт в прод сборке. Чанки анализируем через http://esbuild.github.io/analyze/ после сборки
ng build --stats-json
Хороший анализатор. Рекомендую.Прелоад не используем. Наоборот, грузим только то, что нужно сейчас пользователю. Приложение у нас с настроенным service worker'ом, он фоном смотрит на сервер и если был свежий релиз - сам тихонько загрузит все чанки и предложит обновиться в UI. Это удобно. Пользователь не отвлекается на загрузку и видит кнопку обновления только если все чанки были уже загружены браузером.
Да, холодный старт будет медленнее, но не могу придумать сценариев в нашем окружении где webpack был бы быстрее и оптимальнее Vite. Гибче, может быть, но не быстрее. Не зря на него официально перевели Angular. Надо смотреть ваше приложение, гонять его в Performance анализаторе консоли Google Chrome с разными настройками и искать узкое место. Сервер http2? Он корректно настроен? Надо смотреть зачем вам сразу при старте грузить много кода если можно показать UI, дать с ним работать и догружать куски интерфейса на ходу. Общих рекомендаций к сожалению не дам, надо в детали погружаться.
tizian
Очень странный кейс - сидеть 3 года и ничего не делать, а потом все переписывать.
За монорепом нужно следить и ухаживать, поддерживать все в актуальном состоянии. Постоянное обновление Angular и NX, а также pnpm audit
IgorN Автор
Кто сказал что никто ничего не делал) Не обновляли по стратегическим причинам: сначала приоритет был на стабильности production (риск breaking changes в Angular 14-17 с Ivy, SSR и standalone components мог сломать legacy-функционал) и команда фокусировалась на бизнес-фичах без техдолга (работает - не трогай). Ну и если глянуть на Netflix или GitHub, то они тоже порой не бегут за апдейтами по 2-3 года. Так что местами это нормальная практика.
tizian
Нет, это не нормальная практика. И со стабильностью и с безопасностью - она никак не связана. Как я указал выше, нужно во время обновляться и подтягивать все проекты. Если это делать системно - все работает отлично и никаких side effects не возникает, прод работает ожидаемо, хоть с SSR, хоть без.
Как на моей прошлой работе, где монореп был гигантский, с кучей проектов и тысячами разработчиков, так и на текущей работе - где монореп, уже по-меньше - без разницы, версия ангуляра всегда поддерживается в актуальном состоянии. Обычно, спустя 1-2 месяца после релиза, все обновляем. А в промежутках еще и минорные версии подтягиваем...
bazzzman
Обновление спустя 1-2 месяца после релиза - это круто. Вы молодцы, завидую.
Мы больше ориентированы на бизнес-процессы клиентов и их потребности. Технический долг возвращаем когда он в самом деле появляется.
У нас большая кодовая база и обновление спустя пару месяцев после релиза мы точно не сможем делать т.к. внешние зависимости могут быть несовместимы с новой версией по полгода и далее. Форкать чужие библиотеки и потом назад переходить с форка на основную ветку - не всегда оправдано.
"никаких side effects не возникает" - здесь вот не соглашусь. Это риск. Ни раз нарывались на регрессии как в Ng так и в свежих версиях библиотек. Для себя выбрали стратегию не частых обновлений, с вдумчивым и растянутым по времени бета-тестом. Когда сотрудники могут 1-2 месяца работать с next версией продукта и только после этого будет общий релиз.
tizian
Так, у всех большая кодовая база. И обновление самого Ангуляра - это не самая сложная задача. Гораздо сложнее - это статический анализ кода и написание патчей под сторонние зависимости.
bazzzman
Не понимаю, что вы доказываете? Критика ради критики.
Вот смотрите, у нас Angular и Taiga UI, супер-крутая библиотека от Тинькова. Angular 16 выходит в мае 2023, а Taiga с поддержкой Angular через 15 месяцев, в августе 2024. Как в этом случае обновиться за 1-2 месяца после релиза?
Менять тайгу на что-то другое, переписывать код приложения и переучиваться всем на ходу? Ставить в legacy peer deps режиме и ловить баги? Если зависимостей мало или они быстро обновляются - можно порадоваться за вас. Если нет - обновляемся через 1-1.5 года после выпуска свежего ангуляра.
tizian
Я ничего не доказываю, я написал в первом комменте - что, это очень странный кейс. Для фронта, где все постоянно и быстро меняется - такая практика выглядит очень архаично.
Но теперь понятно, раз вы юзаете Bootstrap и внешние UI-либы - соответственно, делаю вывод что у вас мало компетенций по данной теме. Зачем тянуть к себе в проект такие простые штуки... Видимо, вы еще не выросли.
Ну, ок.
bazzzman
Да, мы не спешим очень быстро меняться и следовать за модой которая во фронте часто меняется. В этом плане да, не выросли. Неспешно используем Angular ещё с первой, js версии и постепенно дошли до 19-ой. Bootstrap 5-ой версии тоже закрывает часть наших задач. Он хорошо документирован, прост и продуман, в него легко погружать программистов. Менять его тоже пока не собираемся. Не спешим никуда, медленно и поступательно развиваемся.
tizian
Теперь все встало на свои места :)
Сразу чувствуется влияние бэкендов. Это у них один раз настроил и все, ближайшие годы, пока не прилетит - ничего не трогаем :)
На фронте - другой подход. Для примера запустите в своем монорепе аудит (npm/pnpm audit или какой у вас пакетный менеджер используется), в идеале должно быть 0 критических уязвимостей.