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! 🌟
Мы прекрасно знаем, как вы любите Angular. Сейчас ещё есть возможность зарегистрироваться на Angular Meetup #23.

Мы будем обсуждать текущее состояние Angular и что нас ждет. Узнаем, сколько версий фреймворка нужно пропустить, чтобы считать свой проект устаревшим. 👩‍💻

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

Если ты с нами
1️⃣ Регистрируйся здесь
2️⃣ Добавляй напоминание в календарь
3️⃣ Поделись этим сообщением с друзьями - чем больше нас будет, тем веселее!

Если не получится прийти на митап, можно посмотреть трансляцию онлайн.
🔥4
Angular 19 вышел

Что нового? Я подчеркнул основные фичи, на мой взгляд.

📌 Поддержка TS 5.7
📌 Теперь в статусе stable: takeUntilDestroyed, signal quieries, model, inputs, outputToObservable, outputFromObservable, @let
📌 Добавлены схематики для конвертации @Input , DOM queries на сигнальные.

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


📌
Добавлен afterRenderEffect() замещает случаи, где нужно использовать effect(). позволяет создавать эффекты для работы с DOM элементами. При этом Angular будет оптимизировать подобные вызовы.
📌 При обновлении будет автоматическая миграция, в ходе которой удалится флаг standalone: true для существующих standalone сущностей и добавится standalone: false для NgModule. При желании можно включить режим компилятора strictStandalone для генерации только таких компонентов.
📌 Добавлено свойство для обнаружения неиспользуемых импортов standalone сущностей. Опция включается в tsconfig.

{ "angularCompilerOptions": {
"extendedDiagnostics": {
"checks": {
"unusedStandaloneImports": "suppress"
}
}
}
}


📌
Добавлено новое Incremental Hydration API.
📌 Добавлен input в RouterOutlet, который позволит передавать данные из родительского компонента в компоненты вывода. Значение будет доступно для дочерних компонентов через токен ROUTER_OUTLET_DATA.

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

#angular
7👍2
Немного для дизайнеров

Я очень редко публикую какие-либо заметки о дизайне. И сейчас тот самый случай)

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

📌 designsystems.surf - здесь можно найти ссылки на дизайн системы известных компаний. Можно вдохновиться решениями.

📌 component.gallery - посвящен UI компонентам для веба. Тут собраны дизайны из разных UI библиотек. Для тех, кто сейчас проектирует систему, собирает макет и тд может быть весьма полезен. Мне стало интересно, что будет написано о компоненте Popover. На странице указаны рекомендации по реализации, советы в области a11y. Даже показан пример недавно появившегося Popover API.

В общем, может пригодится:) Надо же разбавить фронтовые темы небольшими рекомендациями из сферы дизайна.

#ux_design
3👍2
Директивы ngStyle and ngClass deprecated!

В 19.1 уже будет рекомендация их не использовать. Вместо этого предлагается биндить значения к встроенным [class] и [style]. Давно собирались это сделать, решили только сейчас, несмотря на то, что фича продолжает довольно широко использоваться в проектах:)

МР содержит заметку с ограничениями, которые есть у нативных способов привязки:

📌 Нет поддержки Set.
📌 Не получится добавить несколько стилей/классов, разделенных пробелом.

Например, вместо подобной записи

<div [ngClass]="{ 'ring ring-pink-500 ring-offset-2 dark:ring-green-500' : condition }">


можно использовать такую:

<div class="{{ condition ? 'ring ring-pink-500 ring-offset-2 dark:ring' : '' }}"></div>

Как обычно, прикрепляю МР с подробностями.

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

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

#angular
4👍2
Обновление безопасности (CSP)

Только сейчас узнал, что еще было добавлено в новой версии! Теперь Angular автоматически будет генерировать hash-based CSP, реализуя строгую политику безопасности. Необходимо добавить параметр в angular.json:

"security": {
"autoCSP": true
}


Hash-based CSP позволяет указывать хеши для каждого встроенного скрипта, что делает их безопасными для выполнения. Это означает, что только скрипты с известными хешами будут выполняться, и злоумышленники не смогут внедрить свой код без соответствующего хеша.

Сегодня вместо того, чтобы предоставлять список разрешений, из которого можно загружать скрипты, рекомендуется использовать строгий CSP, который бывает двух видов: nonce-based и hash-based. Первый требует генерации уникального идентификатора для каждого ответа, CSP на основе хэша - идеальный выбор для статически обслуживаемого контента без рендеринга на стороне сервера (SSR).

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

#angular #js
👍5🔥3
Я решил написать о типах, которые могут помочь в определенной ситуации и позволят не городить лишние велосипеды. Уверен, что многие из подписчиков знают об этом, но не все. А, если у вас есть, что дополнить, особенно преимущества/недостатки, пишите в комментах!

ReturnType<T> — это Utility Type, который извлекает тип из возвращаемого значения любой функции. Может понадобится при работе с библиотекой, которая не экспортирует типы, но которые нам нужны. Другой пример: написание своей утилиты. Ну или какие-либо трудноизвлекаемые типы.

// type Message = Message.TextMessage;
type Message = ReturnType<typeof bot.telegram.sendMessage>

async function getMessage() {
const res = await bot.telegram.sendMessage('Text');
}


В примере выше тип Message будет точным типом, который используется в либе.

Преимущества:
1. Удобство и безопасность: автоматическое извлечение типа возвращаемого значения функции снижает вероятность ошибок и повышает читаемость кода.
2. Сокращение дублирования: не нужно вручную повторять тип возвращаемого значения, что облегчает рефакторинг и поддержку кода.
Есть и очевидный недостаток. Если функция не экспортируется/не видима, воспользоваться типом не получится.

Следующий тип - NoInfer<T> был добавлен относительно недавно - в TS 5.5. Нужен для вывода типов без сравнения с внутренними типами. Покажу на примере.

const list = [1, 2, 3, undefined];

list
.filter((item) => item !== undefined)
.map((item) => {
...
item.toString();
})


Раньше это вызвало бы ошибку, т.к. тип item в map() был number | undefined, не смотря на то, что в этой части кода undefined уже быть не может. В новых версиях данный пример отработает даже без каких-либо действий с нашей стороны. Параметр функции map() уже выведен корректно.

Что мы получаем? Точность типизации, что особенно полезно в сложных сценариях с generic типами.

function createFSM<TState extends string>(config: {
initial: TState;
states: TState[];
}): TState;

const example = createFSM({
initial: "not-allowed",
states: ["open", "closed"],
});

В примере выше TState складывается из возможных значений initial и states: "not-allowed" | "open"| "closed". Но, если мы хотим, чтобы тип initial был взят только из допустимых значений states? В этом случае сработает добавление initial: NoInfer<TState>; Теперь "not-allowed" будет указан, как ошибочный, поскольку не находится в наборе допустимых. Добавляя тип, мы сможем контролировать набор значений, которые TS извлечет из generic типа. Здесь статья с подробными примерами.

#typescript

Подписывайся / Чат
🔥31
Active zone

Новая статья от Саши Инкина - разбор нетривиальной задачи и решения. На первый взгляд, что сложного в управлении кнопкой с выпадающим меню? Однако, по мере реализации, выясняется множество деталей, о которых и пойдет речь.

- Практические примеры из Taiga UI.
- Детальный разбор решения и пограничных случаев.

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

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

#angular
👍1
JS Import Attributes

Не так давно данный пропозал был включен в стандарт EcmaScript.

В чем суть?

Раньше, при импорте модулей, JS не предоставлял возможности явного указания типа загружаемого ресурса. Это создавало проблемы безопасности и функциональности. Например, можно было случайно или намеренно загрузить файл, как JS модуль, хотя на самом деле это был JSON и т.д. Что в результате могло привести к выполнению нежелательного кода. Может показаться очевидным, что файл, заканчивающийся на .js, будет соответствовать файлу application/javascript. На практике в вебе широко распространено несоответствие между расширением файла и заголовком HTTP Content Type. Здесь описано более детально, можете ознакомиться.

Import Attributes (ранее назывался Import Assertions) позволяет явно указать тип модуля. Если что-то пойдет не так, то вернется ошибка.

Ниже пример использования с импортом JSON. Без with { type: 'json' } файл мог быть интерпретирован как JS, что привело бы к ошибкам. А теперь есть некий контракт между вашим кодом и runtime. Вы явно объявляете, какой тип модуля вы ожидаете:

import json from './data.json' with { type: 'json' };
console.log(json);


Если вы помечаете модуль типом: json, вы гарантированно получите либо данные JSON, либо ошибку, но не исполняемый код.

Преимущества

📌 Безопасность: Предотвращение выполнения некорректного кода.
📌 Явное указание. Повышает читаемость кода. Вне зависимости от контекста считаю плюсом.
📌 Расширяемость: Возможность поддержки новых типов ресурсов в будущем.

Ссылка на детали пропозала.

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

#js
👍4🔥4
Разница SRI и CSP
Недавно писал об улучшении политики безопасности CSP в Angular. И в комментариях получилось обсуждение о его отличиях с SRI. Вот решил чуть подробнее раскрыть тему и лучше разобраться самому.

Subresource Integrity (SRI) – механизм проверки целостности контента при загрузке с сервера. Он позволяет убедиться, что файл не был изменен во время передачи или хранения. Что особенно важно при использовании CDN или других сервисов для загрузки JS, CSS и другой статики.

Как работает SRI? При загрузке ресурса с использованием тега <script> или <link>, указывается хэш-сумма файла в атрибуте integrity. Браузер вычисляет хэш загруженного файла и сравнивает с указанным значением. Если совпадают, ресурс считается безопасным и загружается; если нет – браузер блокирует загрузку. Пример использования SRI:

<script src="https://cock.com/script.js"integrity="sha384-0aJk+WbYjC...WLWHLl" crossorigin="anonymous"></script>


Content Security Policy (CSP) – набор политик безопасности. Это указание браузеру, из каких источников загружать ресурсы (скрипты, шрифты и тд) и запрет на выполнение скриптов (unsafe-inline). CSP указывается в виде http-заголовка или мета-тега и состоит из различных директив, управляющих разрешениями для соответствующих ресурсов / функций браузера. Функции дополнялись в каждой версии, сейчас актуальной является 3. Пример политики CSP:

Content-Security-Policy: default-src 'self'; script-src 'self'; script-src-elem 'self'; style-src 'none'; img-src 'none'; connect-src 'self'; font-src 'none'; object-src 'none'; media-src 'none'; frame-src 'none'; child-src 'none'; form-action 'none'; worker-src 'none'; manifest-src 'none'; navigate-to 'none';


Например, директива connect-src ограничивает, с какими доменами можно устанавливать соединения. Это предотвращает утечку данных через расширения, которые пытаются получить доступ к данным.
Коротко о разнице:

SRI
- Используется для проверки целостности конкретных ресурсов.
- Работает на уровне отдельных ресурсов. Для каждого внешнего файла указывается хэш-сумма, которая проверяется браузером перед загрузкой.
- Применяется только к внешним ресурсам, загружаемым через теги <script> и <link>.
- Требует указания конкретной хэш-суммы для каждого ресурса, что делает его менее гибким при изменении содержимого файлов.

CSP
- Контролирует источники, откуда могут загружаться ресурсы и ограничивает тип контента для выполнения.
- Определяет общие правила для всех ресурсов страницы. Политики применяются ко всем ресурсам определенного типа (скрипты, стили и тд).
- Может применяться ко всему контенту страницы, включая внутренние и внешние ресурсы.
- Позволяет гибко настраивать политику безопасности, например, разрешать загрузку ресурсов с определенных доменов или запрещать определенные типы контента.

Оба инструмента эффективно дополняют друг друга, улучшая безопасность приложения. Механизмы снижают часть рисков и не являются достаточными. Например, CSP является дополнительным способом защиты от XSS, что было сказано в 2 версии спеки. Важно применять комплексный подход к защите и регулярно проводить аудит безопасности приложений.

Подписывайся / Чат
👍5
Немного слов о 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