
Hver app du opprettet med WebCatalogs skrivebordsapp, pleide å ta opp rundt 320 MB diskplass på macOS. Det er ikke uvanlig for en Electron-basert app, men WebCatalog er laget for folk som bruker mange nettapper som skrivebordsapper. Installerte du ti, kunne de bruke mer enn 3 GB, selv om de fleste dataene i appene var nøyaktig de samme.
Vi har nylig endret hvordan WebCatalogs skrivebordsapp bygger apper på macOS. Den første appen bruker nå rundt 340 MB fysisk diskplass, inkludert en klargjort kopi av appmotoren som lagres lokalt. Deretter legger hver ekstra app vanligvis bare til 1–2 MB faktisk diskbruk. I testene våre gikk ti apper fra mer enn 3 GB til rundt 360 MB.
Vi fikk til dette med en funksjon som allerede finnes i macOS: APFS-kloner. Utfordringen var ikke bare å klone filer. Det var å få kloningen til å fungere samtidig som hver app forble uavhengig, korrekt kodesignert og funksjonelt lik en app bygget med den gamle prosessen.
Hvorfor hver app brukte ytterligere 320 MB
WebCatalogs skrivebordsapp gjør nettsteder om til frittstående skrivebordsapper. Hver app du oppretter, kjører på Photon, appmotoren vår som er bygget på Electron. På macOS er hver av dem en vanlig .app-pakke som inneholder Electron (Chromium og Node.js), Photon og filene til den aktuelle appen.
Ta for eksempel Slack og Discord. Navnene, ikonene, pakkeidentifikatorene og konfigurasjonen er forskjellige, men det store Electron-rammeverket og det meste av Photon er identisk.
Frem til nå ble hver app bygget som en helt separat kopi.
Slack.app
Electron
Photon
Slack-spesifikke filer
Discord.app
Electron
Photon
Discord-spesifikke filer
Electron-rammeverket og Photon kunne være identiske byte for byte i begge appene, men macOS lagret likevel en ny fysisk kopi for hver app. Ti apper betydde dermed omtrent ti kopier av nesten den samme app-pakken på 320 MB.
Denne arkitekturen hadde én egenskap vi ville bevare: Hver app var helt uavhengig. Å slette én app kunne ikke påvirke en annen, og installerte apper var ikke avhengige av at WebCatalogs skrivebordsapp fortsatt fantes på systemet.
Det vi ville fjerne, var den unødvendige dupliseringen under overflaten.
APFS hadde allerede funksjonen vi trengte
Moderne Mac-er bruker Apples filsystem APFS. APFS støtter kloning, en kopier-ved-skriving-mekanisme som lar to uavhengige filer dele de samme fysiske dataene til en av dem endres.
Se for deg at du kopierer en fil på 300 MB. Ved en vanlig kopiering skriver macOS ytterligere 300 MB til disken, slik at de to filene til sammen bruker rundt 600 MB.
Med en APFS-klon ser den nye filen fortsatt ut og fungerer som en fullstendig fil på 300 MB, men til å begynne med peker den til de samme fysiske blokkene som originalen.
Fil A ─────┐
├── delte fysiske blokker
Fil B ─────┘
Hvis en del av fil B endres senere, skriver APFS nye blokker bare for dataene som er endret. Alt som fortsatt er identisk, kan fortsette å dele de opprinnelige blokkene.
Fil A ───────── delte blokker
Fil B ───────── delte blokker
└──────── endrede blokker
Sett fra appens side er fil A og fil B separate filer. Sett fra SSD-ens side trenger identiske data bare å lagres én gang.
Det var nesten akkurat det vi trengte.
Bygge apper fra en felles base
WebCatalogs skrivebordsapp klargjør nå en base for hver kombinasjon av Electron- og Photon-versjoner. Photon-baseappen inneholder delene som er identiske på tvers av appene, blant annet Electron, Photon, rammeverkets struktur og de felles signaturene.
Når skrivebordsappen oppretter en ny app med de samme versjonene, pakker den ikke lenger ut og bygger en ny fullstendig kopi fra bunnen av. I stedet lager den en APFS-klon av Photon-baseappen og tilpasser bare delene som må være forskjellige.
Dette omfatter appnavn, ikon, pakkeidentifikator, innstillinger, navn på kjørbare filer, byggidentifikator og andre appspesifikke metadata.
Siden det meste av pakken forblir uendret, fortsetter APFS å dele de fysiske blokkene som inneholder Electron og Photon. Bare den forholdsvis lille mengden appspesifikke data tar opp ny plass.
Hvorfor ikke bare dele Electron?
En mer nærliggende løsning ville være å installere Electron én gang og la alle appene peke til den installasjonen.
Vi vurderte det, men det ville grunnleggende endret pålitelighetsmodellen. Hvis den delte Electron-installasjonen forsvant, kunne alle appene som var avhengige av den, slutte å fungere. Et program som rydder i mellomlageret, kunne fjernet den, avinstallering av WebCatalogs skrivebordsapp kunne fjernet den, og det ville blitt mer komplisert å flytte eller gjenopprette en enkelt app.
Det ville også krevd at vi holdt oversikt over hvilke installerte apper som var avhengige av hvilke versjoner av kjøremiljøet, slik at gamle versjoner kunne fjernes på en trygg måte.
Kodesignering i macOS skaper et annet problem. Streng signaturverifisering avviser symbolske lenker som peker utenfor app-pakken.
APFS-kloner gir oss fordelene ved deling uten å innføre en slik avhengighet. Installerte apper kan dele fysiske diskblokker og samtidig forbli komplette, uavhengige app-pakker.
Å slette Photon-baseappen ødelegger ikke apper som er opprettet fra den. Å slette én installert app påvirker ikke en annen. Filsystemet håndterer delingen, mens apparkitekturen forblir uavhengig.
Kodesignering spiste nesten opp besparelsen
Å klone appen var bare en del av utfordringen. macOS-apper må også kodesigneres.
Den gamle byggeprosessen vår signerte hele app-pakken på nytt, inkludert alt innhold, etter tilpasningen. For en vanlig kopi fungerer det fint. Med kopier-ved-skriving-lagring kan det å endre en stor binærfil imidlertid føre til at APFS må tildele nye fysiske blokker til den.
Under utviklingen målte vi at ny signering av Electron-rammeverket la til omtrent 194 MB fysisk lagringsplass per app. Vi hadde unngått å kopiere Electron da appen ble opprettet, bare for å duplisere mye av det igjen under signeringen.
Derfor måtte vi også endre signeringsprosessen.
Det store, felles rammeverket signeres nå som en del av Photon-baseappen. Når skrivebordsappen kloner denne basen, unngår vi å endre de store, delte binærfilene og signerer på nytt bare de mindre delene som faktisk må være forskjellige fra app til app.
Når appen er ferdig, kjører vi streng signaturverifisering av den ferdige pakken for å sikre at alt fortsatt er gyldig.
Dermed beholder vi både garantiene kodesignering i macOS gir, og plassbesparelsen fra APFS.
Da vi ba Node.js om å klone, men det ikke ble klonet
Et annet uventet problem var selve kloningen.
Node.js tilbyr kopieringsflagg som skal be om kopier-ved-skriving-funksjonalitet, blant annet COPYFILE_FICLONE og COPYFILE_FICLONE_FORCE. På papiret hørtes dette ut som akkurat de API-ene vi trengte.
I testene våre med Node.js 24 kopierte vi den samme Electron-appen på 288 MB med flere metoder og målte hvor mye ekstra fysisk diskplass hver operasjon brukte:
fs.cpSync +288 MB
fs.cpSync + COPYFILE_FICLONE +288 MB
fs.cpSync + COPYFILE_FICLONE_FORCE +288 MB
/bin/cp -c -R ~0 MB
Begge kloningsmodusene i Node.js produserte fortsatt en full fysisk kopi i testen vår, og selv FORCE-varianten rapporterte ingen feil da den forventede kloningen uteble.
Den innebygde macOS-operasjonen cp -c fungerte som forventet, så WebCatalogs skrivebordsapp bruker den mekanismen direkte.
Det var også en nyttig påminnelse om at filsystemoptimaliseringer bør verifiseres ved å måle selve filsystemet. At man kaller et API som ber om kopier-ved-skriving, betyr ikke nødvendigvis at filene som opprettes, faktisk deler fysisk lagringsplass.
Gjøre optimaliseringen trygg også når den mislykkes
Å spare diskplass er en optimalisering. Å installere en app er en nødvendighet.
Vi utformet den nye prosessen slik at kloning kan mislykkes uten at appinstallasjonen feiler. Hvis klargjøringen av Photon-baseappen mislykkes, hvis den mellomlagrede basen er skadet, hvis kloningen feiler, eller hvis signaturverifiseringen ikke blir godkjent, går skrivebordsappen tilbake til den tidligere byggeprosessen med full utpakking og full signering.
I verste fall blir diskbruken dermed den samme som før, ikke en mislykket installasjon.
Vi måtte også ta høyde for samtidighet. En Photon-baseapp klargjøres først i en midlertidig mappe og flyttes til sin endelige plassering først når den er ferdig. Dermed kan ikke to appbygginger som skjer samtidig, ved et uhell bruke en halvferdig base.
Eldre baser kan også fjernes trygt. En installert APFS-klon er ikke avhengig av at den opprinnelige basen fortsatt finnes. Hvis basen slettes, beholder klonen de fysiske blokkene den fortsatt bruker.
Dette fungerer på APFS, standardfilsystemet på alle moderne Mac-er. Hvis appene dine ligger på en disk som ikke støtter kloning, for eksempel en ekstern HFS+- eller exFAT-disk, går WebCatalogs skrivebordsapp tilbake til vanlig kopiering. Appene fungerer da som før, men sparer ikke plass. Windows og Linux er foreløpig uendret.
Logisk størrelse og fysisk størrelse er ikke det samme
En litt forvirrende bieffekt er at Finder fortsatt kan vise at hver app er på rundt 320 MB.
Dette tallet er appens logiske størrelse. Appen inneholder faktisk filer på til sammen rundt 320 MB, og hvis disse filene ble kopiert et sted uten kloning, er det omtrent så mye data som måtte skrives.
Det som er endret, er den fysiske størrelsen, altså hvor mange unike blokker disse filene faktisk opptar på disken.
Hvis to apper inneholder det samme rammeverket på 300 MB og APFS lar dem dele de samme underliggende blokkene, kan hver app logisk inneholde 300 MB, mens den andre appen nesten ikke legger til nye fysiske data.
Vis infovinduet i Finder og verktøy som du gjør ikke nødvendigvis denne delingen synlig. Besparelsen merkes best på hvor mye ledig plass det faktisk er igjen på disken.
Vi bekreftet dette med sju reelle apper: Discord, Facebook, Instagram, Messenger, TikTok og to egendefinerte apper. Bygget på denne måten sparte de rundt 1,9 GB diskplass sammenlignet med den gamle byggeprosessen.
Vi undersøkte også de underliggende fysiske diskposisjonene og bekreftet at appene delte sine felles Electron- og Photon-data på blokknivå. En app opprettet med den gamle byggeprosessen delte ingen av disse blokkene, noe som ga oss et nyttig sammenligningsgrunnlag.
Resultatet
For en som bare oppretter én app med WebCatalogs skrivebordsapp, er forskjellen liten. Den første appen bruker faktisk litt mer diskplass enn før, fordi skrivebordsappen også lagrer Photon-baseappen som brukes til å opprette senere kloner.
Etter det øker gevinsten raskt.
Før
1 app ~320 MB
10 apper >3 GB
Med APFS-kloning:
Etter
1 app ~340 MB
10 apper ~360 MB
Etter at den første basen er opprettet, legger hver ekstra app vanligvis bare til 1–2 MB fysisk diskbruk.
Det viktige er at vi har oppnådd dette uten å innføre en avhengighet til et delt kjøremiljø. Hver app forblir en vanlig, selvstendig macOS-app, mens APFS lagrer de identiske Electron- og Photon-dataene bare én gang. Med rundt ti installerte apper kan det redusere den faktiske diskbruken til mindre enn en åttendedel.
Dette er tilgjengelig i den nyeste versjonen av WebCatalogs skrivebordsapp på macOS. Du trenger ikke å slå på noe: Nye apper bruker det automatisk, og appene du allerede har, tar mindre plass neste gang de oppdateres.