Как стать автором
Обновить
15.47

Angular *

JavaScript-фреймворк

Сначала показывать
Порог рейтинга

AI-кодинг в 2025: Напарник, Фабрика или Облачная Песочница? Сравниваем Cursor, Replit, v0.dev и Harvi

Привет, Хабр!

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

Я решил разобраться в четырех популярных, но идеологически разных подходах, чтобы понять, какой инструмент для каких задач подходит лучше всего. В нашем обзоре: Cursor (AI-напарник в IDE), Replit (облачная песочница), v0.dev (генератор UI-компонентов) и первая в России вайбкодинг студия Harvi.pro (AI-фабрика приложений).

1. AI как Напарник в вашей IDE (Cursor)

Cursor – это "VS Code на стероидах". Он не меняет ваш привычный воркфлоу, а глубоко интегрирует AI для помощи в написании и рефакторинге кода, отладке и поиске информации.

  • Идеально для: работы с существующей кодовой базой, написания сложной бизнес-логики, точечных правок.

  • Минус: Не проектирует приложение с нуля. Всю архитектуру и структуру вы держите в голове.

2. AI как Облачная Песочница (Replit)

Replit предлагает полноценную среду разработки прямо в браузере. Его главная фишка – возможность мгновенно запустить любой проект без локальных настроек. AI здесь выступает как мощное дополнение к этой облачной среде.

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

  • Минус: Для больших и сложных локальных проектов может быть не так удобен. Мощность AI-ассистента, хоть и велика, но все же является частью общей платформы.

3. AI как Генератор UI-компонентов (v0.dev от Vercel)

v0 – это узкоспециализированный инструмент, который делает одну вещь, но делает ее отлично. Вы описываете интерфейс, а он генерирует готовые React-компоненты с использованием Tailwind CSS.

  • Идеально для: фронтенд-разработчиков и дизайнеров, которым нужно быстро создавать красивые, адаптивные UI-компоненты.

  • Минус: Это не полноценная среда разработки. Он не занимается логикой, бэкендом или структурой всего приложения.

4. AI как "Фабрика Приложений" (Harvi.pro)

Российский проект Харви предлагает иной подход, который можно назвать "вайбкодингом". Это веб-студия, где вы описываете общую концепцию, а AI генерирует всю структуру проекта – от фронтенда на Nuxt/Next.js до бэкенда на Node.js. Также интересно то, что это первопроходец, созданный нашими Русскими ребятами в России

  • Идеально для: молниеносного создания MVP с нуля, проверки бизнес-гипотез, быстрого старта для фулстек-приложений.

  • Минус: Как и любой генератор, AI может ошибаться, и сгенерированный код требует итеративной доработки в веб-редакторе, что может быть непривычно.

Выводы: нет "лучшего", есть "подходящий"

Как видим, идеального инструмента на все случаи жизни не существует. Выбор зависит от конкретной задачи:

  • Нужно доработать сложный проект? Ваш выбор – Cursor.

  • Хотите быстро проверить скрипт или поработать над проектом в команде? Replit к вашим услугам.

  • Нужно быстро нарисовать красивый фронтенд? v0.dev сэкономит кучу времени.

  • Нужно с нуля "родить" скелет целого фулстек-приложения для MVP? Harvi.pro может оказаться самым быстрым решением.

Теги:
-1
Комментарии0

withComponentInputBinding()
Упрощение работы с параметрами маршрутизатора в Angular.

Как было раньше?

  1. Создаем переменную/свойство (Signal, BehaivorSubject, Observable, неважно)

  2. Инжектим и подписываемся на ActivatedRoute

  3. Получаем параметры маршрута

  4. Записываем в BS/Signal

😵‍💫😵‍💫😵‍💫

Манипуляций довольно много, но мы все к этому привыкли и это кажется нормальным.

Но с withComponentInputBinding() все стало намного проще:
1. Создаем сигнальный инпут... и...
Вот и все!

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

Функция не новая (кажется, появилась в Angular 16), но я редко ее видел в проектах.

Немного технической информации из документации:

🔍Маршрутизатор передает данные в input() из:

  1. Параметров запроса (?page=1&sort=asc)

  2. Параметров пути и матрицы (/users/123;details=true)

  3. Статических данных маршрута (data: { role: 'admin' })

  4. Результатов резолвера (resolve: { user: userResolver })

🔍 Приоритеты:
Если есть дублирующиеся ключи, данные переопределяются в порядке выше — резолверы имеют наивысший приоритет и перезапишут остальные.

🚩 Важный нюанс
Если в маршруте нет данных для input(), он получит undefined (например, если параметр запроса удален из URL).

ℹ️ Как задать значения по умолчанию?

✔ Через resolver (чтобы данные всегда были в маршруте)
✔ Через transform в input() (если нужно обрабатывать undefined)

Спасибо разработчикам Angular за эту функциональность 🙏.

Больше об 🅰️ngular в моём Telegram-канале

Теги:
+2
Комментарии0

🦥 RxJS defer — ленивая инициализация Observable

defer — это фабрика, которая создает Observable только при подписке, а не во время объявления. Идеально подходит для:

  • HTTP-запросов (чтобы избежать преждевременного выполнения)

  • динамических данных (которые должны быть свежими при каждой подписке)

  • условных потоков (когда Observable зависит от состояния времени выполнения)

📌 Основные варианты использования

  1. Свежие данные при каждой подписке

    const freshData$ = defer(() => of(Date.now()));

    // Новая временная метка при каждой подписке()

  2. Работа с изменяемым состоянием

    const token$ = defer(() => of(localStorage.getItem('token')));

    // Всегда получает текущий токен, даже если обновлен

  3. Условные наблюдаемые

    const api$ = defer(() => isLoggedIn ? http.get('/user') : http.get('/guest') );

  4. Генерация случайного значения

    const random$ = defer(() => of(Math.random()));

    // Новое случайное число на подписку

🚫 Ограничения defer

  • нет кэширования → используйте shareReplay, если вам нужно повторно использовать результаты.

  • нет отмены запроса → объедините с switchMap/takeUntil для управления отменой

⚡Когда следует выбирать defer вместо обычных наблюдаемых?

  • данные должны быть свежими при каждом subscribe()

  • cоздание наблюдаемого стоит дорого и должно быть отложено

  • поток зависит от изменяемых условий (флаги функций, статус аутентификации и т. д.)

Больше об 🅰️ngular в моём Telegram-канале

Теги:
0
Комментарии0

😎 Кастомный signal в Angular

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


И вот, как-то я в очередной раз писал подобные строки:

isOpened = signal(false);

toggle() {

  this.isOpened.update(value => !value);

}


#isOpenedEffect = effect(() => {

  console.log('New state:', this.isOpened())

})

- и подумал: 'Было бы удобно, если бы был булевый signal с методом toggle'


В этом не было прям сильной необходимости, однако было бы немного удобнее (процентов на 10 😅). И появилась идея написать свой сигнал (реализация на фото)


Пример, согласен, так себе. 

👍🏼 меньше кода, более аккуратно

👎🏼 всей команде придется подстроится


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

💬 А какого сигнала не хватает вам?

Больше об 🅰️ngular в моём Telegram-канале

Теги:
0
Комментарии3

RxJS: Почему shareReplay(1) может вызывать утечки памяти

Если вы используете shareReplay(1) в RxJS, будьте осторожны — в некоторых случаях это может привести к утечкам памяти! Давайте разберёмся, почему так происходит и как это исправить.

❌ Проблема с shareReplay(1). По умолчанию:

  • Сохраняет последнее значение в бесконечном буфере, даже если подписчиков больше нет

  • Не отписывается от источника, когда никто не слушает (например, interval, Subject, HTTP-запросы)
    Это означает, что данные могут накапливаться, а ненужные Observable продолжают работать в фоне

✅ Решение: shareReplay({ bufferSize: 1, refCount: true })

  • Добавление refCount: true решает проблему:

  • Автоматически отписывается, когда не остаётся подписчиков

  • Очищает буфер, предотвращая утечки памяти

💡 Ключевые выводы:

  1. shareReplay(1) - Может оставлять "висящие" подписки

  2. shareReplay({ bufferSize: 1, refCount: true }) - Безопасная альтернатива

Я обнаружил эту проблему во время code review вчера, а впервые узнал о ней из видео Dmytro Mezhenskyi.

🔗 P.S. Самое время быстро исправить это в наших проектах!)

Больше об 🅰️ngular в моём Telegram-канале

Теги:
0
Комментарии0

"mergeMap: Секрет управления параллелизмом в RxJS"

Вы знаете mergeMapconcatMapexhaustMap и switchMap — но знали ли вы, что только один из них принимает второй аргумент?

👉 mergeMap уникален благодаря параметру concurrent, который ограничивает параллельные подписки. Это как "регулятор скорости" для ваших Observable.

_____

Пример использования (контролируемая загрузка файлов):

Представьте, что вам нужно:
1️⃣ Обработать несколько файлов
2️⃣ Избежать перегрузки браузера/API
3️⃣ Сохранить порядок загрузки

В этом случае второй аргумент mergeMap становится незаменимым:

from(fileList).pipe(
  mergeMap(
    file => uploadFile(file), // функция загрузки
    3                        // одновременно только 3 файла
  )
).subscribe();

_____

Преимущества mergeMap с concurrent:
✅ Предотвращает перегрузку API
✅ Оптимизирует нагрузку на сеть
✅ Сохраняет отзывчивость интерфейса
_____

Знали ли об этой возможности? 😉

Больше об Angular в телеграмм-канале

Теги:
0
Комментарии0

Управление методами в зависимости от окружения в 🅰️ngular

Бывают случаи, когда нужно, чтобы определенные методы работали только:

  • 🛠️ В dev-режиме (например, фича-тогглы, дебаг-логи, экспериментальные функции)

  • 🚀 В prod-режиме (аналитика, мониторинг, продакшен-логика)

Вместо того чтобы писать if (isDevMode()) {...} везде, можно использовать декораторы Angular для более чистого и декларативного подхода.

_____

Одно из решений:

export function EnvMode(mode: 'dev' | 'prod') { return function (_: unknown, __: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: unknown[]) { const shouldExecute = mode === 'dev' ? isDevMode() : !isDevMode(); if (!shouldExecute) return; return originalMethod.apply(this, args); }; return descriptor; }; }

_____

Как использовать:

@EnvMode('dev') public setFeatureToggle(): void { // Сработает только в dev-режиме } @EnvMode('prod') public sendAnalytics(): void { // Сработает только в prod-режиме }

_____

🤔 А вы создавали кастомные декораторы? Зачем?

Больше про Angular в тг канале

Теги:
0
Комментарии0

Angular Hack: Цикл без данных (в тэмплейте)

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

Вот мой способ (по крайней мере, я нигде такого не видел):

@for (_ of [].constructor(10); track $index) {
<div class="item"></div>
}

Используется Array.constructor, чтобы создать пустую массив фиксированной длины, который @for может перебрать по индексам.

Плюсы ✅

  • Чудо-код (удивит коллег)

  • Минимум кода (не нужно объявлять массив в компоненте)

Минусы ⚠️

  • Чудо-код (может ненадолго ввести в ступор чающего код человека)

Конечно, можно просто использовать Array.from({length: 10})... но так все делают, не интересно)

Норм тема? Как считаете?

Теги:
Всего голосов 2: ↑1 и ↓10
Комментарии3

Немного о резолверах в Angular 19 (теперь в них есть редиректы).

В логике использования гвардов применяется подход:

проверить что-то, если все ок то вернуть true или кинуть редирект на другую страницу

Выглядит достаточно удобно. Но если мне не изменяет память в резолверах такого нет, вместо этого приходилось натягивать Router и рулить navigate или navigateByUrl и т.д.

В 19 же версии нам немного упростили жизнь и резолвер научили в RedirectCommand.

Пример с angular.dev

export const heroResolver: ResolveFn<Hero>= async (
  route: ActivatedRouteSnapshot,
  state: RouterStateSnapshot,
) => {
  const router = inject(Router);
  const heroService = inject(HeroService);
  
  try {
    return await heroService.getHero(route.paramMap.get('id')!);
  } catch {
    return new RedirectCommand(router.parseUrl('/404'));
  }
  
};

Ну просто сказка какая-то, а не только сигналы =)

Теги:
Всего голосов 2: ↑2 и ↓0+2
Комментарии0

Кнопка со счётчиком: React vs Fusor

Кнопка со счётчиком: React vs Fusor
Кнопка со счётчиком: React vs Fusor

Fusor это новый способ разработки вэб приложений https://github.com/fusorjs/dom

Теги:
Всего голосов 4: ↑4 и ↓0+6
Комментарии2