NG Stream
248 subscribers
85 photos
4 videos
2 files
465 links
Авторский канал об Angular и новостях фронтенда. Мы рассказываем о том, с чем сталкиваемся в процессе разработки, делимся полезными, на наш взгляд, статьями.

Made by devs for 🅰️ devs

Авторы:
- @antoonG
- @basters

Чат: https://t.me/+JYGeE7HekO04Y2My
Download Telegram
Немного слов о State of JS

По графикам прошедшего опроса можно увидеть, как возросли показатели Angular. Обновленная дока и увеличение числа обучающих материалов сделали его более доступным для новичков. Снижение порога входа, к которому стремились разработчики, существенно повлияло на показатели. Значительное улучшение удовлетворенности определенно благодаря сигналам и многому другому! Команда Angular уверенно идет к цели!

+12% retention
+5% usage
+5% positivity

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

Что касается React, то он продолжает уверенно удерживать лидирующие позиции. Но отмечается потребность в более простых подходах, поскольку API стал более неоднозначным, особенно с его RSC.

А вот самым используемым и с высоким уровнем удовлетворенности стал Vite и Vitest соответственно. И неудивительно с его количеством интеграций в различные инструменты.

Посмотреть подробности, поиграть с фильтрами здесь.

Подписывайся / Чат

#js
🔥5
После принятого разработчиками Angular решения в 19 версии сделать компоненты standalone по умолчанию, продолжаем ждать, когда же ChangeDetection: OnPush стратегия будет также по умолчанию включена.🤔

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

Особенно актуально с ребрендингом:

ChangeDetection >> Synchronization.

Подписывайся / Чат

#angular
👍6👏1
Всех с наступающим Новым годом!🎄🎉🎉🎉🎉🎉
Вернемся к новостям уже в следующем!

Спасибо, что подписаны! Хотим пожелать нам всем профессионально развиваться и не забывать отдыхать!
🎄11👌1
А мы возвращаемся и продолжаем стримить новости фронтенда! 🎉🎉🎉

Недавно вышла статья, повествующая о вариантах применения inject(). И в каких случаях ваша реализация может быть реализацией антипаттерна Service Locator.

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

export class RiskyService {
private injector: Injector;

// This creates a hidden dependency outside of construction
performAction() {
runInInjectionContext(this.injector, () => {
// Service locator pattern: Looking up service on demand
const analyticsService = inject(AnalyticsService);
analyticsService.track(data);
});
}
}


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

#angular
👍4
Input signals - production-ready

В 19 версии были добавлены схематики, позволяющие произвести миграцию Input на декораторах на сигнальные. О чем я писал в заметке.

ng generate @angular/core:signal-input-migration
ng generate @angular/core:signal-queries-migration


Сейчас команда Angular выпустила заметку в своем блоге, где говорит о переходе сигнальных Input в статус production-ready. Основная причина перехода - типобезопасность, которая позволит разработчикам, например, не писать лишний раз non-null assertions. И отказаться от ngOnChanges().

Заметка простая, но интересно, что команда намекает о необходимости перехода на новое API. Подчеркивается, что комбинация с computed() улучшит читаемость и тд.

Сейчас как раз планирую взять задачу по тех долгу, в которой, помимо декомпозиции и прочего, реализовать функционал на новом API.👍🏻

#angular
👍2
Несовершенства TS

На неделе заметил интересный issue в репозитории Typescript. В нем обсуждается предложение добавить новый модификатор identity для функций.

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

Если добавить чуть больше контекста для понимания, то автор обеспокоен тем, что сигналы нужно проверять на наличие undefined, потому что TS не может нормально сузить тип, который возвращается в value(). А использование этого ключевого слова позволило бы избежать необходимости писать лишние проверки.

declare const value: () => string | undefined;

if (value() !== undefined) {
console.log(value().toUpperCase()); // Ошибка компиляции
}


В комментариях весьма интересно, можно почитать здесь.

#typescript

Подписывайся / Чат
👍1
В коде часто замечаю, что разработчики предпочитают .get() для получения доступа к Form control. Я бы рекомендовал использовать более типо-безопасную альтернативу.

FormGroup предоставляет 2 способа получения доступа к контролу (вдруг читают новички):

- get() - возвращает AbstractControl.
- свойство controls - возвращает конкретную реализацию AbstractControl - FormControl, FormGroup, FormRecord, FormArray.

Преимущества .controls перед .get():

- Типобезопасность: предоставляет конкретный тип контрола, позволяя избегать необходимости уточнять тип (type assertion). В случае с FormArray, сразу можно работать с методами массива.
- Улучшенная работа language services: подсказки IDE работают более точно.

Интересно, насколько изменится API при переходе на сигнальные формы?🤔

#angular

Подписывайся / Чат
👍9
Полезное для Angular

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

ng generate @angular/core:cleanup-unused-imports


Но для этого придется обновиться на версию 19.1.

Что же, очередные бонусы от перехода на standalone components. Сокращаем размер бандла👍🏻

#angular

Подписывайся / Чат
🔥8
Ресурсы и httpClient

Вы знаете, что в 19 версии был добавлен resource API. Это способ работы с запросами, работающий с Promise и интегрированный с сигналами.

Resource имеет тип Resource<T>, который включает сигналы для хранения текущего состояния. WritableResource расширяет Resource<T>, чтобы позволить преобразования resource через значение сигнала (двусторонняя привязка). Кроме того, API позволяет:

📌 конвертировать результат работы в Observable,
📌 отклонять предыдущий запрос, если значение сигнала изменилось. Семантика switchMap().

Подробности можно прочитать по ссылке.

Я предполагал, что core команда предложит отдельный httpClient , который будет предоставлять аналогичный api, но работать с сигналами и ресурсами. Условно, client.get() на промисах.

На выходных увидел заметку с другими планами. В первом комментарии разработчики заявляют о работе над примитивом httpResource, который основывается на текущем httpClient.

Как я понял, httpResource это замена rxResource + Angular Http Stack (включая interceptors) на базе httpClient.

Пока что на уровне слухов, никакого RFC, которое может рассказать гораздо больше, от команды не было. Ждем обновлений!

#angular

Подписывайся / Чат
👍3🔥1
Преобразование CommonJS в ESM

Сначала стоит коротко сказать о форматах модулей.

AMD. Используются в браузерах, для определения модулей применяется функция define. При этом нода их не может импортировать. Строго говоря, AMD - это спецификация. RequireJS это непосредственно реализация AMD-спецификации.

define(['f1', 'f2'], function (f1, f2) {
return function () {};
});


CommonJS. Предназначены для NodeJS и используют для определения зависимостей и модулей require и module.exports. Синхронные, использовать их в браузере нельзя, ведь это было бы странно, если бы при импорте jQuery мы ждали, пока он загрузится, блокируя инициализацию кода. Каждый файл, согласно спецификации, это отдельный модуль.

var dep1 = require('./dep1');  
var dep2 = require('./dep2');

module.exports = function(){}


Потом все скрипты стали использовать UMD формат. По сути, это заголовок, описывающий, как работать. Условно, if browser использовать AMD формат. if (typeofmodule === 'object' && module.exports) тогда используем CommonJS среду для работы с Node.

В 2015 году с выходом ES6 впервые появились ES модули.

Надеюсь, стало понятнее, как работают модули разного типа в JS. Сегодня в чистом виде их используют редко.

С переходом на ES Modules многие сталкиваются с необходимостью переписывания существующих библиотек и модулей.

ES Modules имеют ряд преимуществ:

1. Могут загружаться асинхронно, что улучшает производительность приложений.

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

3. В ESM код автоматически работает в строгом режиме.

4. Поддержка браузерами напрямую.

5. Безопасная работа с циклическими зависимостями. Импортированные переменные инициализируются только после полной загрузки всех модулей.

Никита Ульянов в своей статье рассказал о форматах библиотек и в каких случаях и для каких сред применения какие форматы лучше использовать. Кроме того, автор рассказывает о создании типизированного API для библиотек, приводит рекомендуемые сетапы для разных случаев: браузер, серверная среда.
Если сейчас нет необходимости работать с модулями, статья может показаться сложной, но для общего представления стоит ознакомиться.

#js

Подписывайся / Чат
2👍1
Полезное для Angular

Интерфейс NgZoneOptions включает в себя два параметра eventCoalescing и runCoalescing.

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

А вот с 18 версии первый из них включен по умолчанию provideZoneChangeDetection({ eventCoalescing: true }) , поэтому тоже считаю важным об этом написать.

Event Coalescing - помогает уменьшить количество срабатываний механизма ChangeDetection, объединяя несколько событий и, повышая общую производительность приложения, особенно при частых взаимодействиях с пользователем, таких как клики, ввод текста и т.д. или асинхронных операциях.

В официальной доке приводят такой пример.

<div (click)="doSomething()">
<button (click)="doSomethingElse()"></button>
</div>


При срабатывании клика по кнопке, затем срабатывает клик по div элементу (event bubbling). ZoneJS перехватывает события, запускает CD, который срабатывает дважды. А с 19 версии, при включенном параметре, будет только один вызов механизма.

Run Coalescing - объединяет несколько запусков NgZone в один, что также оптимизирует процесс обнаружения изменений.

#angular

Подписывайся / Чат
🔥6👍2
На MDN опубликовали статью о Temporal. Постоянные читатели канала могли заметить, что я не пропускаю новости о данном пропозале.

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

На странице пропозала на TC39 можно поиграться прямо в консоли, там включен полифилл.

А вот до полноценной поддержки браузерами далеко. Сейчас впереди всех Firefox, причем Nightly сборка.

#js

Подписывайся / Чат
🔥2
Observable API

Через пару версий в Chrome планируют добавить примитив Observable.

Основная идея пропозала заключается в предоставлении более удобного способа управления данными. Вместо императивного подхода с использованием callback функций, который неудобен при работе с большим количеством асинхронных операций, предлагается использовать Observables. Кроме того, в отличие от Promise, они имеют ряд преимуществ, включая возможность обработки множественных значений, отмену подписки и гибкое управление потоком. В общем, все то, к чему мы привыкли, используя RxJs.

Большим преимуществом нативного Observable является интеграция с EventTarget. Предлагаемый метод when(), который возвращает Observable, является заменой стандартному addEventListener().

Изначально было предложено добавить метод .on() в EventTarget. Оказалось, что есть риск коллизии имен с существующим (пользовательским) кодом. Поскольку это посчитали значительным, API метод решили переименовать.

Пример работы:

// Filtering and mapping:
element
.when('click')
.filter((e) => e.target.matches('.foo'))
.map((e) => ({ x: e.clientX, y: e.clientY }))
.subscribe({ next: handleClickAtPoint });


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

Пока примитив добавляют в браузерные движки, Deno тоже решил не отставать и тоже реализовать данный API.

Ссылка на спеку и репозиторий для желающих узнать другие детали.

#js

Подписывайся / Чат
🔥6👍2
Type stripping

Вы слышали, что недавно в Node.js появилась возможность запускать TS-файлы при помощи удаления типов (type stripping). Здесь интересно написано, какие проблемы есть в текущем решении, для чего это в принципе нужно и в каком направлении, вероятно, будет развиваться эта фича Node.js.

Если коротко, то сталкивается стабильность ноды и минусы TS в виде отсутствия спеки, отказа от следования semver, вкупе с частыми обновлениями, возможностью встраивания tsconfig.json в проект и его соответствие типу модуля. Кроме того, большой размер tsc также не добавляет плюсов.

Работает следующим образом: в ноду добавляется SWC (написан на Rust) в виде скомпилированного для WASM бинарника. TS файлы прогоняются через SWC и все.

Enum и namespace, при этом, можно использовать, только при включенном флаге —experimental-transform-types. Что, на мой взгляд, хорошо. namespace вообще редко кто использует, а в чем недостатки enum я писал здесь.

Работа еще продолжается, в TS 5.7 был добавлен флаг rewriteRelativeImportExtensions для изменения расширения с .ts на .js, что ускорит генерацию файлов и, как следствие, сборку. А в следующей версии уже добавили erasableSyntaxOnly, который сообщает компилятору о необходимости выключить несовместимые фичи Enum, experimentalDecorators, namespaces, parameter properties

Очень советую к прочтению roadmap.

#typescript

Подписывайся / Чат
👍1
Нововведения 19.2, новые подходы и RFC

httpResource. Пока в статусе experimental.

Self-closing tags. Добавлены схематики, позволяющие произвести миграцию на self-closing tags (даже не знаю, как это нормально перевести, поэтому буду использовать так).

ng generate @angular/core:self-closing-tag


Сейчас команда Angular обновила раздел в документации. Интересно, почему сразу не обновили до selector-less варианта.😅

Исправлен баг при работе с FormRecord. При объявлении формы с non-nullable значениями типы оборачивались в Partial, из-за чего и возникала ошибка.
#angular

И еще кое-что интересное!

В следующей версии готовятся представить two-way binding, который позволит считывать значения с input без использования FormsModule.

Пример:

input [(value)]="name">
<input type="number" [(valueAsNumber)]="age">
<input type="date" [(valueAsDate)]="birthday">
<input type="file" [(files)]="files" />
<input type="checkbox" [(checked)]="isHappy">


Похоже, сигналы дают такую возможность.

Ссылка на МР, рекомендую ознакомиться.

Новые Resource RFC!

На прошлой неделе команда поделилась RFC, которые описывают

- Архитектурный подход
- API

Первый из них о том, что resource рассматривается, как основной примитив для работы с асинхронностью. Как я понял, цель в том, чтобы предложить разработчикам удобный способ интеграции асинхронных данных в синхронную модель UI. Это позволит компонентам иметь возможность показывать состояния загрузки или ошибок до получения данных.

Рассматривают два паттерна, которые позволяют включать асинхронные источники в синхронные реактивные системы с сигналами:

- Resource (явная асинхронность, где ресурсы представляют асинхронные операции и имеют статус загрузки и значение).
- Suspense ("скрытая" асинхронность, когда чтение значений приостанавливается (suspend), пока не станут доступными. Другими словами, "async signals").

Resource призваны дополнить сигналы, расширяя реактивную систему Angular для поддержки асинхронных сценариев.

#angular

Подписывайся / Чат
👍41🎉1
Немного в продолжение темы новых API

Почитав представленные RFC, отметил для себя особо интересные пункты и решил добавить к сообщению следующее:

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

userData: Signal = asyncComputed(async () => fetch(/api/user/${currentUserId()}));

@suspense {
<user-profile [data]="userData()" />
} @fallback {
<loading-spinner />
}


Если данных в сигнале еще нет (не загружены), срабатывает флаг (на самом деле, выбрасывается исключение).
Suspense API отлавливает это состояние и отображает спиннер.
После того, как данные загрузились, флаг меняет состояние, "suspense boundary" повторяет попытку рендеринга и отображает полученные данные.

Нет необходимости писать кучу дополнительных флагов и собственных велосипедов.

Если добавят prefetch стратегии, которые будут подгружать данные перед инициализацией компонента (кнопки, части UI, например, наведение указателем мыши пользователя на ссылку, прокрутка области просмотра), это привнесет существенное улучшение DX.

Есть и недостатки. Не всегда может быть очевидно, почему часть приложения не загрузилась или UI выглядит не так, как нужно. С отладкой тоже пока непонятно. Dev tools планируют обновить, но гораздо позже.

httpResource

Судя по RFC, это обертка над httpClient, захватывает весь HTTP-стек Angular, включая интерсепторы и утилиты тестирования. Есть отличия:

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

Пример конфигурации:

results = httpResource({
url: '/api/query',
method: 'POST',
body: {...},
params: {
'rowLimit': 100,
},
});


Одна из целей httpResource - улучшение типо-безопасности. По умолчанию возвращается "raw type", для JSON unknown, для остальных возвращается объектный тип с указанием Blob, string и тд. Что более интересно, планируется добавить функцию parse, позволяющую преобразовать значение в любой тип, добавив валидацию.

Пример интеграции с Zod:

const User = zod.object({
id: zod.number(),
name: zod.string(),
// ... other fields ...
});

const user = httpResource(..., {parse: User.parse});


Планы у команды Angular грандиозные, пока можно изучить планируемые обновления. Ссылки я скинул в предыдущем сообщении:)

#angular

Подписывайся / Чат
👍4
Следующее обновление, похоже, будет дополнено еще одной фичей!

Ближе к выходным опубликовали МР с улучшенной поддержкой TS для свойства host.

Исторически, значения и так были типизированы при использовании с декоратороми @HostBinding(), @HostListener(). Но иногда все же возникали баги с проверкой типов в директивах. Эти проблемы сейчас и решают. И настойчиво рекомендуют переходить c декораторов на свойство host, поскольку именно этот вариант будет исправляться и поддерживаться.

Тем временем, в комментах уже спрашивают про поддержку Tailwind:)

#angular

Подписывайся / Чат
👍2
Инициатива Interop

📌 Для тех, кто не слышал, что это.
Это совместная работа крупнейших команд разработчиков браузеров (Google Chrome, Mozilla Firefox, Microsoft Edge и Apple Safari) для согласованной разработки фич, чтобы стандарты быстрее распространялись и получали стабильную кроссбраузерную поддержку.

Например, одним из предыдущих достижений является обеспечение поддержки современных спецификаций CSS и HTML. Одна из целей инициативы состояла в улучшении совместимости CSS-свойства gap для Flexbox и Grid Layout, которое теперь корректно работает.

📌 В феврале были анонсированы фичи для проработки в этом году. Вот некоторые из них: новые методы для WASM, Storage Access API, URLPattern, Anchor positioning.

📌 Для Storage Access API планируют добавить document.requestStorageAccess(), который повзоляет содержимому iframe запрашивать разрешение на хранение и чтение файлов cookie и других данных сайта. И document.hasStorageAccess(), который, соответсвенно, проверяет, предоставлено ли разрешение.

📌 Что касается WASM, то упоминаются два улучшения:
- Resizable Buffers (позволяют динамически изменять размер памяти, выделенной для модуля WebAssembly, прямо во время выполнения программы, что полезно для оптимизации использования памяти и повышения производительности приложений, работающих с большими объемами данных).
- JS String Built-ins (помогают преобразовывать данные между форматом WASM и привычными строковыми типами JS).

📌 Кроме того, продолжают работу над улучшением совместимости обработки MouseEvent в Safari. Да, наконец-то!!! Стоит сказать, что в прошлом году Safari значительно улучшил поддержку.

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

В 2025 основными направлениями инициативы являются обеспечение одинакового поведения CSS, улучшение конфиденциальности с помощью Storage Access API (но, пока отсутствует хорошая автоматизированная система тестирования для проверки конфиденциальности в разных браузерах) и улучшение доступности(a11y).

Подписывайся / Чат
👍5
Все наверняка слышали о портировании компилятора Typescript на Go. В результате чего планируется ускорение сборки проекта в 10 раз. Считаю важным тоже об этом написать и собрать источники в одном посте.

Почувствовать столь существенный прирост возможно будет в 7 версии.

Что необходимо мигрировать?

📌 CLI компилятора
📌 Language server (причем новый будет поддерживать LSP для упрощения работы редакторов кода)
📌 Тулинг, необходимый для работы TS.

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

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

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

Очень многообещающий анонс с далеко идущими перспективами.

Репозиторий с обсуждением.
Статья

#typescript

NgStream / Чат
👍1
Недавно побывал в Питерском музее Яндекса. Это восторг! Опишу пару экспонатов.

ZX Spectrum - про него точно слышали все! Разработан британской Sinclair Research в 1982, стал культовым в Великобритании и странах Восточной Европы из-за низкой цены и высокой доступности. Он обладал простым интерфейсом и базовыми возможностями программирования

Микроша – советский ПК, созданный в начале 80-х на базе TRS-80 Model I, но адаптирован под советское производство. Был популярен среди программистов, благодаря надежности и простоте. И обратите внимание на названия моделей!

Агат – первый советский ПК для массового использования, выпущен в 70-х и использовался в школах, НИИ. Его существенный плюс - поддержка работы с дисками (большинство были с кассетами для хранения данных).

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

NgStream / Чат
👍21🔥1