Tree shaking

Looking for some guidance on reducing our app size. We are integrating a number of third party tools into our app, each comes with a swift package. The providers are expanding their offerings and adding large dependencies to their packages for features we have no intention of ever using. Slowly but surely our app size is ticking up and I can see new dependencies showing up in my project's "Package Dependencies". I've asked the teams to try modularise their setups and they've said no, or not responded.

I realise I can't do much about the packages showing up in Xcode. But is there any tooling to strip these out as part of a build phase before it gets archived or anything like that? Would really love to cut all this crap out of my app install size

I am not sure if I fully understand what you are trying to achieve or what you are asking.

However not all packages, which are shown in the „Package Dependencies“ section in Xcode are actually bundled into your app. Only those which are actually required by targets you depend on.

Only those which are actually required by targets you depend on.

Yes I depend on the target, but the target is massive, and i'm only using 10% of it. They keep expanding it and now i'm only using 5% of it. But because its all bundled together, it all ends up in my app. They provide a minor bug fix for a feature i'm using, I upgrade the version and all of a sudden my app size increase 2mb for no reason.

I'm looking for a tree shaking solution, like other languages, that strips out unused code. There are entire packages that my code never actually touches, but they are being bundled with my app because a third party package refuses to modularise it. I want to strip out this code so that my app size stops increasing for no reason

There have been other discussions about this; search for forums for "dead code stripping".

You might see some benefit if you add the -internalize-at-link flag to your compile configuration. This stops the compiler from annotating quite as much code with no_dead_strip (which applies to any public declaration by default, which is going to cover most packages you're using by definition). It won't strip out all the metadata, but it might improve your numbers somewhat by removing other dead code.

Identifying which type metadata can be removed and making it removable is trickier, so there hasn't been as much progress made on that front.

Sorry for the long delay, finally had a few minutes to look at this. When I add this to my xcode build settings as a compiler flag I get a build error saying unknown argument. How/where do I use this?

After a lot of googling I found that its a "frontend" flag and needs to be used like this when doing command line builds with xcodebuild:

... OTHER_SWIFT_FLAGS="-Xfrontend -internalize-at-link"

This unfortunately had barely any impact, removing a fraction of a mb from the app size. A swift package I use added a sub dependency recently, for a new feature that I make no use of. This new sub dependency added ~0.3mb to the app size, but turning on this flag didn't even remove that much let alone anything from the other packages in similar situations

If anyone has any other suggestions, please let me know, thanks

I think reducing binary size is an important aspect, and it should be part of the maturing of the Swift programming language that there should be a simple top-level build option to be working in this direction or even a good default behaviour. There is too much expertise needed for the options discussed here.

2 Likes