JS F/k
6 subscribers
7 photos
42 links
HTML/TS/Vue — с примерами, по делу, без воды

https://js-f-k.netlify.app

#html #vue #typescript #npm
Download Telegram
Telegram Mini Apps: быстрый старт

Создавать мини-приложения для Telegram проще, чем кажется.

Всё, что нужно:
1. Зарегистрировать бота через @BotFather;
2. Указать ссылку на ваш сайт.

После этого сайт откроется прямо внутри Telegram — без сложной логики или интеграций. Фактически это тот же веб-сайт, только с запуском в мессенджере.

Хотите довести всё до идеала? Оптимизируйте страницу под размеры окна Telegram, сделайте отдельный быстрый лендинг или добавьте поддержку специфичных API. Подробный разбор с примерами таких улучшений есть в статье на Хабре: Telegram Mini App. Как создать Web App с нуля.

Главное — начать с простого, а детали можно освоить позже.

#service
Запуск TypeScript напрямую в Node.js

Хорошие новости: в новых версиях Node.js можно запускать .ts-файлы напрямую — без ts-node, tsx или ручной сборки.

v22.6.0: Появилась базовая поддержка type-stripping
v22.7.0: Добавлен флаг --experimental-transform-types
v23.6.0: Удаление аннотации типов включено по умолчанию
v24.3.0: Функция больше не считается экспериментальной

Подробнее о нативной поддержке TypeScript в Node.js — в официальной документации.

Что изменилось
- Node.js сам удаляет аннотации типов (type stripping), оставляя чистый JavaScript.
- Флаг --experimental-strip-types теперь не обязателен — он активен по умолчанию. При необходимости его можно отключить с помощью --no-experimental-strip-types.
- Если используются конструкции, требующие транспиляции (enum, namespace), потребуется флаг --experimental-transform-types.

Пример запуска
node --experimental-transform-types index.ts


Как писать совместимый код
В TypeScript 5.8 появился новый флаг erasableSyntaxOnly. Он запрещает конструкции, которые Node.js не сможет вырезать. Добавив этот параметр в tsconfig.json, редактор предупредит вас о неподдерживаемом коде.

Кому это пригодится?
Крупные проекты на TypeScript, которые активно используют namespace, enum и прочие трансформируемые конструкции, всё равно останутся на привычных инструментах вроде ts-node, tsx или полноценной сборки через tsc — и это нормально. Но для маленьких утилит, тестовых скриптов и инструментов возможность просто запустить node script.ts — отличный способ сэкономить время и не настраивать дополнительное окружение.

#build #typescript
Модульность и видимость экспортов

Разделение кода на мелкие модули — хорошая практика, но она сталкивается с тривиальной проблемой инкапсуляции: экспортированные из внутренних файлов сущности становятся видны по всему проекту. Если в нескольких подмодулях есть функция или переменная с одинаковым именем, IDE при автодополнении будет предлагать импорты из всех этих файлов.

Ни у платформы, ни у языкового стандарта пока нет простого механизма видимости по модулю — то есть способа пометить экспорт как доступный только внутри границ модуля/папки. На площадке обсуждения стандартов EcmaScript (Ecma Technical Committee 39) есть тред, где обсуждается идея директивы вроде 'use internal' или модификатора internal, которые ограничивали бы область видимости экспортов, но это остаётся лишь предложением.

Иные варианты существуют, но они компромиссны: уникальные имена, явное указание namespace, отказ от реэкспорта конфликтующих сущностей через barrel export, linter-правила, настройка IDE для предпочтения локальных импортов. Все эти подходы имеют свои минусы и не дают системного, стандартного контроля видимости экспортов.

Решения на уровне стандарта и экосистемы были бы желательны, но если у вас есть идеи по реализации — предлагайте в обсуждении или непосредственно в треде на es.discourse.group.

#build #unresolved
Forwarded from Веб-стандарты (Vadim Makeev)
Baseline в Browserlist. Свежий релиз Browserlist 4.26.0 теперь позволяет настроить браузерную поддержку в терминах Baseline, например "baseline widely available", "baseline newly available", а также более консервативый "baseline 2024" и раньше. #baseline #tools

https://browsersl.ist/#:~:text=select%20browser%20by%20baseline
Forwarded from mefody.dev
Что мы можем делать при помощи corner-shape

Помню, как сильно радовался массовому внедрению в браузеры свойства border-radius. Не нужно больше рисовать скруглённые уголки при помощи таблиц, кайф!

Но в дизайнах всё ещё бывают не только выпуклые круглые уголки. На данный момент без хаков можно играться с овальными формами границ. Ну или разбираться с border-image, который не самый developer friendly, на мой взгляд. Хотя в большинстве случаев этого всё-таки хватает.

Дэниэл Шварц показывает, как мы сможем визуально создавать всевозможные формы блоков с помощью нового свойства corner-shape, которое пока что работает только в Chrome:
- впуклые уголки (инвертированный круг);
- скошенные уголки;
- вырезанные уголки;
- сквирклы (красивые более естественные скругления).

С демками.

https://css-tricks.com/what-can-we-actually-do-with-corner-shape/
Типизация as const

В TypeScript as const позволяет фиксировать значения литералов и делать их максимально конкретными: строки не расширяются до string, числа — до number, а свойства объектов и массивы становятся readonly. Это удобно, когда нужно работать с неизменяемыми объектами или использовать их как "enum-подобные" конструкции. Документация: const assertions

Посмотрим, как это работает на практике и какие подводные камни возникают при использовании обычной типизации и as const.

Прямое указание типа
type Fruit = { name: string };

const Apple: Fruit = { name: "Apple" }; // создаём объект Apple и указываем, что он имеет тип Fruit
Apple.name = "Orange"; // ⚠️ нет ошибки


Свойство остаётся изменяемым. Видно, что обычное указание типа не защищает от изменений.

Использование as const
const Apple = { nme: "Apple" } as const; // объект неизменяемый
function isFruit(payload: unknown): payload is Fruit { return payload && "name" in payload; } // простейший type-guard для наглядности
isFruit(Apple); // ⚠️ false


В названии поля допущена ошибка (nme вместо name), поэтому проверка не сработала. Это показывает, что as const фиксирует значения, но не гарантирует соответствие интерфейсу — легко допустить опечатку или пропустить обязательное поле.

Комбинация as const и интерфейса

Кажется логичным совместить as const с интерфейсом:
const Apple: Fruit = { name: "Apple" } as const;
Apple.name = "Orange"; // ⚠️ нет ошибки


На практике as const "теряется": тип сужается до { name: string }, и свойство снова становится изменяемым.

Readonly
const Apple: Readonly<Fruit> = { name: "Apple" };
Apple.name = "Orange"; // ошибка компиляции


Такой способ защитит от изменения свойств, а переданный тип Fruit не даст ошибиться в названиях полей. Но есть нюанс: IDE покажет тип Apple как { name: string }, а не конкретное значение { name: "Apple" }. Будет потерян "конкретный тип", ради которого обычно и используется as const.

ReadonlyDeep

Если вам достаточно Readonly, не забывайте, что он работает только на верхнем уровне объекта: вложенные объекты и массивы останутся изменяемыми. В таких случаях стоит использовать утилиту ReadonlyDeep из type-fest. Она рекурсивно обходит все уровни и делает все свойства неизменяемыми.

Решение

Чтобы одновременно зафиксировать значения и проверить правильность структуры, используется оператор satisfies. Он проверяет, что выражение совместимо с указанным типом, при этом сохраняя исходный (более конкретный) тип для вывода. Документация: satisfies operator

const Apple = { name: "Apple" } as const satisfies Fruit;
Apple.name = "Orange"; // ошибка компиляции


При использовании конструкции as const satisfies %type% TypeScript корректно проверяет правильность полей в объекте, as const сохраняет неизменность значений, а попытка присвоить новое значение свойству ловится на этапе компиляции.

Итог

as const satisfies — простой способ объединить две цели: сохранить значения объекта неизменными и убедиться, что его структура соответствует интерфейсу. Особенно полезно для крупных объектов, например конфигураций, где легко допустить опечатку или ошибку в типах.

#typescript
Forwarded from mefody.dev
Динамический тултип

Темани Афиф делится коротким сниппетом, который позволяет собрать тултип на чистом CSS. Тултип пытается вместиться во вьюпорт любым легальным способом. И следует за якорем.

То, для чего мы сейчас используем JS-библиотеки на 200 килобайт, можно будет заменить на пару десятков строк CSS благодаря Anchor Positioning.

(Не забывайте проверять CanIUse)

https://css-tip.com/tooltip-anchor/
Сводка по переносу и обрезанию текста

Вёрстка длинных слов, URL и блоков кода часто ломает дизайн, если не использовать правильные свойства. В статье собраны ключевые приёмы: overflow-wrap, word-break, white-space, text-overflow и text-wrap. Показано, как контролировать перенос, сохранять пробелы и добавлять многоточие, чтобы текст оставался аккуратным на любых экранах.

https://js-f-k.netlify.app/articles/line-wrap

#css
Forwarded from Веб-стандарты (Vadim Makeev)
Рейтинг браузеров для PWA. Дэшборд Чарльза Уилтгена для сравнения возможностей веб-приложений в популярных мобильных браузерах (в планах и десктоп) на основе данных Can I Use и MDN: установка и манифест, уведомления, фоновые задачи, доступ к устройству, медиа и другие категории. #pwa #browsers

https://pwascore.com/
Forwarded from Vueist
SFC и раздутые компоненты

какое-то время в нескольких сообществах бурно обсуждаются плюсы и минусы подходы к SFC в целом. Описание всех плюсов и минусов оставлю на другой раз. Сейчас же сосредоточимся на конкретной претензии: SFC ведет к раздутым компонентам. Так ли это? А давайте разберемся с этим на примере работы в вакууме.

1. У вас есть компонент и внутри него есть template + style + script
2. В какой-то момент времени вы ловите себя на мысли "компонент стал большим, по нему неудобно навигироваться и работать с ним"
3. Вам нужно что-то предпринять

И тут у вас 2 выбора, но вначале разберем первый:
Взять компонент и посмотреть на него еще раз:
- Вынести переиспользуемую логику в композаблы
- Разбить шаблон на более базовые компоненты
- Даже банально вынести обычные утилиты из компонента

Итого получаем обратно более лаконичный компонент, он не раздут. Стало больше переиспользуемых частей. Это и есть pit of succes.
- Делать хорошо легко: маленькие компоненты легко и приятно поддерживать в SFC стиле
- Делать вербозные и раздутые компоненты неудобно, навигация усложняется и вы чувствуете как много времени уходит на что-то не то
- Есть мотивация перейти из плохого состояния в хорошее: у вас естественным образом возникает желание разбить компонент

Однако иногда система дает сбой и кому-то кажется, что решение проблемы это "а давайте разобьем компонент и вынесем из него css/html/js" не важно что. Как только вы поставили самоцелью сделать не функциональное разбиение, а типовое, то вы сразу
1) Ломаете то как работает изначальная идея: вам должно неприятно работать с раздутыми компонентами
2) Ломаете привычный флоу работы со Vue
3) Теряете плюсы которые дает SFC
И ради чего? Ради того, чтобы лечить раковую опухоль(использование практики раздутых компонентов) сбивая температуру(просто разбивая файл, а не функционал)

Надеюсь, что мораль ясна. А вам стало понятна еще одна причина, почему SFC — это хорошо
Почему не стоит проверять email сложными регулярными выражениями

Если у вас появилась задача "проверить полное соответствие введённого email стандарту RFC", то скорее всего вы не понимаете реальной цели формы, которую даёте на заполнение пользователю. Единственная правильная цель – убедиться, что с введённым адресом можно связаться с пользователем.

Написание сложных regex, вроде:
(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\ x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])

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

Простая проверка
Если нужно просто убедиться, что пользователь не ошибся полем, достаточно проверить наличие символа @.

Если нужен более строгий подход: .+@.+\..+, это проверит:
- наличие хотя бы одного символа до @
- наличие домена после @
- наличие точки и домена верхнего уровня

Даже эта проверка чаще всего избыточна: главная задача — чтобы адрес был действующим.

Почему полноценная проверка избыточна
RFC 5322 описывает email как довольно сложную конструкцию:
- в локальной части до @ допустимы специальные символы
- допускаются комментарии в скобках, включая вложенные
- сервер обрабатывает локальную часть по своим правилам, и нестандартные адреса могут быть валидными

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

Единственный надёжный способ проверить, что email рабочий, — это отправить письмо с подтверждением. Только так вы можете убедиться, что адрес действительно существует и пользователь реально может получить на него письмо.

Базовые правила проверки
Для упрощённого взаимодействия с пользователем достаточно проверить:
- поле не пустое
- поле содержит символ @
- наличие защиты от SQL-инъекций или других очевидных злоупотреблений

Итог
- Сложные regex для email почти всегда избыточны
- Базовой проверки достаточно для большинства задач
- Основной инструмент проверки — подтверждающее письмо

#html
Forwarded from Веб-стандарты (Vadim Makeev)
Простые поля для одноразовых кодов. Тайлер Стика показывает, как создать полностью рабочее поле для одноразового пароля (OTP) с помощью одного HTML-элемента — без JavaScript, CSS-хаков и сторонних библиотек. Достаточно атрибутов inputmode="numeric", autocomplete="one-time-code" и pattern="\d{6}", чтобы обеспечить автозаполнение, валидацию и доступность. Всё остальное можно добавить как прогрессивное улучшение. #html #a11y

https://cloudfour.com/thinks/simple-one-time-passcode-inputs/
👍1
Forwarded from mefody.dev
Переезд с Chalk на нативный styleText

Есть такая утилита Chalk, которую даже если вы осознанно в проект на Node.js не подключали, есть высокая вероятность, что подключали неосознанно. У неё какое-то неприличное девятизначное число скачиваний в неделю. И нужна она, чтобы в терминале красиво выводить текст: с фоновым цветом, разноцветно, жирненько или курсивом и так далее.

В Node.js v22.13.0 стабильной стала нативная утилита node:util.styleText, которая может почти всё то же самое, но с некоторыми ограничениями. Для нас, разработчиков, это приятное удаление лишней зависимости и более быстрое логирование.

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


npx codemod @nodejs/chalk-to-util-styletext


https://nodejs.org/en/blog/migrations/chalk-to-styletext
👍1
Forwarded from Веб-стандарты (Vadim Makeev)
Явное управление ресурсами в JavaScript. Мэтт Смит объясняет using и await using, а также Symbol.dispose и Symbol.asyncDispose, чтобы очистка всегда выполнялась при выходе из области видимости и в обратном порядке для нескольких ресурсов. Для большей гибкости есть DisposableStack и AsyncDisposableStack. #js #ecmasript

https://allthingssmitty.com/2026/02/02/explicit-resource-management-in-javascript/
Автоматизация релизов на GitHub

Если вы поддерживаете несколько проектов или библиотек на GitHub и устали делать релизы вручную, шаблон Auto Release Template поможет с автоматизацией. Он генерирует changelog, создаёт коммит с новой версией, добавляет тег и публикует GitHub Release. При этом ничего не опубликуется без вашего подтверждения — всегда есть возможность проверить релиз перед публикацией. Одно из значимых отличий — в GitHub Release сразу видны все изменения, без лишней ссылки на полный changelog.

Принцип работы
1. Вносите правки и называйте коммиты по Conventional Commits.
2. Запустите npm run release — обновится версия, сгенерируется CHANGELOG.md, создастся коммит и тег.
3. Вызовите git push --follow-tags.
4. GitHub Action сработает на новый тег и создаст GitHub Release с автоматически сгенерированным changelog.

Настройка и кастомизация
Вы можете изменить формат коммитов, префикс тегов и определить типы коммитов, которые попадут в changelog. Дополнительно вы можете настроить:
- автопубликацию npm пакета в registry npmjs или GitHub Packages;
- использование с pnpm;
- создание draft релиза;
- создание provenance statement;
- подключение хуков и добавление сгенерированных файлов в билд.

Подробные примеры для продвинутых сценариев есть в вики.

Итог
Использование Auto Release Template сокращает время на создание релизов, позволяет остановиться или откатиться на любом шаге и обеспечивает аккуратный changelog прямо в GitHub релизе. Дополнительно, с правильной настройкой GitHub Actions, это даст возможность публиковать релизы даже в приватных и командных репозиториях.

#ci #git #github #npm
Forwarded from mefody.dev
Гайд по Anchor Positioning

Anchor Positioning — это декларативный способ описать визуальную привязку одного элемента к другому на странице. Тулптипы, подсказки, сноски, выносные элементы — всё это можно реализовать относительно легко при помощи Anchor Positioning API.

Рома Ахмадуллин в Доке написал подробную статью, как работать с этим однозначно полезным API. Много интерактивных демок.

https://doka.guide/css/anchor-positioning-guide/
👍1
Обрезание текста по центру

В статье по переносу и обрезанию текста был показан часто используемый пример с text-overflow: ellipsis, где не влезающий в контейнер текст обрезается в конце. Но есть сценарии, когда требуется отобразить конец строки, а середину скрыть: UUID и хэши, email-адреса, пути к файлам, blockchain-адреса, токены и ключи.

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

Разбираем простой подход, без зависимостей и сложных вычислений ширины текста

https://js-f-k.netlify.app/articles/middle-ellipsis

#css #html
Forwarded from Vueist
Мне прислали вопрос по моему докладу:
почему нежелательно использовать классы вместо компосаблов.

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

Так как композаблы сами в себе альтернатива ООП заточенная конкретно под нужды Vue. Они уже используют фичи соответствующие потребностям и отсекают вещи которые не особо нужны.

Выше уже было мое сравнение композаблов и ООП, потом в отдельных чатах эта тема прорабтывалась куда подробнее. Но тут я сосредоточусь на минусах классов как замены композаблов

1) Классы - не vue way. Ни в одном гайде не будет такого использования. Вы увеличите время онбоардинга, а разработчикам придется куда сложнее с точки зрения приспосабливаемости к проекту, Библиотеки также не адаптированы под данный подход. В одном из случаев вам придется писать огромную портянку с оберткой композаблов в классы, в другом у вас будет адская смесь из классов и композаблов. Выдерживать единый стиль в таких проектах кратно сложнее.

2) Нет четко выработанных практик о том как БЕЗОПАСНО использовать смесь Vue и классов. Высока вероятность получения хрупкого кода, потери реактивности и лапши, При этом опять же у вас не будет гайдов, как правильно это использовать в том или ином случае. Реактивность Vue не дружит полноценно с классами. Например private property несоввместимы с proxy, вам придется полагаться только на TS зоны видимости, но и с ними будут свои нюансы

3)ООП дает избыточные инструменты которые будут только мешать при использовании Vue, они хуже связываются с его жизненным циклом. Наследование, instanceof и тп просто бесполезны. А вот классическую деструктуризацию использовать сложнее

4) Вы не получите никаких бенефитов от данного подхода. Все что дает ООП и реально нужно, то возможно использовать с композаблами и так.

Так стоит ли это того? Классы часто берут по привычке, либо если почувствовали в себе труъ-инженеров (а это буквально самое страшное что может случиться с проектом, самые запущенные случаи которые видел, когда кто-то посчитал себя истинным инженером и нагородил такой лапши, что проще проект выкинуть и переписать заново, чем править его логику)

Почему же это использовали со Vue2?
- А потому что других вариантов адекватных не было. Как раз из-за отсутсвия композаблов выносить логику из компонентов для переиспользования было прям сильно сложнее, а миксины были еще хуже как решение. Вот собственно и все

Когда классы+Vue ок? Когда вы используете сторонние специализированные инструменты которые уже заточены под классовое ооп. Например, если вы подключили Mobx (хотя особого смысла я в этом тоже не вижу)