Проблема: «На тестовых устройствах всё летает»
История знакомая: приложение для рабочих (blue collar employees), где основной сценарий — сканирование QR, обработка фото и отправка чекпоинтов. На среднестатистических тестовых смартфонах всё работает идеально: 1-2 секунды на загрузку, instant submission. Но в поле — перегрев устройств, лаги и авторефреш страницы вместо отправки данных.
Ключевые симптомы:
- Загрузка фото вместо 2 секунд занимает 40+ секунд при нормальном интернете (210 Mbps)
- Многократные клики по кнопке из-за «зависания» интерфейса
- Браузер убивает вкладку при нехватке памяти (сотни фоновых приложений у пользователей)
Где тонко: специфика low-end окружения
Первая ошибка — тестировать только на «чистых» устройствах. В реальности у пользователей:
- Фоновые процессы: 100+ приложений (мессенджеры, соцсети, заводские утилиты)
- Урезанная память: бюджетные Android с 2-3 ГБ RAM, где браузеру выделяют ≤500MB
- Неидеальные QR: повреждённые, грязные или частично разорванные коды на оборудовании
Проблемные места в текущем стеке:
- QR-сканер (qr-scanner-wechat) не справляется с повреждёнными кодами
- Кастомный редактор изображений (сгенерированный Claude) не оптимизирован под слабые GPU
- Next.js hydration на дешевых процессорах съедает 3-4 секунды до интерактивности
Что можно сделать без переписывания
Прежде чем бросать Next.js, попробуйте:
Для QR:
// Переход на WASM-сканер с adaptive thresholding
import { ZXingBrowser } from "@zxing/browser";
const reader = new ZXingBrowser.BrowserQRCodeReader();
reader.decodeFromVideoElement(cameraPreview);
ZXing лучше обрабатывает повреждённые коды за счёт алгоритмов бинаризации.
Для памяти:
- Включить
optimizeFonts: falseв next.config.js — шрифты не блокируют FCP - Добавить
?rawдля встроенных изображений в CSS, чтобы избежать лишних парсинговых потоков - Заменить
next/imageна<img loading="lazy">для тяжёлых фоточекков
Для CPU:
// Заменить useState на сигналы в медленных компонентах
import { signal } from "@preact/signals-react";
const imageSrc = signal(null);
Preact Signals на 40% легче для частых обновлений.
Когда vanilla JS — не панацея
Полный отказ от фреймворков кажется логичным, но:
- Вам всё равно нужен роутинг (например, Navigo)
- Ручное управление состоянием усложнит поддержку
- Своя сборка скорее всего проиграет в TTI Next.js + SWC
Альтернативы:
- Preact + Vite — 3KB runtime против 45KB React
- Astro с островами — если интерфейс простой (QR + форма)
- PWA с Service Worker — кешировать core-логику в оффлайне
Вместо выводов: checklist для миграции
Если решили уходить с Next.js:
- Протестируйте TTI на реальных устройствах пользователей через WebPageTest
- Для сканера попробуйте комбинацию Dynamsoft + preload WASM
- Замените кастомный редактор на Pica.js для ресайза и Compressor.js для сжатия
- Добавьте визуальный feedback при долгих операциях (прогресс-бар вместо спиннера)
Главный урок: на низкоэндовых устройствах проблемы начинаются там, где вы их не ждёте — например, в GC из-за частых событий мыши. Иногда проще убрать анимацию на touchmove, чем переписывать половину приложения.
Источник: https://www.reddit.com/r/reactjs/comments/1vbudao/our_next_js_app_not_works_on_low_end_devices/