WebDev+ | Веб-разработка
8.3K subscribers
507 photos
242 videos
10 files
702 links
Присоединяйтесь к нашему каналу и погрузитесь в мир веб-разработки

Связь: @devmangx
Download Telegram
This media is not supported in your browser
VIEW IN TELEGRAM
Сделай свой веб-интерфейс по-настоящему динозавровым 🦖

Меняй сложный JS на пару строк CSS, чтобы собрать карусели и оживить анимации.

Уже доступно в Chrome, скоро подтянутся и другие браузеры → https://goo.gle/44L646B

@WebDev_Plus
Please open Telegram to view this post
VIEW IN TELEGRAM
2
Используй стандартное поле Node.js imports вместо алиасов TypeScript.

@WebDev_Plus
5🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
Настоящий TypeScript ещё ни разу по-настоящему не пробовали.

@WebDev_Plus
👍1
Это может стать настоящей революцией в веб-разработке!
Сейчас разрабатывают протокол проверки email-адресов (Email Verification Protocol).

Можно будет валидировать почту без отправки писем и без соцлогина.
Прямо из браузера и на 100% приватно.

Пока это только предложение, но выглядит очень интересно.

@WebDev_Plus
👍32
Просто небольшое напоминание: для описания ограниченного набора возможных состояний лучше использовать union type.
А не жонглировать кучей boolean-полей и потенциально невалидными состояниями.

@WebDev_Plus
🔥5
Chainable async API

Меня всегда интересовало, как DrizzleORM
удаётся чейнить async-функции вроде await delete() и await delete().where().

Они реализовали свой кастомный Promise, от которого наследуются все операции с БД, например PgDelete для delete в Postgres.

Чейнящиеся методы типа delete() и where() просто изменяют внутреннее состояние и всегда возвращают this (тот же самый инстанс промиса).

Поэтому, когда ты делаешь await delete(), под капотом вызывается then() этого промиса, который запускает this.execute().

Реальный запрос к базе выполняется именно в методе execute, который переопределяется в каждом подклассе.

Я считаю, что это очень крутой дизайн API, а сама идея имплементить Promise — просто отличная.

Ссылка на QueryPromise
Ссылка на PgDelete

@WebDev_Plus
Обеспечьте исчерпывающую проверку на этапе компиляции с помощью утилитарного типа Record в TypeScript

@WebDev_Plus
3
This media is not supported in your browser
VIEW IN TELEGRAM
Изучаю SwiftUI после долгой работы с React. Первое, что реально бросается в глаза — .task.

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

Удобно, например, чтобы поднять подписку через convex и сохранить данные в состоянии. Чисто и приятно 👍

Самое близкое сравнение — это useQuery, но тут не нужно городить подкомпоненты, чтобы ограничивать область ререндера.

Ещё интересно, во что это может вылиться, если везде рендерить по принципу render-as-you-fetch. Похоже, на масштабе всё же придётся активно передавать данные через пропсы?

@WebDev_Plus
Please open Telegram to view this post
VIEW IN TELEGRAM
1
This media is not supported in your browser
VIEW IN TELEGRAM
У <dialog> вместе с формами есть простой способ сделать кнопку Cancel без единой строчки JS. Помимо POST и GET, формы внутри <dialog> могут использовать метод DIALOG. В этом режиме кнопка submit просто закрывает диалог, не отправляя данные на бэкенд.

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

Когда форма внутри <dialog> отправляется методом dialog, само диалоговое окно закрывается, состояние контролов формы сохраняется, но ничего не уходит на сервер. При этом returnValue принимает значение той кнопки, по которой пользователь кликнул.

Чистый и удобный способ обработать отмену или выбор без полноценного сабмита.

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

Подробнее на MDN: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dialog

@WebDev_Plus
1👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Нужны эффектные анимации для React Native?

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

Отлично подходит, если хочется прокачать анимацию в приложении, не собирая всё вручную.

Исходники: github.com/enzomanuelmangano/demos

@WebDev_Plus
👍1
По мне, это самый удобный вариант монорепы без отдельного шага сборки:

• pnpm workspaces и установка через workspace:*
• внутренние пакеты, которые экспортируют *.ts файлы
• опционально: pnpm publishConfig, чтобы при публикации подменять экспорты на *.js

{
"name": "@internal/foo",
"version": "1.0.0",
// Экспорт исходников TypeScript
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": "./src/index.ts"
},
// Экспорт собранного кода при публикации
"publishConfig": {
"access": "public",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": "./dist/index.js"
}
},
"dependencies": {
// Установка других внутренних пакетов из workspace
"@internal/bar": "workspace:*"
}
}


@WebDev_Plus
4
React провернул трюк на миллиард долларов. Он превратил невозможную задачу O(n³) в O(n).

Сама задача такая. Ты обновляешь UI. У React есть две виртуальные DOM-деревья: одно отражает то, что сейчас на экране, второе то, что должно быть на экране. Нужно понять, что изменилось.

Классическое решение? Сравнить каждый узел дерева A с каждым узлом дерева B, чтобы найти оптимальное преобразование. Это алгоритм вычисления расстояния между деревьями. Его сложность O(n³).

Для 1000 элементов UI это миллиард сравнений. Приложение зависает на 10 секунд каждый раз, когда ты нажимаешь кнопку. Лента Facebook? Таймлайн Instagram? Нереально.

React посмотрел на эту классическую CS-задачу и решил: а что если нам не нужен идеальный результат? Что если достаточно «достаточно хорошего»?

Они сделали два жестких компромисса.

Компромисс 1. Разные типы компонентов? Даже не сравниваем их детей. Старое поддерево выкидываем целиком. Новое создаем целиком. Ноль анализа. Мгновенное O(1) решение. Иногда расточительно? Да. Быстро? Да.

Компромисс 2. Один и тот же тип? Сравниваем только узлы на одном уровне дерева. Не ищем более удачные соответствия где-то глубже. Какие-то оптимизации теряются? Конечно. Но сложность падает с O(n³) до O(n).

В итоге миллиард операций превращается в тысячу. 10 секунд превращаются в 2 миллисекунды. Невозможное становится тривиальным.

Поэтому ленты Instagram листаются плавно. Поэтому Facebook не зависает, когда ты ставишь лайк. Поэтому твое React-приложение с 10 000 компонентов ощущается мгновенным. Поэтому веб ощущается почти нативным.

React не решил невозможную задачу. Он просто сменил задачу.

Главный вывод: стремление к идеалу убивает скорость. А скорость — единственное, что действительно важно пользователю.

@WebDev_Plus
🔥6👍32🤡2🗿1
Покажите мне API мутаций лучше, чем вот это.

https://fate.technology/guide/actions

@WebDev_Plus
This media is not supported in your browser
VIEW IN TELEGRAM
Лучший дев-портфолио снова в строю!

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

Сайт сделан на Three.js и WebGPU, выглядит просто нереально круто:

http://bruno-simon.com

@WebDev_Plus
6
В последнем апдейте Vue Language Tools для vuejs директива v-for теперь ведёт себя с ключами типа number так же, как TypeScript и рантайм Vue.js: ключи автоматически считаются строками. Больше консистентности, меньше сюрпризов.

И это ещё не всё! Добавили поддержку Template Literal Types в v-for: если у ключа union из числовых литеральных типов, он автоматически "строкифицируется"
1 | 2 → "1" | "2"

@WebDev_Plus
2
This media is not supported in your browser
VIEW IN TELEGRAM
В Chrome DevTools MCP добавили улучшение, о котором просили многие 🦌

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

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

Теперь агенты могут получать доступ к активным сеансам отладки в пользовательском интерфейсе DevTools. Например, если вы обнаружите запрос с ошибкой на панели «Сеть» в Chrome DevTools, выберите запрос и попросите своего агента исследовать его. То же самое работает и с элементами, выбранными на панели «Элементы».

@WebDev_Plus
Please open Telegram to view this post
VIEW IN TELEGRAM
3
Наконец-то! Можно начинать прощаться с new Date() в JS.

Temporal API доехал до Google Chrome 144.

Это новый способ работать с датами и временем.

Там куча утилит и улучшений:

// 1) Разница между датами - без миллисекунд и без головняка
const start = Temporal.PlainDate.from('2026-01-10')
const end = Temporal.PlainDate.from('2026-01-30')

console.log(`Длительность: ${start.until(end).days} дней`)
// Длительность: 20


// 2) Создаём время без даты и таймзоны
const opensAt = Temporal.PlainTime.from('09:30')
console.log(`Открывается в ${opensAt.hour} часов и ${opensAt.minute} минут`)
// Открывается в 9 часов и 30 минут


// 3) Конвертим таймзоны без боли
const meeting = Temporal.ZonedDateTime.from(
'2026-03-15T18:00[Europe/Madrid]'
)

console.log('Мадрид:', meeting.toString())
console.log('Токио:', meeting.withTimeZone('Asia/Tokyo').toString())


// 4) Прибавляем время, не ломая даты
const release = Temporal.PlainDate.from('2026-02-01')
console.log('Следующий релиз:', release.add({ months: 1 }).toString())
// Следующий релиз: 2026-03-01


// 5) Instant - точка во времени (логи, события, метрики)
const now = Temporal.Now.instant()
console.log('Точный таймстамп:', now.toString())


@WebDev_Plus
This media is not supported in your browser
VIEW IN TELEGRAM
Большинство CSS-переходов плавные, но display переключается мгновенно. allow-discrete делает так, что элемент еще немного остается видимым, чтобы анимация выхода выглядела гладко, и только потом уходит в display: none.

Ключевое слово allow-discrete применяет тайминги transition к дискретным свойствам. Для exit-анимаций элемент остается видимым, проигрывает переход, а затем переключается в display: none уже после завершения transition.

Подробнее на MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/transition-behavior

Свойство overlay управляет тем, остается ли диалог в top layer во время перехода. Без него диалог сразу “провалится” назад, за другой контент.

MDN: https://developer.mozilla.org/en-US/docs/Glossary/Top_layer

CSS-сниппет:

dialog {
opacity: 1;
scale: 1;

transition:
opacity 0.2s ease-out,
scale 0.2s ease-out,
overlay 0.2s ease-out allow-discrete,
display 0.2s ease-out allow-discrete;

@starting-style {
opacity: 0;
scale: 0.95;
}
}



И:

dialog::backdrop {
background-color: rgb(0 0 0 / 0.5);
transition:
background-color 0.2s ease-out,
overlay 0.2s ease-out allow-discrete,
display 0.2s ease-out allow-discrete;

@starting-style {
background-color: rgb(0 0 0 / 0);
}
}


@WebDev_Plus
5