Нажмите «Загрузить», и в инструментах разработчика появится красная надпись: размер главного пакета превышает ограничение в 2 МБ. Публиковать версию нельзя, задачи висят в очереди.
В этой статье не будет теоретического обзора, только список способов вернуть размер главного пакета в пределы 2 МБ, отсортированный по принципу «много сэкономить, мало изменить».
Сначала разберемся: что именно ограничивает 2 МБ
WeChat устанавливает для кода Mini Program два жёстких лимита:
| Ограничение | Верхняя граница |
|---|---|
| Главный пакет (включая app.js, страницы tabBar, общие ресурсы и т.д.) | 2 МБ |
| Один подпа́кет | 2 МБ |
| Общий размер всех пакетов | 20 МБ |
Обратите внимание: здесь «размер» — это объем уже загруженного кода, а не только JS. В проекте учитываются все файлы, которые попадут в сборку: .js、.wxml、.wxss、.、шрифты、аудио, а также — обычно занимающие львиную долю — изображения.
Это жёсткое ограничение «не укладываешься — не выйдет релиз», а не просто «лучше оптимизировать». Поэтому первым делом не нужно хвататься за инструмент, а нужно понять, где деньги ушли.
Шаг 0: Посмотреть, что именно занимает место в главном пакете
В правом верхнем углу инструментов разработчика WeChat можно посмотреть общий размер локального пакета в разделе «Подробнее → Основная информация»; подробнее — в панели инструментов «Анализ зависимостей кода» (Code Dependency Analysis), где можно увидеть объем по файлам и отметить неиспользуемые.
У большинства проектов после просмотра этой таблицы выясняется одна и та же вещь: статические ресурсы, такие как изображения и шрифты, значительно больше бизнес-кода. JS объемом в десятки тысяч строк — это всего несколько сотен КБ, а необработанный баннерный снимок может занимать сотни КБ, а каталог images/ легко съедает половину главного пакета.
Ниже — список мер, отсортированный по выгоде от наибольшей к наименьшей.
Способ 1: Удалить абсолютно бесполезные файлы
Самый простой и часто игнорируемый способ.
- Файлы, помеченные как неиспользуемые в «Анализе зависимостей»: старые иконки, оставшиеся от прошлых версий,废弃ные страницы, тестовые изображения — удаляем.
- Файлы, которые не должны попадать в пакет: макеты, README,
.psd, исходные материалы, Mock-данные. Если можно вынести их из каталога проекта — выносите; если нет — вproject.config.используйтеpackOptions.ignoreдля исключения:
{
"packOptions": {
"ignore": [
{ "type": "folder", "value": "design" },
{ "type": "suffix", "value": ".psd" }
]
}
}
- Полная имплементация библиотеки компонентов: если используется всего три компонента, а в главный пакет попадает вся библиотека UI — это частый «скрытый жирный». Измените на имплементацию по требованию (on-demand), оставив только нужные каталоги компонентов.
Способ 2: Подпакеты — вынести страницы, не являющиеся стартовыми, из главного пакета
Это официальный правильный путь. В главный пакет оставляем только стартовую страницу, страницы tabBar и необходимые общие для них ресурсы. Остальные страницы по бизнес-логике разбиваем на подпакеты:
{
"pages": ["pages/index/index", "pages/mine/mine"],
"subPackages": [
{ "root": "packageOrder", "pages": ["list/list", "detail/detail"] },
{ "root": "packageActivity", "pages": ["index/index"] }
],
"preloadRule": {
"pages/index/index": { "network": "all", "packages": ["packageOrder"] }
}
}
Несколько важных моментов:
- Ресурсы следуют за страницей. Для картинок и компонентов, используемых в подпакете, их нужно поместить в каталог подпакета. Если они лежат в общем
images/главного пакета, то независимо от того, как вы разбили подпакеты, их объем всё равно будет засчитан в главном пакете. preloadRule— предварительная загрузка. При входе на главную страницу можно «по дороге» скачать тот подпакет, который с высокой вероятностью понадобится дальше. Пользователь почти не почувствует задержки.- Независимый подпакет (
"independent": true): подходит для страниц мероприятий, лендингов и т.п., которые могут открываться отдельно от главного пакета, без зависимости от него при запуске. - Асинхронность подпакетов. При использовании компонентов или JS из других подпакетов можно использовать заглушки и
require.async, чтобы не подтягивать код обратно в главный пакет ради «общего» использования.
Цена такого подхода — необходимо менять структуру каталогов и пути переходов. Для старых проектов разборка может занять много времени, именно поэтому сначала имеет смысл выполнить следующий шаг — часто после него главный пакет возвращается в пределы 2 МБ.
Способ 3: Сжать изображения (изменений минимум, выгода максимальная)
Изображения — самая простая часть для «лишнего веса» в главном пакете. PNG из экспорта дизайнера могут содержать лишние блоки данных, качество JPG может быть завышенным. Эти байты пользователю невидимы, но каждый из них учитывается в 2 МБ.
Какие изображения обязаны остаться в пакете
Не все изображения можно перенести в CDN:
- Иконки
tabBar:iconPath/selectedIconPathподдерживают только локальные пути, сетевые изображения не работают. - Стартовый экран, логотип главного экрана, резервные изображения. Их нужно показывать и при слабом интернете или офлайне.
- Маленькие иконки, которые встречаются часто. Загрузка каждого раза по сети невыгодна.
Эти изображения можно оставить только в пакете, поэтому единственный способ — сделать их меньше.
Обходная трюк: фоновые изображения в wxss
Использование background-image для локальных изображений в .wxss на реальном устройстве не работает. Частый обходной путь — преобразовать в base64 и встроить. Но кодировка base64 увеличивает объем примерно на треть, и она скрыта в файле стилей, так что в анализе зависимостей заметна не сразу. Если можно использовать компонент <image> или сетевой адрес — не используйте встроенные стили; если встроить обязательно — сначала сожмите исходник, а потом конвертируйте.
Используйте ImgZilla для on-site сжатия целого каталога ресурсов
Самое страшное для разработки Mini Program — после сжатия картинок возвращаться и менять пути — в wxml、в wxss、в конфигурации JS、в конфигурации tabBar. Там повсюду /images/xxx.png. Многие утилиты сохраняют как xxx-min.png или требуют экспортировать в другую папку, и после сжатия нужно вручную заменять и перепроверять, не пропустили ли что-то.
ImgZilla — это инструмент для сжатия изображений для macOS, который работает on-site (без смены имен и путей):
- Имя файла、путь、формат не меняются. После сжатия
icon-home.pngпо-прежнемуicon-home.png, в коде ничего менять не нужно. - Просто перетащите целый каталог. Он рекурсивно сканирует все подкаталоги, автоматически пропуская скрытые файлы и
node_modules. Перетащитеimages/、static/или даже весь каталог проекта — и сразу в инструментах разработчика увидите изменение объема пакета. - Исходники по умолчанию перемещаются в корзину. Если что-то не понравится — правый клик «Вернуть на место» — и файл возвращается. Если проект в Git, это дополнительная страховка.
- Работает локально, без отправки в сеть. Материалы корпоративного проекта не покидают ваш компьютер, и нет ограничений онлайн-сервисов по количеству файлов или размеру.
В плане качества подход отличается для разных форматов:
- PNG: используется oxipng для без потери качества (lossless). Пиксели не меняются. В Mini Program много иконок и сплайнов — их можно сжимать смело.
- SVG: удаление избыточных тегов — тоже без потерь.
- JPG / WebP / GIF и т.д.: сжатие с потерями. Параметры уже настроены на диапазон визуально без потерь — человеческим глазом разницу заметить сложно. Не обязательно слепо доверять; встроенное окно сравнения (⌘D) позволяет сравнивать в реальном времени и детально рассматривать пиксели.
Еще два момента:
- Он не «жмет» сильно уже оптимизированные изображения. Если степень сжатия менее 0,4%, файл помечается как «уже минимальный» и остается без изменений. Не ради красивой цифры картинка не размывается. Если ваши изображения уже были тщательно оптимизированы, этот шаг может не дать большого эффекта — это нормально и указывает, что пора переходить к подпакетам.
- Не меняет формат и разрешение. После сжатия PNG остается PNG, размер не меняется. Если вы хотите конвертировать в WebP или уменьшить размер 3x-изображения до 2x — это отдельная задача.
Сколько можно сэкономить зависит от того, как изначально были экспортированы изображения, поэтому конкретный процент не приводится. В качестве ориентира: для тестов мы опубликовали результаты — для уже сжатых JPG сайтов экономия составила 46,8%; для JPG с камер — 76,8% (подробнее в серии «ImgZilla Test»). В Mini Program изображения часто экспортируются прямо из дизайн-софта, обычно не были оптимизированы, поэтому стоит попробовать.
ImgZilla на данный момент только для macOS (macOS 12.3 и выше), доступна в Mac App Store, до 10 изображений бесплатно в день. Для пользователей Windows логика этого раздела применима, нужно просто найти аналогичный инструмент, сохраняющий имена файлов.
Способ 4: Переместить большие изображения в CDN
После сжатия остаются изображения, которые всё еще велики — например, баннеры мероприятий, длинные изображения деталей, большие снимки товаров — изначально они не подходят для размещения в пакете. Загрузите их в объектное хранилище или CDN, замените ссылки на сетевые адреса — и главный пакет сразу становится легче.
Но это не бесплатно:
- Первая загрузка идет по сети, при слабом интернете возможны пустые экраны. Лучше использовать заглушки или скелетоны.
- Нужно поддерживать процесс загрузки、кэширования и обновления.
- Оплата по трафику CDN. Каждый раз, когда изображение загружается, вы платите. Стоимость примерно равна объему изображения × количеству просмотров. Поэтому, прежде чем переносить в CDN, также имеет смысл сначала сжать изображения — один раз сжатие сэкономит трафик при каждом последующем просмотре.
Способ 5: Финальные штрихи на уровне кода
После того как с изображениями и структурой разобрались, оставшееся свободное место можно «вытянуть» из кода:
- В инструментах разработчика в разделе «Подробнее → Локальные настройки» включите сжатие скриптов, стилей и WXML при загрузке.
- В
app.включите"lazyCodeLoading": "requiredComponents"(по требованию). Это в основном влияет на скорость запуска, а не на объем пакета, но если вы занимаетесь оптимизацией — включите и это. - Проверьте
miniprogram_npm: не имплементируется ли весь пакет npm, когда используются только несколько функций. - Длинные статические данные (списки городов, таблицы конфигурации), записанные прямо в JS, лучше передавать через API.
Таблица-резюме
| Мера | Экономия | Изменения | Рекомендуемый порядок |
|---|---|---|---|
| Удаление бесполезных файлов | Зависит от истории проекта | Очень мало | 1 |
| On-site сжатие изображений | Чем больше изображений и хуже экспорт, тем больше | Почти ноль, пути не меняются | 2 |
| Подпакеты | Может быть много | Необходимо менять структуру каталогов и маршрутизацию | 3 |
| Перенос больших изображений в CDN | Много | Нужно менять ссылки, поддерживать процесс загрузки | 4 |
| Сжатие кода и имплементация по требованию | Мало | В зависимости от ситуации | 5 |
Логика проста: сначала мелкие изменения, потом крупные. Удаление файлов и сжатие изображений почти не затрагивают бизнес-код. После этого посмотрите, сколько еще не хватает до 2 МБ — если главный пакет уже в норме, релиз можно публиковать; если нет — переходите к подпакетам и CDN.
Превышение лимита главного пакета часто происходит в самый напряженный момент перед релизом. Включите сжатие изображений в повседневный процесс — перед добавлением каждой новой картинки сжимайте её — и в следующий раз не придется волноваться перед дедлайном перед красной надписью об ошибке.
