Аналитика Telegram-канала
Подписчики
82
Публикаций
2
Динамика подписчиков
7 дней
30 дней
6 месяцев
Больше
8 ноя11 ноя14 ноя
Показаны последние 7 дней
Больше истории →
Охваты публикаций
26.1004.11
4
Средний охват
7
Лучший результат
Показаны 2 публикации — последние в канале
Больше статистики →
Упоминания
2
Упоминаний
1
Из них репостов
1
Каналов
0
Упоминаний за 90 дней
0
Из них репостов
0
Каналов за 90 дней
Последние посты
2 из 2 2 из 2Бизнес-модель приложений, над которыми я работаю – это White Label (WL). Простыми словами: код один, а приложений сотни. В таких условиях крайне важную роль играет пайплайн доставки в прод и его оптимизация, так как скорость CI/CD процессов здесь влияет не только на обновление существующих, но и на создание новых приложений.
Напомню, что у нас Nx-монорепа с React Native, SPA-сайтом и киоском самообслуживания (подробнее – тут).
Сегодня хотел бы рассказать об инциденте в мобильном приложении.
Приложения на React Native состоят из нативной части и JS-бандла. Сборка последнего занимает порядка 40% всей сборки (для Android это около 1–2 минут на 8GB RAM). В случае c WL-приложениями результаты сборки JS можно шарить между всеми, так как код везде один. То есть собираем первый раз, для остальных сборок переиспользуем результаты первой и выигрываем часы работы CI/CD. Достигается это через кастомный Metro Transform Cache, который при первой сборке кладет файлы в S3, а при последующих – читает оттуда.
У нас есть два контура env-переменныx: одни JS читает из натива в рантайме, другие Babel вшивает в код при трансформации. Последние нужны для e2e-тестов и отладки, например, мы подменяем адрес API, чтобы в тестах приложения шли на мок-сервер.
Выпустив очередной релиз, мы поняли, что часть iOS-приложений шла не к своим API. Интуиция сразу направила в сторону poisoned-кэша. Отозвали приложения, которые ещё не прошли ревью, и пошёл разбираться.
Как и у любого кэша, у Metro есть ключи, и строятся они так:
• глобальная часть: версия Metro, cacheVersion из конфига (дефолт – 1.0), хеши файлов трансформеров и хеш настроек трансформера;
• ключ отдельного файла: к глобальной части добавляются путь к файлу, различные опции и sha1 содержимого файла;
• переменных окружения здесь нет.
Вот и произошла коллизия:
• добавили билдтайм-переменную с именем рантайм-переменной, а в коде вшитое значение стояло перед нативным;
• бандл с этой вшитой переменной попал в кэш;
• сломанные приложения уехали в сторы.
Что сделал, чтобы проблема больше не повторилась:
1. Вшитые значения применяются только в e2e-сборке;
2. Все билдтайм-переменные вынесены в отдельный модуль, и их хеш участвует в cacheVersion;
3. Перед отправкой на ревью смотрим, какие переменные реально попали в бандл, и роняем отправку, если значения переменных не совпали с ожидаемыми для бренда.
// metro.config.js
cacheVersion: `mobile-${getInlinedEnvHash()}`,
// tools/inlined-env.js
const getInlinedEnvHash = () =>
createHash('sha1')
.update(INLINED_ENV_KEYS.map((key) => `${key}=${process.env[key] ?? ''}`).join('\n'))
.digest('hex');
Эта история напомнила мне похожую проблему из моего опыта. Кроме того, в Nx тоже сильно предупреждают о классе cache-poison проблем.
Вывод: всё, что влияет на результат сборки, должно входить в ключ кэша. И проверять надо готовый артефакт, а не надеяться на процесс сборки.
ещё
1
0
4 ноя, 15:26
В одном из наших продуктов есть поддержка сканеров штрихкодов. Все эти устройства браузер видит как обычные клавиатуры. Собственно, и работают они так же: после сканирования очень быстро эмитят события keydown на элемент с фокусом, которое потом всплывает наверх в document. Здесь мы не изобретаем нового:
• используем библиотеку доИИэры onscan.js, которая вешает необходимые обработчики;
• обработчики есть на паре экранов, при уходе с них – отписываемся;
• хотим использовать captureEvents, чтобы поймать keydown от сканера раньше обработчиков приложения.
Однако при использовани последней опции, после ухода с этих экранов, любое нажатие на реальную клавиатуру падает с TypeError: Cannot read properties of undefined (reading 'options'). Помимо прочего, добрый вечер, утечка! После недолгой отладки выяснилось, что либа вешает и снимает обработчики с разным количеством аргументов. Я не знал, но есть правила, по которым формируется "ключ" обработчика:
el.addEventListener('keydown', onKeyDown, true);
el.removeEventListener('keydown', onKeyDown); // не снимет, т.к. capture – часть "ключа"
В моем случае, чтобы не патчить мертвую библиотеку, решение – не использовать captureEvents. Но в таком случае обработчики приложения видят события скана раньше библиотеки и если кто-то из них вызовет stopPropagation, библиотека вообще не получит keydown. Хорошо, что на экранах со сканером таких обработчиков пока нет.
Для собственного же кода надежнее всего использовать AbortController для событий, чтобы не беспокоиться о "ключе":
const controller = new AbortController();
el.addEventListener('keydown', onKeyDown, { capture: true, signal: controller.signal });
controller.abort(); // abort() снимает слушатель с любыми опциями
Любопытно, но недавно появилась другая библиотека onscan-next в соавторстве с Claude, где такой проблемы нет.
ещё
7
0
1 26 окт, 16:50
Продолжить анализ этого канала
- История роста подписчиков
- Просмотры и охваты публикаций
- Кто упоминает канал и кого упоминает он
- Похожие каналы и подбор для рекламы
Открыть аналитику
Демо до 14 дней