Как десктопное приложение WebCatalog использует клоны APFS, чтобы сократить занимаемое приложениями место на диске Mac до 8 раз

Настольное приложение WebCatalog теперь использует клоны APFS в macOS, чтобы значительно сократить использование дискового пространства. Поскольку одинаковые данные Electron и Photon сохраняются только один раз, каждое дополнительное приложение обычно занимает всего 1–2 МБ физического пространства вместо примерно 320 МБ.

23 сентября 2026 г.

Nguyen Tran · Software Engineer

Как десктопное приложение WebCatalog использует клоны APFS, чтобы сократить занимаемое приложениями место на диске Mac до 8 раз

Раньше каждое приложение, созданное с помощью настольного приложения WebCatalog, занимало на macOS около 320 МБ дискового пространства. Для приложения на базе Electron это не необычно, но WebCatalog рассчитан на людей, которые используют много веб-приложений как настольные. Установите десять таких приложений — и они могут занять более 3 ГБ, хотя большая часть данных внутри них совершенно одинакова.

Недавно мы изменили процесс создания приложений в настольном приложении WebCatalog для macOS. Теперь первое приложение занимает около 340 МБ физического пространства на диске, включая хранящуюся локально подготовленную копию движка. После этого каждое следующее приложение обычно добавляет лишь 1–2 МБ фактически занятого места. В наших тестах десять приложений стали занимать около 360 МБ вместо более чем 3 ГБ.

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

Почему каждое приложение занимало ещё 320 МБ

Настольное приложение WebCatalog превращает сайты в самостоятельные настольные приложения. Каждое созданное приложение работает на Photon — нашем движке на базе Electron. В macOS это обычный пакет .app, содержащий Electron (Chromium и Node.js), Photon и файлы конкретного приложения.

Возьмём, например, Slack и Discord. Их названия, значки, идентификаторы пакетов и настройки различаются, но объёмный фреймворк Electron и большая часть Photon у них одинаковы.

До сих пор каждое приложение создавалось как полностью отдельная копия.

Slack.app
  Electron
  Photon
  Файлы Slack

Discord.app
  Electron
  Photon
  Файлы Discord

Фреймворк Electron и Photon в обоих приложениях могли совпадать побайтно, но macOS всё равно хранила отдельную физическую копию для каждого из них. Поэтому десять приложений означали примерно десять копий почти одинакового пакета размером 320 МБ.

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

Мы хотели устранить лишь ненужное дублирование данных.

В APFS уже был необходимый нам механизм

Современные компьютеры Mac используют файловую систему Apple APFS. Она поддерживает клонирование — механизм копирования при записи, который позволяет двум независимым файлам совместно использовать одни и те же физические данные, пока один из файлов не изменится.

Представьте, что вы копируете файл размером 300 МБ. При обычном копировании macOS записывает на диск ещё 300 МБ, и оба файла в сумме занимают около 600 МБ.

При клонировании в APFS новый файл выглядит и ведёт себя как полноценный файл размером 300 МБ, но изначально ссылается на те же физические блоки, что и оригинал.

Файл A ────┐
           ├── общие физические блоки
Файл B ────┘

Если впоследствии часть файла B изменится, APFS запишет новые блоки только для изменённых данных. Всё, что осталось прежним, продолжит использовать общие блоки.

Файл A ──────── общие блоки

Файл B ──────── общие блоки
        └────── изменённые блоки

С точки зрения приложения файлы A и B — отдельные файлы. С точки зрения SSD одинаковые данные достаточно хранить один раз.

Это почти в точности то, что нам было нужно.

Создание приложений на общей основе

Теперь настольное приложение WebCatalog подготавливает основу для каждой комбинации версий Electron и Photon. Базовое приложение Photon содержит части, одинаковые для всех приложений: Electron, Photon, структуру фреймворка и общие подписи.

Когда настольное приложение создаёт ещё одно приложение на тех же версиях, оно больше не распаковывает и не собирает с нуля очередную полную копию. Вместо этого оно создаёт клон базового приложения Photon средствами APFS и изменяет только то, что должно отличаться.

Это название и значок приложения, идентификатор пакета, настройки, имена исполняемых файлов, идентификатор сборки и другие метаданные конкретного приложения.

Поскольку большая часть пакета остаётся неизменной, APFS продолжает совместно использовать физические блоки с Electron и Photon. Новое место занимает лишь сравнительно небольшой объём данных, относящихся к конкретному приложению.

Почему бы просто не использовать общую копию Electron?

Более очевидный подход — один раз установить Electron и сделать так, чтобы все приложения на него ссылались.

Мы рассматривали этот вариант, но он в корне изменил бы модель надёжности. Если бы общая установка Electron исчезла, все зависящие от неё приложения могли бы перестать работать. Её могла бы удалить утилита очистки кэша или удаление настольного приложения WebCatalog. Перемещение или восстановление отдельного приложения также стало бы сложнее.

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

Подпись кода в macOS создаёт ещё одну проблему: строгая проверка подписи отклоняет символические ссылки, ведущие за пределы пакета приложения.

Клоны APFS позволяют получить преимущества совместного хранения без такой зависимости. Установленные приложения могут использовать общие физические блоки на диске, оставаясь при этом полноценными независимыми пакетами.

Удаление базового приложения Photon не нарушит работу созданных из него приложений. Удаление одного установленного приложения не повлияет на другое. Совместным использованием данных управляет файловая система, а приложения остаются архитектурно независимыми.

Подпись кода едва не свела экономию на нет

Клонирование приложения было лишь частью задачи. Приложения для macOS также нуждаются в кодовой подписи.

В прежнем процессе сборки после внесения изменений мы заново подписывали каждый пакет приложения целиком, включая вложенные компоненты. При обычном копировании это не проблема. Но при хранении с копированием при записи изменение большого бинарного файла может заставить APFS выделить под него новые физические блоки.

Во время разработки мы измерили, что повторное подписание фреймворка Electron добавляло примерно 194 МБ физически занятого места на каждое приложение. Мы избежали копирования Electron при создании приложения, но затем снова дублировали значительную его часть при подписании.

Поэтому процесс подписания тоже пришлось изменить.

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

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

Так мы сохраняем и гарантии подписи кода в macOS, и экономию места благодаря APFS.

Когда запрос на клонирование через Node.js не привёл к клонированию

Возникла ещё одна неожиданная проблема: само выполнение клонирования.

Node.js предоставляет флаги копирования для запроса копирования при записи, в том числе COPYFILE_FICLONE и COPYFILE_FICLONE_FORCE. На бумаге это были именно те API, которые нам требовались.

При тестировании на Node.js 24 мы скопировали одно и то же приложение Electron размером 288 МБ несколькими способами и измерили, сколько дополнительного физического места на диске заняла каждая операция:

fs.cpSync                              +288 МБ
fs.cpSync + COPYFILE_FICLONE           +288 МБ
fs.cpSync + COPYFILE_FICLONE_FORCE     +288 МБ
/bin/cp -c -R                          ~0 МБ

В нашем тесте оба режима клонирования Node.js всё равно создавали полную физическую копию. Даже вариант FORCE не сообщал об ошибке, когда ожидаемого клонирования не происходило.

Штатная команда macOS cp -c работала как ожидалось, поэтому настольное приложение WebCatalog использует непосредственно её.

Это также напомнило нам, что оптимизации файловой системы нужно проверять измерениями на уровне самой файловой системы. Вызов API с запросом копирования при записи не обязательно означает, что полученные файлы действительно совместно используют физическое пространство.

Как сделать так, чтобы сбой оптимизации не мешал установке

Экономия места на диске — это оптимизация. Успешная установка приложения — необходимость.

Мы спроектировали новый процесс так, чтобы сбой клонирования не нарушал установку. Если не удаётся подготовить базовое приложение Photon, если сохранённая в кэше основа повреждена, если клонирование завершается ошибкой или если не проходит проверка подписи, настольное приложение возвращается к прежнему процессу сборки с полной распаковкой и полным подписанием.

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

Нам также пришлось учесть одновременную сборку нескольких приложений. Базовое приложение Photon сначала подготавливается во временном каталоге и перемещается в конечное расположение только после завершения. Поэтому две параллельные сборки не смогут случайно обнаружить недостроенную основу.

Старые базовые приложения тоже можно безопасно удалять. Установленный клон APFS не зависит от существования исходной основы. Если её удалить, клон сохранит физические блоки, которые он использует.

Это работает на APFS — файловой системе по умолчанию на всех современных компьютерах Mac. Если приложения находятся на диске, который не поддерживает клонирование, например на внешнем накопителе с HFS+ или exFAT, настольное приложение WebCatalog возвращается к обычному копированию: приложения работают как прежде, но место не экономится. В Windows и Linux пока ничего не меняется.

Логический и физический размеры — не одно и то же

Есть один не совсем очевидный побочный эффект: Finder по-прежнему может показывать, что каждое приложение занимает около 320 МБ.

Это логический размер приложения. Оно действительно содержит файлы общим объёмом около 320 МБ, и при копировании без клонирования на диск пришлось бы записать примерно столько данных.

Изменился физический размер — количество уникальных блоков, которые эти файлы фактически занимают на диске.

Если два приложения содержат одинаковый фреймворк размером 300 МБ и APFS позволяет им использовать одни и те же физические блоки, каждое приложение может иметь логический размер 300 МБ, хотя второе почти не добавит новых физических данных.

Окно «Свойства» в Finder и инструменты вроде du не обязательно показывают такое совместное использование. Экономия заметнее всего по фактическому объёму свободного места на диске.

Мы проверили это на семи реальных приложениях: Discord, Facebook, Instagram, Messenger, TikTok и двух пользовательских приложениях. При сборке новым способом они сэкономили около 1,9 ГБ дискового пространства по сравнению со старым процессом.

Мы также проверили физическое расположение данных на диске и подтвердили, что приложения совместно используют общие данные Electron и Photon на уровне блоков. Приложение, созданное старым способом, не использовало ни одного из этих блоков совместно с ними — это дало нам полезный ориентир для сравнения.

Результат

Если вы создаёте с помощью настольного приложения WebCatalog только одно приложение, разница невелика. Первое приложение даже занимает немного больше места, чем раньше, потому что настольное приложение также хранит базовое приложение Photon для создания последующих клонов.

Но дальше выгода быстро растёт.

Раньше

1 приложение     ~320 МБ
10 приложений    >3 ГБ

С клонированием APFS:

Теперь

1 приложение     ~340 МБ
10 приложений    ~360 МБ

После создания первоначальной основы каждое следующее приложение обычно добавляет лишь 1–2 МБ физически занятого места на диске.

Важно, что мы добились этого без зависимости от общей среды выполнения. Каждое приложение остаётся обычным, самодостаточным приложением для macOS, а APFS хранит одинаковые данные Electron и Photon лишь один раз. При примерно десяти установленных приложениях фактическое использование диска может сократиться более чем в восемь раз.

Эта возможность доступна в последней версии настольного приложения WebCatalog для macOS. Включать ничего не нужно: новые приложения используют её автоматически, а уже установленные начнут занимать меньше места при следующем обновлении.