Заполночь в IT
СтатистикаFrontend (JavaScript, TypeScript, React.js) и общеайтишная тематика (качество кода, архитектура, лучшие практики). Автор канала: Гафаров Назим @zapolnoch
- Последний пост
- 23 авг. 2024 г.
- Последнее чтение
- 13 авг.
- Постов за неделю
- 0
- Всего постов
- 20
- Тип
- открытый
- Язык
- русский
- В каталоге с
- 13 авг.
- 1/24сутки в ленте
- —
- 1/48двое суток
- —
- 1/72трое суток
- —
Оценка по просмотрам недавних постов: пост набирает почти всё за первые сутки.
Посты
Запуск фронтенда локально должен быть максимально простым: npm install npm start Без установки Docker и Kubernetes. Без перенастройки браузера, установки сертификатов или правок hosts. Все API запросы проксируются через локальный порт, например, с помощью http-proxy-middleware. В нем можно автоматически удалять флаг secure с куков и перенаправлять запросы на HTTP. Если развертывание фронтенда на локальной машине разработчика занимает больше двух минут, это сигнал о серьёзных проблемах в вашем проекте.
Очень крутой proposal для упрощения обработки ошибок, замена try-catch. Как говорится, плоское лучше, чем вложенное: const [error, response] ?= await fetch("https://example.com")
без подписи
Дополнение к предыдущему посту: сборщики способны заранее такое посчитать. Вот как ESbuild и Terser из Webpack выполняют подобный код при сборке и минификации. В Parcel для этого вообще завезли специальный атрибут импорта, указывающий, что код должен выполняться во время сборки: import yearsToMilliseconds from "date-fns" with { type: "macro" } const maxAge = yearsToMilliseconds(1)
В коде нежелательно выполнять вычисления, которые можно посчитать заранее. Например, вместо того чтобы писать maxAge: 60 * 60 * 24 * 365, лучше использовать заранее вычисленное значение: 31_536_000 и добавить комментарий: // Вместо const maxAge = 60 * 60 * 24 * 365; // Лучше const maxAge = 31_536_000; // 1 year
Многие языки программирования используют стандарт IEEE 754 для представления чисел с плавающей запятой: a = 0.1 + 0.2 print(a) # 0.30000000000000004 Java и C#: double a = 0.1 + 0.2; Go: a := 0.1 + 0.2 Эти примеры демонстрируют, что проблема не уникальна для JavaScript. Поэтому если вы видите человека, который критикует JavaScript из-за особенностей IEEE 754, то понимаете, что перед вами стоит самый тупой человек на планете.
Почему не работает 1.toString()? Это происходит потому, что парсер ожидает увидеть либо еще цифры после первой точки (как в числе с плавающей запятой), либо вызов метода/свойства. Самый явный и понятный способ вызвать метод toString() на числе — использовать скобки: (1).toString(); Это позволяет избежать любых неоднозначностей, но есть способы интереснее. Запись с двумя точками 1..toString() сработает, потому что первая точка интерпретируется как часть числа с плавающей запятой (1.0), а вторая точка — как оператор вызова метода. Можно разделить число и метод пробелом: 1 .toString() Это поможет парсеру понять, что 1 — это полное число, а точка и последующий текст являются вызовом метода.
К сожалению, в JavaScript if это не выражение, а оператор. Поэтому ты не можешь в JSX написать: { if (cond) <Comp /> } Логический оператор && тут не подходит, т.к. рендерит нежелательные значения, такие как 0. Поэтому мы вынуждены городить конструкции типа: {cond ? <Comp /> : null} Эту проблему можно было бы решить с помощью postfix if как в Ruby: func() if cond или если разрешить тернарник без второй ветки: cond ? func()
В Python, чтобы импортировать зависимость, сначала указываешь название пакета и только потом конкретные функции или классы из этого пакета: from module import name Преимущество в том, что IDE подсказывают доступные функции после указания пакета. В JavaScript ты сначала указываешь, что импортируешь, и только потом откуда. Соответственно, никаких IDE-подсказок в процессе написания: import name from "module"
Среди крипто-разработчиков популярно мнение, что все нужно писать с нуля, минимизируя внешние зависимости. Этим типа можно повысить безопасность кодовой базы. На практике же это приводит к обратному результату. Например, веб-версия TON Wallet для блокчейна Telegram написана на чистом JS с минимумом зависимостей. View-слой строится с помощью шаблонных литералов с прямыми HTML-вставками. Это привело к тому, что разработчик банально забыл экранизировать пользовательский комментарий к транзакции. XSS? Не, не слышал. Напоминаю, что это код криптовалютного кошелька. В React же по умолчанию экранируется весь вывод. Чтобы сделать HTML-вставку, ты должен явно использовать метод, который кричит о своей небезопасности: dangerouslySetInnerHTML. Вывод: используйте проверенные решения с большим сообществом. Это безопаснее, чем пилить свои велосипеды.
Из коробки CSS Modules не поддерживают типизацию для классов, определенных в CSS-файлах. Но можно подключить плагин typescript-plugin-css-modules, который автоматически сгенерирует TypeScript типы на основе имен классов. В Visual Studio Code убедитесь, что используете версию TypeScript, которая установлена в вашем проекте, а не глобальную. Это можно сделать, нажав на версию TypeScript в правом нижнем углу и выбрав "Use Workspace Version".
const array = ['hello', 'world'] const x = array[3] // type: string x.toUpperCase() // runtime error Чтобы повысить строгость проверок при обращении к элементам массива нужно включить опцию noUncheckedIndexedAccess в TypeScript. Эта опция не входит в набор --strict, ее нужно включать отдельно.
При использовании строковых литералов любые переменные приводятся к строкам, что может привести к нежелательному поведению. TypeScript не будет ругаться на такой код: const user = null console.log(`Hello, ${user}`) // Hello, null Чтобы запретить такое поведение есть правило restrict-template-expressions к Typescript-eslint.
Если не ставить точки с запятой в своем JavaScript/TypeScript-коде, то он станет намного чище и красивее. У нас есть механизм ASI (Automatic Semicolon Insertion). Зачем в этом случае загрязнять свой код? Вы же не управляете памятью вручную в языке со сборщиком мусора.
В последних проектах я решил вместо связки Prettier + ESLint + TypeScript-eslint + Husky перейти на biomejs.dev Системы плагинов еще нет, но основные правила покрыты на 90%. Biome даже планируют затащить в репу самого Node.js Советую и вам попробовать.
Экспортировать переменные и функции из модуля можно просто добавляя export к каждому объявлению или же сгруппировав их в единый экспорт в конце файла. Первый способ чем-то напоминает флаг public в полях классах. Второй вариант лучше, если вы предпочитаете видеть всё публичное API модуля в одном месте, без размазывания по файлу. export const text = "" export const todos = [] export const completed = todos .filter(todo => todo.completed) vs. const text = "" const todos = [] const completed = todos .filter(todo => todo.completed) export { text, todos, completed }
Прежде чем использовать какой-то метод из Lodash, посмотри его реализацию. Часто вижу, что в коде используют _.isNil(value), а там реализация value == null Двойное равенство сработает на null и undefined. Многие Lodash-методы уже давно есть в ES6+ стандарте.
View-слой должен быть декларативным, а контроллер — императивным. Если делаешь императивный view (как в React), то получается каша. Если делаешь декларативный контроллер (как в htmx), то получается говно. Нормального баланса достигли в Angular. В React же грамотно реализовать контроллер можно с помощью MobX, оставив "глупый" view, без хуков и другой логики.
Довольно тупо выглядит ситуация, когда сервису дают какие-то "прикольные" названия из мифологии, аниме и т.д. Обычно крупные компании любят этим заниматься. У сервиса должно быть одно понятное точное название, определяющее, что оно делает. Если четкое название придумать не получается, значит, с выделением сервиса произошла какая-то ошибка. Скорее всего, нужно по-другому разделить систему.
«Уродливые проблемы часто требуют уродливых решений» (Rasmus Lerdorf, cоздатель PHP)