Recaf icon indicating copy to clipboard operation
Recaf copied to clipboard

Reduce Recaf artifact size

Open Col-E opened this issue 1 year ago • 1 comments

Current size as of 2b3017f0866dc8e6c17fc325ac6ba6e620ade841 - 76 MB - (Nov 18 2024)

Current size as of 17371d720e71d06665f472a09cff80437a4733eb - 56 MB - (Jan 3 2025)

Current size as of bcf59f76e1d08afbb842f4e926dfb5a6430d09ec - 60 MB - (Sept 7 2025)

Current size as of f101c6e92af76914c6be3ef9b71b11081d9a3623- 62 MB - (Nov 13 2025)

Action items

  • [ ] -30 MB Remove unused fastutil collection implementations
    • ~~Can create a shadowJar output filter for this~~ Actually no we can't - packaging only a select few classes from transitive dependencies is broken in shadowJar
  • [x] OpenRewrite options:
    • [x] -10 MB Remove it + transitive dependencies
      • Need an alternative for parsing Java source
        • We could possibly make our own with the javac AST similiar to how OpenRewrite does things, but more lean (DONE: SourceSolver)
        • ~~Go back to using JavaParser~~ (~2 MB)
          • ~~Not ideal since we would lose the partial AST read support we get with OpenRewrite~~
    • [x] -7 MB Remove unused transitive dependencies
  • [ ] -9 MB Remove R8 in favor of dex
  • [ ] -1 MB Remove JPhantom in favor of Reconstruct
  • [x] -4 MB Remove Jackson dependency and store AndroidRes data in JSON instead of XML
    • Will want to keep a tool in the Recaf repo to produce the JSON from the XML since the XML comes from the Android SDK releases. We can keep Jackson on the runtime path for this case, but not as a implementation/api dependency.
  • [ ] ~~-4 MB Strip debug info from dependencies (after the above steps)~~
    • Not worth it because it makes bugs harder to diagnose if there is a crash/exception in the dependency code

Summary

Assuming all action items are taken (and best alternatives for multiple choice cases)

  • -53 MB in potential removed data leading to a 23 MB fat-jar

Col-E avatar Nov 20 '24 03:11 Col-E

For fastutil, these are the classes we and transitive dependencies import.

it.unimi.dsi.fastutil.Hash.Strategy;
it.unimi.dsi.fastutil.bytes.ByteIterator;
it.unimi.dsi.fastutil.chars.Char2IntArrayMap;
it.unimi.dsi.fastutil.chars.Char2IntMap;
it.unimi.dsi.fastutil.chars.Char2ObjectArrayMap;
it.unimi.dsi.fastutil.chars.Char2ObjectMap;
it.unimi.dsi.fastutil.chars.CharArraySet;
it.unimi.dsi.fastutil.chars.CharSet;
it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
it.unimi.dsi.fastutil.ints.Int2IntLinkedOpenHashMap;
it.unimi.dsi.fastutil.ints.Int2IntMap;
it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
it.unimi.dsi.fastutil.ints.Int2IntSortedMap;
it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap;
it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry;
it.unimi.dsi.fastutil.ints.Int2ObjectMap;
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
it.unimi.dsi.fastutil.ints.Int2ObjectSortedMap;
it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap;
it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap;
it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
it.unimi.dsi.fastutil.ints.Int2ReferenceMaps;
it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
it.unimi.dsi.fastutil.ints.Int2ReferenceRBTreeMap;
it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMaps;
it.unimi.dsi.fastutil.ints.IntArrayList;
it.unimi.dsi.fastutil.ints.IntBidirectionalIterator;
it.unimi.dsi.fastutil.ints.IntList;
it.unimi.dsi.fastutil.ints.IntOpenHashSet;
it.unimi.dsi.fastutil.ints.IntSet;
it.unimi.dsi.fastutil.ints.IntSortedSet;
it.unimi.dsi.fastutil.longs.Long2ReferenceMap;
it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap;
it.unimi.dsi.fastutil.objects.Object2BooleanArrayMap;
it.unimi.dsi.fastutil.objects.Object2BooleanMap.Entry;
it.unimi.dsi.fastutil.objects.Object2BooleanMap;
it.unimi.dsi.fastutil.objects.Object2CharArrayMap;
it.unimi.dsi.fastutil.objects.Object2CharMap;
it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap;
it.unimi.dsi.fastutil.objects.Object2IntMap;
it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
it.unimi.dsi.fastutil.objects.Object2LongMap;
it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenCustomHashMap;
it.unimi.dsi.fastutil.objects.Object2ObjectMap;
it.unimi.dsi.fastutil.objects.Object2ObjectRBTreeMap;
it.unimi.dsi.fastutil.objects.Object2ObjectSortedMap.FastSortedEntrySet;
it.unimi.dsi.fastutil.objects.Object2ReferenceLinkedOpenHashMap;
it.unimi.dsi.fastutil.objects.ObjectIterator;
it.unimi.dsi.fastutil.objects.Reference2BooleanMap.Entry;
it.unimi.dsi.fastutil.objects.Reference2BooleanMap;
it.unimi.dsi.fastutil.objects.Reference2BooleanMaps;
it.unimi.dsi.fastutil.objects.Reference2BooleanOpenHashMap;
it.unimi.dsi.fastutil.objects.Reference2IntLinkedOpenHashMap;
it.unimi.dsi.fastutil.objects.Reference2IntMap.Entry;
it.unimi.dsi.fastutil.objects.Reference2IntMap;
it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
it.unimi.dsi.fastutil.objects.Reference2ReferenceMap;
it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;

Can probably do some basic analysis and see all the classes we need to support these uses and then toss everything else.

Col-E avatar Nov 20 '24 04:11 Col-E