Defront — про фронтенд-разработку и не только – Telegram
Defront — про фронтенд-разработку и не только
13.5K subscribers
21 photos
1.09K links
Ламповый канал про фронтенд и не только. Всё самое полезное для опытных web-разработчиков

Обсуждение постов @defrontchat

Также советую канал @webnya
Download Telegram
Вчера на сайте web.dev Фил Волтон из Google опубликовал статью, посвящённую Largest Contentful Paint, — новому API, с помощью которого можно получить наиболее точное время появления основного содержимого сайта.

Необходимость в новом API возникла из-за того, что существующее событие DOMContentLoaded не всегда соответствует появлению содержимому, которое можно считать полезным. First Paint и First Contentful Paint тоже не очень хорошие кандидаты для получения времени, так как они отражают начало рендеринга. Метрики First Meaningful Paint и Speed Index, которые рекомендовались ранее, часто некорректно говорят про время отображения основного контента.

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

Для определения этого события предназначено API Largest Contentful Paint (LCP). Так как при загрузке страницы контент может меняться, браузер отправляет PerformanceEntry c типом largest-contentful-paint при каждом появлении нового большого элемента. Отправка метрики прекращается, после того как пользователь начинает взаимодействовать со страницей. Время самого последнего отправленного события является нужным значением.

Largest Contentful Paint доступен в Chrome 77. В этой версии также стал доступен Element Timing API, на базе которого построен LCP. С помощью него можно узнать время появления конкретных элементов на странице.

#web #performance #rendering #chrome

https://web.dev/largest-contentful-paint
Аксель Раушмайер в прошлом месяце написал неплохую статью о том, как работают глобальные переменные в JS — "How do JavaScript’s global variables really work?"

Перед объяснением нюансов работы с глобальными переменными в статье рассказывается, что такое область видимости (scope) и как она определяется на уровне спецификации. В спеке области видимости "реализуются" с помощью lexical environments, которые состоят из environment record (нечто похожее на словарь с ключами и значениями) и ссылки на внешний scope. Таким образом дерево вложенных друг в друга областей видимости представляется деревом связанных между собой lexical environments.

На самом верхнем уровне этого дерева находится "global environment", состоящий из двух компонент: "object environment record", который поддерживает связь с свойствами глобального объекта ( window / self в браузере и global в node.js), и "declarative environment record", который создаётся с помощью const, let, class. Эти части существуют независимо, что даёт возможность создавать биндинги с одинаковыми ключами в разных записях. При обращении к таким биндингам из кода будет побеждать declarative environment record. Если очень упростить, то можно сказать, что начиная со спецификации ES2015 в JavaScript появились два разных вида глобальных переменных.

Рекомендую почитать статью и посмотреть на примеры того, как это всё работает.

#specification #js #es2015

https://2ality.com/2019/07/global-scope.html
Хочу ещё разок написать про блог Акселя. Совсем недавно он опубликовал там статью про globalThis — "ES proposal: globalThis".

В прошлом посте рассказывалось о том, что в JS сейчас есть два вида глобальных переменных, один из которых определяется с помощью global object. В браузерах исторически для доступа к глобальному объекту использовался window. В веб воркерах для доступа к global object используют self, потому что window там недоступен. В node.js в свою очередь вместо window используется global. Для того чтобы унифицировать доступ к глобальному объекту в разных окружениях, в стандарт языка планируется добавить globalThis.

Предполагается, что новый идентификатор будет полезен при написании полифиллов и для определения наличия фич в JS-окружении. С помощью него также можно создавать "классические" глобальные переменные, но это не приветствуется, так как само по себе наличие global object считается ошибкой дизайна языка, от которого нельзя избавиться из-за обратной совместимости.

На данный момент globalThis находится на третьей стадии добавления в стандарт. Его поддержка уже есть в Firefox, Chrome и Safari.

#js #proposal

https://2ality.com/2019/08/global-this.html
Нашёл интересную статью Омара Шехата про работу с бинарными данными в браузере — "Binary data in the browser: Untangling an encoding mess with JavaScript Typed Arrays".

Омар кодил приложение для визуального создания полиритмов с возможностью загрузки полученной мелодии в виде midi-файла без использования бэкенда. Для генерации midi он использовал библиотеку jsmidgen, которая без проблем работала в node.js, но в браузере результат получался битым.

Сначала было предположение, что по каким-то причинам некорректно работал jsmidgen, но дебаг это не подтвердил. Потом автор предположил, что проблема возникает при передаче строки в Blob. Он принудительно перевёл каждый символ результата в uint8 с помощью типизированного массива, и это решило проблему. Далее в статье идёт детальный разбор того, почему первый подход к решению задачи был неудачным. Если говорить кратко, то проблема заключалась в том, что при передаче в Blob строка кодируется в UTF-8. В UTF-8 один символ может быть закодирован с помощью одного или двух байт.

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

#js #encoding #binary #midi

https://blog.logrocket.com/binary-data-in-the-browser-untangling-an-encoding-mess-with-javanoscript-typed-arrays-119673c0f1fe/
В Vue 3.0 запланировано добавление нового function-based API, с помощью которого можно переиспользовать логику между компонентами по такому же принципу, как это делается с помощью React Hooks. Тарас Батенков написал статью про то, как можно использовать новое API во Vue 2 — "Vue.js 3: Future-Oriented Programming".

В начале статьи на примере страницы публикаций и залипающей шапки описываются проблемы, которые существуют при старом подходе переиспользования логики с помощью миксинов и HOC'ов: коллизии имён, неявность источника, производительность. Потом этот же самый пример перерабатывается с использованием нового API.

Разработчики Vue элегантно поддержали новое API во второй версии. Для его добавления в существующий проект необходимо установить плагин npm install vue-function-api и подключить с помощью Vue.use():
import Vue from 'vue'
import { plugin } from 'vue-function-api'

Vue.use(plugin)


Статью стоит прочитать, если в вашем проекте используется Vue и хочется попробовать новое API.

#js #vue #hooks

https://blog.bitsrc.io/vue-js-3-future-oriented-programming-54dee797988b?gi=19a1dde5a8f4
Неделю назад в Chrome 76 была добавлена поддержка ленивой загрузки. Энди Поттс из BBC поделился опытом использования новой фичи в статье "Native lazy loading has arrived!"

Ленивая загрузка позволяет загружать изображения и содержимое iframe только тогда, когда они попадают во viewport браузера. Раньше подобный трюк можно было провернуть, используя JavaScript для отслеживания позиции элементов на странице. При ленивой нативной загрузке процесс проверки осуществляется вне главного потока JS. Это более производительно и не приводит к потере кадров при прокрутке страницы.

Энди обкатал ленивую загрузку на небольшом внутреннем продукте BBC (3000 пользователей в день). На странице этого сайта выполняется запрос, который может привести к загрузке 100 изображений. На быстром соединении время загрузки одного изображения снизилось до 50% (с одной секунды до 500 миллисекунд). Также снизилась нагрузка на сервер — для некоторых сессий количество запросов снизилось на треть.

Ленивая загрузка добавляется с помощью атрибута loading="lazy":
<img src="image.png" loading="lazy" width="400" height="400" />


Фича очень полезная. Когда её поддержка появится в других браузерах, будет совсем круто.

P.S. Я уже писал про ленивую загрузку ранее; другой пост можно найти по тегу #lazy.

#lazy #chrome #performance

https://medium.com/bbc-design-engineering/native-lazy-loading-has-arrived-c37a165d70a5

Views before: 567
Я никогда не задумывался о том, как работает двухфакторная аутентификация. Когда мы сканируем QR-код в 2FA приложении и видим одноразовый пароль или получаем его в смс, под капотом работают алгоритмы, описанные в RFC6238 и RFC4226. Александр Ховановский разобрался со всем этим и опубликовал на хабре статью про OTP (one time password) — "Генерируем одноразовые пароли для 2FA в JS с помощью Web Crypto API".

Существуют два вида одноразовых паролей: HMAC-based One Time Password (HTOP) и Time-based OTP (TOTP). HMAC расшифровывается как Hash-based Message Authentication Code. В нём используется счётчик, который должен синхронизироваться между клиентом и сервером. В Time-based OTP счётчиком выступает интервал времени. Он получается делением Unix-времени на окно валидности пароля (обычно это знакомые нам 30 секунд). Затем происходит процесс преобразования исходных данных в одноразовый пароль с участием алгоритма SHA-1 (использовался Web Crypto API).

Статья хорошая. С большим количеством примеров и кода. Хочу перечитать её ещё разок и написать свою реализацию просто ради интереса.

https://habr.com/ru/post/462945/

#js #cryptography #security
Два дня назад Матиас Байненс в блоге v8 написал статью про пропозал "Subsume JSON a.k.a. JSON ⊂ ECMAScript".

"Subsume JSON" делает JSON полноценным подмножеством JavaScript. Раньше строковые литералы не могли содержать незаэскейпленные символы U+2028 LINE SEPARATOR и U+2029 PARAGRAPH SEPARATOR. Их присутствие приводило к SyntaxError. Это проблема, потому что JSON может их содержать. Чтобы в коде ничего не взорвалось, надо было писать дополнительную пост-обработку вставляемого в скрипт результата работы JSON.stringify(). Новая фича избавила разработчиков от этого неудобства.

Но от пост-обработки нельзя отказаться в том случае, когда происходит сериализация пользовательских данных, которые вставляются на страницу. В статье есть пример XSS-атаки, в которой используется символ U+2028.

Subsume JSON уже попал в последнюю версию стандарта — ES2019. Поддержка новой фичи есть во всех актуальных версиях браузеров.

#js #unicode #security #es2019

https://v8.dev/features/subsume-json
Партрик Вентузело — независимый эксперт в области ИБ — опубликовал статью про анализ WebAssembly модуля Google Keep — "Analysis of Google Keep WebAssembly module​".

Сначала Патрик пытался выяснить, за что отвечает загружаемый WebAssembly модуль. Для этого он извлёк информацию о сборке. В ней содержались сведения о wasm-тулчейне (emnoscripten-wasm), использованной системе сборки (Bazel), имя сервера и путь до результата сборки. Название "sketchology", которое находилось в пути, дало подсказку о том, что модуль отвечает за создание векторных изображений в заметках Google Keep.

Далее в статье рассказывается, какую ещё информацию можно достать из модуля. Например, в секции данных модуля находились бинарные данные protobuf. Их можно проанализировать с помощью protobuf-inspector. В той же секции находились абсолютные пути скомпилированных файлов, сообщения об ошибках, имена функций и констант. С помощью этой информации можно восстановить дерево скомпилированного проекта. При большом количестве времени и упорстве возможно декомпилировать wasm-модуль в C-код.

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

#webassembly #security #re

https://webassembly-security.com/google-keep-webassembly-module-analysis/
Пару недель назад количество подписчиков Defront перевалило за тысячу. Хочу сказать вам спасибо, за то что читаете и пишете в личку, если видите какую-то неточность или опечатки. И хочу сказать спасибо всем каналам, которые меня поддерживают или из которых я черпаю информацию для канала:

@juliarderity — информация из первых рук про новинки в web-стандартах, рекапы встреч комитета TC39 и многое другое (Сергей Рубанов — создатель канала — участвует в разработке стандарта ECMAScript)
@oleg_log — отличный канал Олега Ковалёва, в котором он делится своим богатым опытом разработки. Пишет про Go, DevOps, бэкенды и всё что с ними связано, не избегает тем про JavaScript
@webstandards_ru — один из самых известных телеграм-каналов, посвящённых web-разработке, который ведёт Вадим Макеев
@forwebdev — канал Андрея Романова, в котором публикуются ссылки на полезные статьи и инструменты, у автора есть личный блог в tg, на который я тоже подписан — @andrew_r_notes
@breakfastjs — подборки статей из мира фронтенд-разработки от Дмитрия Мананникова
@iamakulov_channel — заметки от Ивана Акулова про производительность в web'е и другая годнота
@smart_dev — канал с ссылками на интересные статьи, авторские переводы
@amorgunov — канал моего коллеги из Яндекса — Александра Моргунова, пишет про JS и жизнь
@ufostation — канал Сергея Ufocoder про фронтенд и фп
@jabanoscript — хороший телеграм-блог Виктора Турского
@we_use_js — канал, с хорошими ссылкам на статьи, новые инструменты и т.п.
@tproger_web — канал про web-разработку проекта tproger
Деструктуризация — удобное средство для доступа к свойствам объектов и элементам массивов, но оно не ограничивается только этими сценариями. Дмитрий Павлютин написал статью с описанием неочивидных подходов с использованием этой фичи — "5 Interesting Uses of JavaScript Destructuring".

1. С помощью деструктуризации можно обменивать значения переменных таким же образом, как это можно сделать в python: [a, b] = [b, a];.
2. Можно легко получить первый элемент массива с подстановкой дефолтного значения, если этого элемента нет: const [firstColor = 'white'] = colors;.
3. Комбинируя деструктуризацию с rest-оператором, можно отбросить первый элемент массива: const [, ...lastNumbers] = numbers;.
4. Деструктуризация работает для всех объектов, которые имплементируют протокол итерирования (строки, массивы, Map, Set). Например, таким образом можно получить первую букву в строке: const [firstChar] = 'cheese';.
5. Используя динамические свойства объектов, можно получить заранее неизвестное свойство объекта: const { [nameProp]: name = 'Unknown' } = obj;.

Я пересказал содержимое всей статьи, но всё равно в ней есть более развёрнутые примеры. Советую посмотреть.

https://dmitripavlutin.com/5-interesting-uses-javanoscript-destructuring/

#js #es2015 #list
После прочтения статьи "Responsible JavaScript" я рефлексировал на тему того, что было бы здорово иметь такой источник информации, в котором бы детально разбирались типы рендеринга и то как они влияют на метрики производительности web-приложений. Сегодня увидел твит от Эдди Османи, в котором он поделился ссылкой на статью, посвящённой этой теме — "Rendering on the Web".

В статье разбираются все виды рендеринга страниц: Server Rendering, SSR, SSR with Rehydration, CSR with Prerendering, Full CSR. Даётся оценка того, как они влияют на метрики приложения и даются советы, в каком случае лучше использовать тот или иной подход. Например, авторы статьи не рекомендуют использовать SSR с гидрированием, так как метрики производительности, собранные с реальных сайтов, использующих этот подход, говорят не в его пользу. Из статьи я впервые узнал про "Trisomorphic Rendering". Это такой подход, когда для рендеринга страниц используются сервис воркеры.

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

#performance #web #rendering

https://developers.google.com/web/updates/2019/02/rendering-on-the-web#top_of_page
Иногда заполнение и отправка web-формы превращается в проблему: например, непонятно, к какому полю относится лейбл или сообщение валидации говорит, что есть ошибка, но не говорит, где именно и т.п. Адам Силвер написал статью о том, чего лучше всего избегать при проектировании форм и чего стоит придерживаться — "Form design: from zero to hero all in one blog post".

Вот несколько интересных моментов. Следует избегать форм с многоколоночной раскладкой, так как более 10% пользователей, не могут заполнить такие формы правильно. В поля ввода, которые отвечают за ввод грамматически неправильных данных (например, email'ов), следует добавить атрибуты autocapitalize="none", autocorrect="off" и spellcheck="false", чтобы браузер автоматически не изменял вводимые данные. Используйте <select> только в самой безвыходной ситуации, потому что им неудобно пользоваться. Вместо него лучше всего использовать radio-кнопки или <select> с автодополнением для очень большого списка опций.

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

#ux #forms

https://adamsilver.io/articles/form-design-from-zero-to-hero-all-in-one-blog-post/
Вчера вышла новая версия Node.js 12.9.0.

В новом релизе V8 был обновлён до версии 7.6. С новой версией движка в Node.js появилась поддержка Promise.allSettled, улучшена поддержка BigInt, ускорена работа JSON.parse().

В модуле fs были добавлены fs.writev, fs.writevSync и filehandle.writev, с помощью которых можно записывать в файл массив buffer'ов. Этот API будет полезен при оптимизации записи файлов на диск.

В модуле crypto появилась новая опция oaepHash для асимметричного шифрования, с помощью которой можно указать хэш-функцию при использовании optimal asymmetric encryption padding (OAEP).

В модуле http были добавлены недостающие "streamlike" свойства к OutgoingMessage.prototype: writableObjectMode, writableLength и writableHighWaterMark. В модуле stream добавлены новые свойства readableEnded и writableEnded, которые показывают текущее состояние завершения чтения или записи стрима.

#release #nodejs

https://nodejs.org/en/blog/release/v12.9.0/
В бете Chrome 77 за экспериментальным флагом #native-file-system-api появилась поддержка Native File System API.

С помощью этого API можно создавать приложения, которые имеют прямой доступ на чтение и запись файлов, например, полноценный текстовый или графический редактор, IDE и т.п. Много внимания уделяется безопасности нового API. Оно будет доступно только на тех сайтах, которые работают по https. Открытие окна выбора файлов возможно только со стороны пользователя, то есть программно вызвать это окно нельзя. Тем не менее появление доступа к файловой системе открывает новые возможности для атак на данные пользователей.

Native File System API является частью проекта capabilities, цель которого сделать возможным разработку таких типов web-приложений, которые доступны только на нативных платформах. Интересно наблюдать, как браузер постепенно превращается в полноценную платформу для запуска серьёзных приложений.

#future #chrome #experimental

https://developers.google.com/web/updates/2019/08/native-file-system
Прочитал интересную историю переезда с Angular на Preact от Джорджа Фу — "Optimizing for the mobile web: Moving from Angular to Preact".

У ребят было приложение с 200 тысячими строк. Время загрузки страницы на мобильных устройствах занимало до 11 секунд. Время старта приложения в режиме разработки — 3 минуты.

Команда решила, что с этим надо что-то делать и для начала избавилась от больших библиотек: moment, lodash и core-js. После этого начался перевод листовых Angular-компонентов. Для интеропа с ангуляром был использован специальный компонент "angular-preact-bridge". Это позволило не останавливать разработку и переводить проект на Preact постепенно. В процессе переезда им очень помогал TypeScript. После всей работы (в статье не говорится о количестве затраченного времени, но у них был дедлайн в 4 месяца), размер приложения уменьшился в два раза, время загрузки снизилось до 3-4 секунд.

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

#jsframeworks #experience #migration

https://bytes.grubhub.com/optimizing-for-the-mobile-web-moving-from-angular-to-preact-f09ca61ea27c#8f83
Лин Кларк на Mozilla Hacks опубликовала большую статью, посвящённую новому пропозалу в WebAssembly — "WebAssembly Interface Types: Interoperate with All the Things!"

На данный момент WebAssembly без использования glue-кода может общаться с внешним миром только числами (значения, смещения, адреса). Пропозал "WebAssembly Interface Types" позволит работать со сложными типами напрямую (строки, объекты, структуры и т.п.) Это открывает двери таким возможностям как работа с Web API непосредственно из WebAssembly без привлечения JavaScript, общение wasm-модулей, скомпилированных из разных языков, между собой, использование одного и того же модуля без перекомпиляции в совершенно разных окружениях, например, Node.js, Python, WASI-рантаймах и т.п.

В статье очень детально разбирается, как это всё работает. От описания высокоуровневой проблемы до примеров реализации того, как будут представлены интерфейсные типы в коде wasm-модулей. Экспериментальная поддержка предложения есть в рантайме Wasmtime, Rust-тулчейне и wasm-bindgen.

Что сказать... очень крутая новость. Пойду ещё разок задоначу в Mozilla Foundation.

#webassembly #proposal

https://hacks.mozilla.org/2019/08/webassembly-interface-types/
Tproger вчера запостил (https://news.1rj.ru/str/tproger_web/193) awesome-список, посвящённый мобильной web-разработке, который я веду больше года. Там есть разные статьи, книги и инструменты, которые могут помочь в создании быстрого mobile-friendly сайта. Рекомендую посмотреть подборку всем web-разработчикам, так как пользователей интернета сейчас больше всего именно на мобильных платформах.

#mobile #list

https://github.com/myshov/awesome-mobile-web-development
Сегодня меня занесло в 2015-ый год. Прочитал статью Джека Арчибальда про старые баги браузеров с планированием микрозадач — "Tasks, microtasks, queues and schedules".

Если выполнить такой код:
console.log('noscript start');
setTimeout(() => console.log('setTimeout'), 0);
Promise.resolve().then(() => console.log('promise'));
console.log('noscript end');


то в консоль будет выведено: "noscript start", "noscript end", "promise", "setTimeout". Такой порядок объясняется тем, что очередь микрозадач (куда попадают выполнение коллбеков MutationObserver и коллбеки промисов) опустошается до выполнения следующей задачи, которая в данном случае создаётся с помощью setTimeout.

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

Проверил примеры — браузеры уже пофиксили описанные проблемы. Но всё равно рекомендую почитать статью, если она прошла мимо вас.

#async #history

https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
Филип Уолтон написал про свою идею использования нативных модулей в качестве выходного формата бандла — "Using Native JavaScript Modules in Production Today".

На данный момент самый популярный бандлер Webpack не поддерживает нативные модули в качестве выходного формата. Если вы посмотрите внутрь бандла, то увидите вместе с кодом модуля бойлерплейт-код для его инициализации. У менее популярного бандлера Rollup есть поддержка esm в качестве выходного формата. Использование нативных модулей даёт несколько преимуществ: выходной бандл получается меньше в объёме и нативные модули можно эффективно загружать с помощью хинта modulepreload (только в Chrome).

В статье подробно разбирается, как реализовать описанный подход на практике. Статью стоит почитать и взвесить все за и против использования описанного подхода в своём проекте.

#performance #rollup #esm

https://philipwalton.com/articles/using-native-javanoscript-modules-in-production-today/
Фараз Келини написал хорошую статью про BigInt — предложение добавления в стандарт JavaScript — "The Essential Guide To JavaScript’s Newest Data Type: BigInt".

BigInt — новый тип в языке. Его планируют добавить в стандарт из-за того, что размерности Number недостаточно, если необходимо работать с большими числами. Если Number выходит за пределы Number.MAX_SAFE_INTEGER и Number.MIN_SAFE_INTEGER, то число округляется, приводя к багам в программе. Например, 9007199254740992 === 9007199254740993 будет true.

BigInt-числа выглядят как обычные, но с суффиксом n в конце — 10000n. В арифметических выражениях BigInt и Number, нельзя смешивать между собой (будет TypeError ), так как возникает дихотомия в интерпретации результата. Если хочется использовать разные типы в одном выражении, то их надо привести явно к одному типу: 1000n + BigInt(1). При сравнении чисел BigInt и Number нельзя использовать строгое сравнение, так как это разные типы ( 10n === 10 // false ), но можно использовать нестрогое.

На данный момент пропозал BigInt находится на stage 3. Его поддержка есть в Chrome, Firefox и последней версии Edge. Создать полноценный полифилл для BigInt невозможно, поэтому в статье предлагается использовать библиотеку JSBI для поддержки старых версий браузеров.

В общем, рекомендую почитать статью. Скорее всего BigInt попадёт в следующую версию стандарта.

#js #proposal

https://www.smashingmagazine.com/2019/07/essential-guide-javanoscript-newest-data-type-bigint/