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
Давайте поговорим еще об одном инструменте из TypeScript: T[number].

Это вывод типов (derived types) с использованием indexed access types. Данный подход может пригодиться для объявления типа вместо enum. О минусах работы с ним я писал здесь.

Для примера определим массив и через typeof получим тип.

const possibleResponses = [
{
status: 200,
body: 'Success',
},
{
status: 404,
body: 'Not found',
},
];
type Responses = typeof possibleResponses;
// type Responses = { status: number, body: string }[];


Сейчас тип это массив объектов с полями status,body. Попробуем убрать массив из типа и получить тип самого объекта. Применим решение с T[number].

type Responses = possibleResponses[number];


В этом случае мы говорим вывести все свойства объекта, доступ к которым осуществляется через numeric key.

Важно задекларировать исходный массив as const, что заставит вывести буквальные значения массива. Иначе TS извлечет тип string[].

Пример использования:
const roles = ['admin', 'editor'] as const;
type RolesType = typeof roles;
type Role = RolesType[number];
// type Role = 'admin' | 'editor';


Прикрепляю ссылку с примерами использования deriving types.

#typescript

NgStream / Чат
5🤔1
Новости предстоящего обновления

📌 В версии 20.2 появится возможность указывать алиас as в блоке else if, что немного упростит чтение кода. Соответствующий МР появился на прошлой неделе.

@if (template) {
template 1
} @else if (loaderTemplate(); as state) {
<skeleton [loading]="state.loading">
}


Вы можете заметить некоторые пересечения с использованием в шаблоне директивы @let, добавленной пару версий назад. Если посмотреть на CanIUse, то статус stable с 18.2. Но сходство заметно только на первый взгляд.

В чем же разница?

- @let позволяет задать полученное значение на более широкий контекст. Например, на весь шаблон.
- as все-таки предназначен для случаев, когда значение требуется только в одном блоке. В общем, у него меньше зона покрытия. Эту идею стоит учитывать при выборе инструмента.

📌 Свойство lastSuccessfulNavigation из Router API станет сигналом.

// 20.1
const navigation = this.router.lastSuccessfulNavigation;
// 20.2
const navigation = this.router.lastSuccessfulNavigation();

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

Ожидаем обновлений с переходом остальных элементов Router на сигналы!

📌 Разработчики улучшили вывод типов при работе с событиями DOM. Т.к. тип EventTarget | null слишком общий, он доставляет некоторые неудобства при обработке и получении value c input. При этом не всегда возможно сделать cast типов (as HTMLInputElement). Например, в шаблоне.
Теперь для void элементов, например, <input>, <img>, <br>, где всплытие невозможно, тип $event.target будет определяться автоматически. Это уменьшит количество ошибок TypeScript и не будет необходимости писать лишние проверки.

Ссылка на МР.

#angular

NgStream / Чат
🔥91
Новости signal-based forms

Команда Angular обновила прототип сигнальных форм, перетащила в отдельный пакет @angular/forms/signals и планирует влить в master.

Насколько я понял, на данном этапе пакет не будет доступен (нет package.json) и он с пометкой, что дизайн API еще в разработке и может измениться. МР с кодом, большим количеством тестов и документацией можно посмотреть по ссылке.

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

📌 Формы состоят из 4 основных блоков: Data Model, Field State, Field Logic, UI Controls.
📌 Ключевой принцип в том, что форма не хранит данные внутри. По сути, это ссылка на модель. Единый источник правды хранится в WritableSignal. При обновлении модели обновляется сигнал в форме и, наоборот, при обновлении формы обновится модель.

userModel = signal<User>({name: '', username: ''});
userForm = form(this.userModel);


📌 Как и с другими сигналами, form() требуется объявлять в injection context или передав ссылку на контекст.

private readonly injector = inject(Injector);
...
const form = form(this.userModel, {injector: this.injector});


Заметки команды, показанные ранее, я разбирал в канале. Тогда в них не было ничего сказано об интерфейсе ControlValueAccessor.

🛠 Сейчас в коде я нашел класс, обеспечивающий interop. Отмечено, что это заглушка NgControl для обеспечения совместимости с текущей версией контролов. Он реализует только часто используемые свойства и методы настоящего NgControl. Этот класс используется, например, в директиве [control].

🛠 Директива [control] связывает поле формы (FieldState) и шаблон (UI), обеспечивая двустороннюю привязку данных и состояние формы. Из описания видно, что она может работать с CVA, но только в режиме совместимости для реактивных форм и стоит предпочесть сигнальный FormValueControl, нативный html элемент. Получается, что для сигнальных форм необходимости в CVA не будет, а для разработки собственных контролов предполагается реализовывать интерфейс FormValueControl. А NgControl, скорее всего, будет помечен, как deprecated через какое-то время после релиза.

В общем, видно, что переход на сигналы еще активно разрабатывается и полная картина, включая миграцию проекта с Reactive/Template форм, пока не совсем ясна. Ждем обновлений!

#angular #signal_forms

NgStream / Чат
🔥82❤‍🔥1👍1
В ESLint 9.34.0 будет доступен многопоточный линтинг

📌 По заявлениям команды ожидается прирост примерно в 1.5 - 3 раза для крупных проектов. Добиться ускорения получилось за счёт использования механизма worker threads из Node.js API.

📌 Ранее, задачи, которые больше всего нагружали CPU - парсинг AST дерева, работа сложных правил, выполнялись в одном потоке Event Loop, что могло приводить к его блокировке. Теперь main thread становится менеджером - он создает пул worker threads, управляет задачами, перенаправляя их в другие потоки и агрегирует данные.

📌 Основная проблема была в том, что worker threads обмениваются данными с главным потоком через механизм structured clone, что не позволяло передать довольно сложную конфигурацию, включающую кастомные правила, инстансы плагинов и тд. Решить этот вопрос позволяют Options Modules. Вместо передачи конфига каждый worker клонирует его и работает с независимой копией.

📌 Также было ограничение с обработкой только одного файла, теперь появилась возможность параллельного выполнения.

📌 На примере показано объявление ECMAScript модуля и создание инстанса через ESLint.fromOptionsModule(), передав в нее ссылку на конфиг.

const configURL = new URL("./my-eslint.config.js", import.meta.url).href;
const optionsModuleText = `
import config from ${JSON.stringify(configURL)};

export default {
concurrency: "auto",
overrideConfig: config,
overrideConfigFile: true,
stats: true,
};
const optionsURL = new URL(`data:text/javascript,${encodeURIComponent(optionsModuleText)}`);
const eslint = await ESLint.fromOptionsModule(optionsURL);


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

NgStream / Чат
🔥12🤔2
Navigation API

📌 На прошлой неделе в репозитории Angular появился МР, в котором говорится о поддержке экспериментального Navigation API! Это показывает желание более тесно интегрироваться с платформой и использовать будущий стандарт индустрии вместо самописных решений.

📌 Спецификация самого API еще находится на этапе обсуждения в WICG (Web Platform Incubator Community Group). Хотя, в целом, ее одобряют, детали реализации (сигнатуры методов, названия событий) теоретически могут измениться. Кроме того, потребуется время на миграцию, это не просто замена одного метода на другой, а смена парадигмы управления навигацией.

📌 Судя по комментарию к МР, новый API пока что может ломать некоторые тесты, но есть временное решение с TestBed.

Что такое Navigation API?

🛠
Это новый стандарт, предоставляющий интерфейс управления историей переходов и URL, заменяющий устаревший History API. Задача - сделать навигацию более предсказуемой, надежной и удобной для разработчиков.

🛠 Поскольку History API вообще не предназначен и не проектировался для управления целым приложением, это приводит к усложнению кода при попытке написать какую-либо нетривиальную логику, трудностям с обработкой кнопок браузера "Назад/Вперед" и тд.

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

🛠 Какие ограничения накладывает данное API?

- Компромиссы в текущей реализации. Например, navigate() не срабатывает при первоначальной загрузке страницы. Это подходит для SSR, но требует доработки логики для SPA (MPA), т.к. нужно инициализировать код, отвечающий за рендеринг начального состояния страницы.
- Работает только в контексте одного окна или одного iframe, но не между ними, т.е. он работает только с историей текущего топ-левел окна или конкретного iframe.
- Не позволяет модифицировать последовательность записей в навигации. Сценарий с закрытием модалки и удалением временного url, который использовался для открытия из истории будет невозможен с новым подходом.

Что с поддержкой у браузеров?

Здесь пишут, что на данном этапе проблемы с поддержкой только у Firefox. Даже Safari имеет ограниченную поддержку.

Новый подход сможет улучшить DX и стандартизировать существующие решения. Ждем обновлений!

#js #angular

NgStream / Чат
👍5🤔1
Возможно, вы слышали, что разработчики Angular добавили целый раздел по работе с AI. Пару недель назад команда представила инструмент по миграции приложения на zoneless с помощью AI. Это MCP сервер, который автоматизирует процесс миграции.

Стоит коротко сказать, что такое MCP.

📌 MCP - Model Context Protocol, открытый протокол взаимодействия LLM моделей и всевозможных инструментов.

📌 Эта штука предоставляет AI прямой доступ к самой актуальной информации: официальной доке, текущим рекомендациям и структуре конкретного проекта, например, монорепе или набору библиотек.

📌 Для этого у MCP есть набор инструментов, которые используются при ответе на вопрос:

get_best_practices
Получает текущие стандарты написания кода для Angular.

search_documentation
Ищет ответ в доке, что понятно по названию.

list_projects
Анализирует структуру workspace.

📌 Данный подход решает ключевую проблему LLM - работу на устаревших данных. Также гарантирует, что будут предлагаться более корректные и актуальные решения. Аналогично Language Server Protocol организует взаимодействие между редактором и языковым сервером, но, в данном случае, взаимодействие происходит между LLM, CLI и проектом, анализируя и получая данные о миграции. В файлах даже есть описание требований, которые предъявляются к каждому этапу миграции.

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

Уже заметна тенденция - более точная работа AI с разворачиванием специализированного MCP-сервера с более точным и актуальным контекстом. Возникает вопрос, насколько большие проекты можно будет отдавать модели и как быстро будет идти миграция.

📌 Если вам интересна эта тема, то на 16 сентября анонсировали Angular AI Event, на котором расскажут о работе AI, инструментах и возможных интеграциях! Ссылка на live трансляцию на youtube.

И в пятницу опубликовали сообщение в блоге с списком недавних обновлений 20.1 и 20.2. Summer update ;)

#angular

NgStream / Чат
👍51🤪1
Со следующей версии использование функции provideHttpClient будет необязательным. Добавлять в список providers[] потребуется только для указания дополнительных параметров, например, withFetch() или withInterceptors([]).

Что это значит?

Что зависимость автоматически будет providedIn: root на уровне приложения. И далее можно будет сразу в нужном классе инжектить зависимость HttpClient.

@Injectable({ providedIn: 'root' })
export class HttpClient {}


#angular #angular21

NgStream / Чат
❤‍🔥64🔥3🤔1
Jetbrains анонсировали JavaScript Day на 2 октября. Митап бесплатный и пройдет онлайн. Состав спикеров впечатляющий!

Ryan Carniato, maintainer SolidJS с рассказом о сигналах, реактивности. Один из докладов, который хотелось бы послушать.

Lydia Hallie, developer advocate, Bun с темой, интересной для многих: Bun: The Fast JavaScript Runtime.

Среди других популярных спикеров Kent C. Dodds, Victor Savkin, Alexander Lichter.

#js

NgStream / Чат
🔥4
Angular выпустили предрелизную версию 21.0.0-next.2. Среди прочих нововведений есть сигнальные формы, с которыми я решил поэкспериментировать. Для желающих добавляю ссылку на stackblitz.

📌 Сразу бросается в глаза переход на декларативную валидацию и rule-based подход.

📌 Сейчас мы добавляем валидаторы в массив, навешивая на контролы или группу контролов. С signal forms процесс построен иначе.

Как и было указано ранее в заметках команды, в новом подходе, в первую очередь, нужно смоделировать модель в отдельном сигнале (источнике) и тип формы. Затем передать источник в форму и добавить валидаторы. Для связи модели и шаблона используется директива [control]. Она обеспечивает "two-way binding" между состоянием элемента формы (value, disabled, touched, aria-attributes) и UI. Каждый элемент формы это Field, которые хранит состояние. Для получения состояния обращаемся к инстансу, который возвращает FieldState, из него можно получить value, errors, disabled и т.д.

Из плюсов я бы отметил:

📌 Декларативная запись. Проще читать, выделять уровни абстракций и использовать термины из предметной области.
📌 Расширяемость. За счет заявленной schema composition. С помощью функции apply можно выносить общие правила валидации и бизнес-логики для часто используемых структур данных (например, адрес или дата) в отдельные, переиспользуемые схемы, что позволит избежать дублирования кода.
📌 Тестируемость. Поскольку такая запись зачастую является чистой функцией, ее проще тестировать, делая это изолированно.

Есть и недостатки:

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

📌 Нужно стараться писать абстрактные и гранулярные валидаторы (правила). Мнения, касательно этого пункта могут отличаться и не каждому проекту такой способ подойдёт.

Нашел и некоторые баги (или я не понял идею?).

При добавлении валидаторов required() и email() на поле email и указании в модели email: null - первый валидатор не отрабатывает вообще, массив errors() оказался пустым, а второй требует только string для входного значения. Это не совсем удобно, т.к. для проверки наличия значения необходима декларация вида None|Some<A>. В общем, даже эти два валидатора вместе дружат только с ограничениями, либо, повторюсь, есть дополнительные параметры для настройки, которые я не увидел. В итоге написал простой собственный валидатор, поскольку встроенный не отличается строгостью, так же, как и в реактивных формах.

Видно, что проделана большая работа по упрощению подхода, в целом. Ждем обновлений!

Это уже третья заметка на канале из серии о сигнальных формах!🎉

#angular #angular21 #signal_forms

NgStream / Чат
👍5🤔3❤‍🔥11
📌 Появился ресурс, на котором можно удобно посмотреть совместимость версий библиотек. Может быть полезно при обновлениях. Автор: Gerome grignon


📌 Jean Meche сделал интерактивный пример работы директивы track для элемента for. Наглядно и понятно для каких случаев какой вариант выбирать. Можно скинуть коллеге и использовать на ревью.

#js #angular

NgStream / Чат
🔥4👍1
Я наконец-то добрался до возможности написать заметки в канал. Месяц выдался напряженным.

Тем временем уже опубликованы предрелизные и RC сборки 21.0.0. Одной из самых ожидаемых фичей является Signal forms. В канале уже есть заметки, собранные по dev notes команды Angular. А вы пробовали превью сигнальных форм? Понятно, что реализация пока не рекомендуется для enterprise проектов. Я немного поковырял на пет проекте и заметил, что DX заметно подрос!

Рассмотрим стандартный сценарий - форма заказа товара, соответствующая OrderForm.

interface OrderForm {
information: FormGroup<InformationGroupControls>,
cost: FormGroup<CostGroupControls>,
additionalDetail?: FormGroup<AdditionalDetailControls>
}


📌 Reactive Forms состоят из нескольких sub FormGroups. И некоторые из них добавляются по специфичной бизнес логике. Для жонглирования синхронизации UI и модели данных приходится использовать addControl и removeControl. На прктике все это обрастает значительным количеством логики, которая потом сложна для восприятия.

📌 Signal forms. Если еще не разобрались, задам контекст. Эти формы строятся на основе готового объекта (модели данных). В нашем случае представим объект, соответствующий интерфейсу OrderForm. И здесь для управления отображением формы предусмотрен немного другой API. Есть 2 подхода. В зависимости от того, надо ли отображать модель на UI.

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

- поля присутствуют в модели, но скрыты
- сохраняется и отрабатывает валидация
- состояние сохраняется при скрытии/показе

2 случай. Данные не нужно отображать. В этом случае поля опциональны в модели, а валидация стоит применять через applyWhenValue().

orderForm = form(this.orderModel, order => {
// 1 случай. Добавлена валидация для additionalDetail:
apply(order.additionalDetail, orderDetailSchema);

// ИЛИ
// 2 случай. Добавить валидацию, если представлены данные
applyWhenValue(
order.additionalDetail,
(detail) => detail !== undefined,
orderDetailSchema,
);

// Пользователь не должен видеть часть формы, пока не отмечен checkbox
hidden(order.additionalDetail, ({valueOf}) => valueOf(order.showAdditionalDetail));
});


Еще на Q&A сессии с разработчиками говорилось, что перед созданием формы возможно объединить несколько сигналов. Например, использовать linkedSignal().

selectedItem = signal("Phone");
quantity = linkedSignal({
source: this.selectedItem,
computation: () => 1,
});


Если состояние формы инициализируется из resource(), то linkedSignal() может указать, как должно обновляться состояние формы, когда сервер присылает новое значение. Поскольку он получает старое и новое значение от сервера и знает текущее состояние, может выполнить "3-way merge". Пока что звучит непонятно и нужно смотреть детали.

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

📌 Производительность без необходимости ручной оптимизации. Нет лишних проверок изменений.
📌 Совместимость с сигналами и предсказуемое управление состоянием. Самый очевидный плюс, теперь формы вписываются картину всего приложения, поскольку при первом внедрении сигналов переключения доставляли неудобства.
📌 Композиция и переиспользование. За счет schema для построения и валидации (о чем писал раньше), linkedSignal, композиция сложных форм становится более интуитивной.
📌 Типобезопасность. Типизация форм стала лучше, меньше потребности в приведении типов, как это было, например, с FormRecord<T> для динамических форм.

#angular #angular21 #signal_forms

NgStream / Чат
🔥7
На улице осень, близится релиз Angular, который мы сможем заценить в течение пары недель.

С 21 версии Vitest будет использоваться как test runner по умолчанию для новых проектов. Но пока что под флагом experimental.

Дело в том, что в 2023 году Karma стала deprecated и вставал вопрос, на какой инструмент переходить. Кстати, в течение года команда Karma все еще правила баги, критические уязвимости и тд. В итоге был выбран Vitest, который обладает мощным API, по сравнению с Jasmine и даже Jest. Кроме того, включает browser mode, что означает запуск тестов в реальном окружении. Vitest работает на базе Vite.

📌 Преимущества Vitest
- Ускорение благодаря ES-модулям;
- Нативная поддержка TypeScript;
- Встроенная поддержка моков и spies;

📌 Async-oriented API?
Новые инструменты разработаны с учетом обратной совместимости - работа с TestBed и существующими утилитами.
Одна из приглянувшихся мне фичей - Test Context, которая позволяет задать контекст тестирования. На первый взгляд, похоже на DI для тестов. Будет удобнее работать, например, с фича флагами, передавая конкретный контекст для теста. Есть и другие интересные инструменты - Polling Feature, Soft Assertions.

📌 При чем тут ZoneJS?
Zone.js патчит setTimeout, setInterval и тд, что позволяет отслеживать асинхронные операции. Однако нативные Promise оставались вне зоны контроля. Сейчас есть некоторые проблемы с долгим ожиданием таймеров и непредсказуемым поведением в сложных сценариях.

С 21 версии zoneless является стандартом. Это означает, что
- fakeAsync() и waitForAsync() перестают работать без явного включения Zone.js
- Существующие тесты требуют переписывания асинхронных частей.
Vitest и Jest предлагают собственные механизмы контроля времени:

// Включение fake timers
vi.useFakeTimers();

// Запуск всех таймеров (включая setInterval)
vi.runAllTimers();

// Запуск только ожидающих таймеров
vi.runOnlyPendingTimers();


📌 Недавно был влит MR, добавляющий возможность выбора между vitest (default) и karma и установку соответствующего билдера со всеми зависимостями.

📌 Разработчики предполагают постепенную миграцию. Стоит начать с добавления Vitest параллельно с существующей конфигурацией, затем постепенно переносить наиболее медленные тесты, заменять fakeAsync() на fake timers. И полностью перейти на новую инфраструктуру.

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

#angular #angular21

NgStream / Чат
🔥6❤‍🔥11
Developer Event, на котором будет представлен Angular v21 со всеми нововведениями, анонсирован на 20 ноября.

Стрим пройдет в 22:00. 👾

Кстати, на сайте теперь есть раздел с dev events. Может я не замечал раньше🤔

Что больше всего ожидаете от релиза?

📌 Новые инструменты Angular MCP Server для улучшения AI-рабочих процессов и генерации кода.
📌 Signal Forms - новый, упрощенный подход к формам.
📌 Новые детали о пакете Angular ARIA. Неужели увидим a11y инструменты?

#angular #angular21

NgStream / Чат
🔥51❤‍🔥1
Оптимизации @defer

Defferable views, добавленные в Angular 17, позволяют лениво загрузить данные по определенному условию. Для определения момента, когда пользователю необходимо загрузить и показать блок на странице, используются триггеры (triggers). Некоторые из них и были улучшены.

@defer {
<large-component />
} @placeholder {
<p>Placeholder content</p>
}


📌 В текущей реализации использование триггера prefetch on viewport немного не логично - если @placeholder уже находится в области viewport и bundle уже загружен, стоит уже отображать компонент, а не использовать prefetch. Это означает, что prefetch on viewport имеет смысл только при использовании с target, который появляется перед @defer, но есть нюанс - легко забыть обновить target при перемещении или переиспользовании компонентов.

Резюмируя, была добавлена поддержка offset параметра IntersectionObserver для триггеров on viewport, prefetch on viewport и hydrate on viewport, который будет активировать загрузку до того, как элемент достигнет viewport.

@defer(on viewport; prefetch on viewport(200)) {
<component />
}


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

Подробности по ссылке.

#angular #angular21 #signal_forms

NgStream / Чат
❤‍🔥43
Скорее всего, в Angular 21 будет расширен набор возможных типов ViewEncapsulation. Причем, на фоне разговоров о формах про него молчат!

Сейчас, как мы знаем, доступны три типа (enum ключа).
- Emulated. Применяется по умолчанию. Стили изолированы для компонента
- None. Стили становятся глобальными и применяются ко всему приложению.
- ShadowDom. Стили полностью скрыты нативным способом в ShadowDOM. Хорошо подходит для написания виджетов в приложении, нотификаций или веб-компонентов.

Будет добавлен ViewEncapsulation: IsolatedShadowDom. Пока в статусе experimental.

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

#angular #angular21

NgStream / Чат
👍10
В новой версии Angular 21 в составе CLI-инструментов для MCP появится коллекция из 18 готовых примеров, которые наглядно показывают, как работать с сигнальными формами. Что такое MCP, я рассказывал выше.

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

Примеры включают
- Core concepts and basic setup
- Built-in and cross-field validation
- Dynamic and conditional form structures
- Custom form controls and reusable validators
- Asynchronous operations and third-party integrations (Zod)
- Best practices for testing, accessibility, and styling

Что еще любопытно, разработчики сразу добавляют ARIA атрибуты для валидации форм. Например, aria-describedby="email-errors" и aria-errormessage, говорящий о том, что за ошибка произошла в конкретном контроле.

#angular #angular21

NgStream / Чат
👍4
Angular 21 вышел!

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

📌 Signal Forms. Experimental. Модель формы определяется через сигнал, который автоматически синхронизируется с привязанными к нему полями формы через директиву [field]. Schema-based валидация. ControlValueAccessor теперь optional, работает в режиме обратной совместимости.

📌 Angular Aria. Developer Preview. Это набор headless-директив, которые реализуют распространённые WAI-ARIA паттерны доступности. Они обрабатывают клавиатурные события, ARIA-атрибуты, управление фокусом и поддержку скринридеров. Пока не совсем понятны детали и как применять на практике. Интересно, что у Angular свой инструмент, наверняка вдохновленный Material.

📌 MCP Server. На презентации Developer Event большой акцент был сделан на развитии инструментов. В частности, показали автоматическую миграцию на zoneless с пошаговым планом.

📌 Vitest. Test runner по умолчанию для новых проектов. Подробнее писал здесь. Также в документации посвящена отдельная страница по миграции.

📌 Zoneless. Stable. Включен по умолчанию. Из преимуществ - улучшение Core Web Vitals, нативная поддержка async-await, уменьшение размера бандла, упрощение отладки и лучший контроль за изменениями.

Кроме того:

📌 HttpClient будет добавлен в приложение по умолчанию. Нет необходимости указывать provideHttpClient().

📌 Добавили поддержку регулярных выражений в шаблонах. Выглядит сомнительно, на мой взгляд. Шаблон должен отвечать за отображение, а не наброс логики, которую зачем-то вытащили из класса.

@let isValidNumber = /\d+/.test(someValue);

@if (!isValidNumber) {
<p>{{someValue}} is not a valid number!</p>
}


📌 SimpleChanges теперь generic! Раньше был указан any для previousValue и currentValue , по факту означает отключение типизации.

Использование ngClass не рекомендуется. Вместо него стоит использовать class. Добавлен schematic.

ng generate @angular/core:ngclass-to-class 


[style]="{ 'border-color': borderColor() }"


📌 Обновлена страница Angular Can I Use со списком фичей и их статусами. Почему-то плохо открывается, только через vpn.

В общем, обновление получилось интересным с значительными улучшениями. Если еще не обновились и есть возможность - самое время! Представленные изменения существенно улучшают DX и направлены на повышение производительности приложений.

Кстати, отдельно хочется отметить необычную подачу с видеоигрой на Developer Event. Ну, круто же!)

Заметка в блоге с подробностями.

#angular #angular21

NgStream / Чат
🔥6👍2
В новой версии, как многие заметили, изменился подход к созданию custom control.
Почему-то многие говорят о том, что создание контролов через ControlValueAccessor было неудобным, много бойлерплейта… Я так не считаю, не вижу сложности в реализации интерфейса в несколько строк кода. Несравнимо с какими-нибудь сторами… Но не спорю, что стало еще проще. Нет необходимости указывать каждый раз provide: NG_VALUE_ACCESSOR токен, реализовывать методы.

В общем, теперь интерфейс ControlValueAccessor будет использоваться преимущественно при написании custom control для Template-Driven и Reactive Forms. Но совместим с signal forms!

Пока что CVA не помечается, как deprecated, просто сигнальные формы рекомендованы для использования:) Скорее всего, сделано на время перехода, которое может быть долгим.
А для создания signal custom control необходимо реализовать интерфейс FormValueControl<T> , который обязывает объявить только поле value:ModelSignal<T> = model(). При необходимости добавить disabled input. Для реализации switchers/toggles нужен, соответственно, FormCheckboxControl<T>. И тот, и другой наследуются от FormUiControl, который содержит все необходимые свойства: touched, dirty, required, pending, hidden, errors и тд.

Для вставки самого компонента используется директива [field].

На мой взгляд, улучшение больше направлено на новичков для уменьшения порога входа. Как считаете вы? Если не согласны, пишите в комментариях свое мнение!

#angular #angular21

NgStream / Чат
🔥6
В декабре появились новости об уязвимостях в Angular

И здесь в чате об этом писали, спасибо @ngxSamurai за новость👍🏻

📌 Сначала в репозитории опубликовали сообщение о CSRF уязвимости.
Суть в том, что URL, начинающиеся с //, обрабатываются некорректно. Рекомендуется проверить приложение на наличие динамически формируемых URL, особенно с участием пользовательских данных.

📌 Но об этом уже многие слышали, но на прошлой неделе добавилась XSS уязвимость, которая возникает из-за недостаточной проверки URL-атрибутов: Схема безопасности некорректно классифицирует некоторые атрибуты, которые могут содержать URL (например, xlink:href в SVG). Это позволяет передавать в них javascript: URL, которые не блокируются.

📌 Уязвимость в SVG: Атрибут attributeName в элементах SVG-анимации ( , и др.) не проверялся должным образом. Злоумышленник может динамически назначить этот атрибут как "href" и передать в values вредоносный javascript: URL, что также обходит санитизацию.

Команда Angular рекомендует обновить приложения до следующих версий:
- Angular v19: обновиться до 19.2.17
- Angular v20: обновиться до 20.3.15
- Angular v21: обновиться до 21.0.2

#angular

NgStream / Чат
👍41👏1
Перегрузка функций

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

📌 Ключевое правило - более специфичные сигнатуры должны быть выше, общие (any, unknown) - ниже. TypeScript использует первую подходящую перегрузку сверху вниз.

// Хорошо
declare function fn(el: HTMLDivElement): string;
declare function fn(el: HTMLElement): number;
declare function fn(el: unknown): unknown;

// Плохо
declare function fn(el: unknown): unknown;
declare function fn(el: HTMLElement): number;


В примере выше, если первым поставить unknown, то узкие сигнатуры не будут использованы, т.к. этот тип является супертипом и будет совпадать всегда.

unknown ⊃ any ⊃ HTMLElement ⊃ HTMLDivElement
// где ⊃ означает "является супертипом"

Несмотря на то, что union types безопаснее, перегрузки функций обеспечивают лучший DX для других разработчиков через автодополнение. Пишите в комментарии, если тоже сталкивались или есть другой подобный опыт:)

#typescript

NgStream / Чат
👍5❤‍🔥1
Обновление OWASP

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

📌 О чем вообще речь?

OWASP - сообщество, которое создает открытые стандарты, инструменты и документацию по безопасности веб-приложений.

📌 Сначала коротко о самых известных инструментах.

- OWASP Cheat Sheet - руководства по конкретным темам (аутентификация, криптография, защита от SQL-инъекций и тд).
- OWASP Application Security Verification Standard - описывает требования безопасности и используется для проведения аудитов. При проектировании приложения позволяет не забыть о валидации данных на клиенте, работе с токенами, защите от CSRF.
- OWASP Zed Attack Proxy (ZAP) - инструмент для динамического тестирования безопасности (DAST), который помогает автоматически находить уязвимости в работающем приложении.

📌 Теперь об отчете.

Самым интересным кажется появление в рейтинге supply chain атак. Если кратко, то это тип атак через любой из компонентов цепочки поставки – сторонние библиотеки, инфраструктура сборки, хранения кода, мониторинга. При этом риск охватывает и инструменты разработки на основе ИИ, которые сами становятся вектором атаки (небезопасный сгенерированный код, уязвимости в самих помощниках).

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

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

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

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

NgStream / Чат
👍3