Як застосунок WebCatalog Desktop використовує клони APFS, щоб зменшити використання дискового простору застосунками на Mac до 8 разів

Тепер настільний застосунок WebCatalog використовує клони APFS у macOS, щоб значно зменшити використання дискового простору. Завдяки тому, що однакові дані Electron і Photon зберігаються лише один раз, кожен додатковий застосунок зазвичай займає лише 1–2 МБ фізичного простору замість приблизно 320 МБ.

23 вересня 2026 р.

Nguyen Tran · Software Engineer

Як застосунок WebCatalog Desktop використовує клони APFS, щоб зменшити використання дискового простору застосунками на Mac до 8 разів

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

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

Для цього ми використали можливість, уже вбудовану в 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. APFS підтримує клонування — механізм копіювання під час запису, завдяки якому два незалежні файли можуть спільно використовувати ті самі фізичні дані, доки один із них не зміниться.

Уявіть, що ви копіюєте файл розміром 300 МБ. За звичайного копіювання macOS записує на диск ще 300 МБ, тож разом два файли займають близько 600 МБ.

Клон APFS виглядає і працює як повноцінний файл розміром 300 МБ, але спочатку він посилається на ті самі фізичні блоки, що й оригінал.

Файл A ─────┐
            ├── спільні фізичні блоки
Файл B ─────┘

Якщо згодом частина файлу B зміниться, APFS запише нові блоки лише для змінених даних. Усе, що залишиться однаковим, і далі зможе використовувати початкові блоки спільно.

Файл A ───────── спільні блоки

Файл B ───────── спільні блоки
        └─────── змінені блоки

З погляду застосунку файли A і B — це окремі файли. З погляду SSD однакові дані достатньо зберігати лише один раз.

Це майже саме те, що нам було потрібно.

Створення застосунків зі спільної основи

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

Коли настільний застосунок створює ще один застосунок із тими самими версіями, він більше не розпаковує й не збирає ще одну повну копію з нуля. Натомість він створює клон APFS базового застосунку Photon і змінює лише ті частини, які мають відрізнятися.

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

Оскільки більша частина пакета залишається незмінною, 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. Нічого вмикати не потрібно: нові застосунки використовують її автоматично, а вже встановлені почнуть займати менше місця після наступного оновлення.