avelino / avelino/jbundle

Smart resource reachability analysis for shrink

Open
#17 0 comments 0 reactions 0 assignees View on GitHub
area/jlink performance
Dominant language
Rust
Stars
181
Forks
11
PR merge metrics
No merged PRs in 30d

Description

## Problem

The current `--shrink` flag uses a heuristic approach — it removes known-unnecessary files by pattern (`.git`, `LICENSE`, SCM metadata, etc.). This is safe but leaves significant optimization potential on the table. Many resources inside uberjars are never accessed at runtime but cannot be identified by simple pattern matching.

## Inspiration

GraalVM's native-image performs [reachability analysis](https://www.graalvm.org/latest/reference-manual/native-image/guides/optimize-native-executable-size-using-build-report/) on resources — only resources that are actually referenced by reachable code are included in the final binary. Their build reports show that erroneous resource inclusion (e.g., overly broad regex patterns in resource configuration) is one of the most common causes of bloated binaries.

Their [size optimization guide](https://www.graalvm.org/latest/reference-manual/native-image/guides/optimize-for-file-size/) demonstrates that removing unreachable resources and code can reduce binary size by 40%+ in some cases.

## Expected Outcome

An enhanced `--shrink` that goes beyond pattern matching to perform actual analysis of resource usage:

### Analysis Layers

1. **Class reference analysis**: scan bytecode for `getResource()`, `getResourceAsStream()`, and similar calls to identify which resources are actually loaded
2. **Namespace dependency analysis**: for Clojure AOT classes, trace namespace require chains to identify orphan namespaces (dev/test utilities bundled in production)
3. **Duplicate detection**: find identical files included multiple times from different dependencies (common with `LICENSE`, `NOTICE`, `META-INF/services`)
4. **Native library analysis**: detect platform-specific native libs for other platforms (e.g., Linux binary bundling `.dll` files from a Windows dependency)
5. **Dev-dependency detection**: identify resources from dependencies that are typically dev-only (test frameworks, REPL utilities, documentation generators)

### Shrink Levels

```bash
jbundle build --shrink # current behavior (safe patterns only)
jbundle build --shrink aggressive # add reachability analysis
jbundle build --shrink report # show what would be removed without removing
```

### Categories of Removable Content

| Category | Example | Risk |
|---|---|---|
| SCM metadata | `.git/`, `.svn/`, `pom.properties` | None |
| Duplicate licenses | Multiple `LICENSE.txt` from deps | None |
| Wrong-platform natives | `.dll` in Linux build, `.dylib` in Linux | None |
| Unreferenced resources | XML configs for unused features | Low |
| Dev/test namespaces | `*-test.class`, `dev/*.class` | Low |
| Unused service providers | `META-INF/services/` for unused interfaces | Medium |
| Unused class files | Classes from deps never referenced | Medium |

### Safety Mechanism

- `--shrink` (no argument) remains safe and conservative (current behavior)
- `--shrink aggressive` performs deeper analysis but may break apps with highly dynamic resource loading
- `--shrink report` (or integration with `analyze`) shows potential savings without removing anything
- Allow `--shrink-keep ` to whitelist resources that analysis marks as removable but the user knows are needed

## Impact Estimate

For a typical Clojure web application uberjar:
- Current `--shrink`: removes ~5-15% (metadata, licenses, SCM)
- With reachability analysis: could remove ~20-40% (unused deps, wrong-platform natives, dev resources)

Contributor guide

Open the contributing guide

Research direction

Begin by tracing the existing `jbundle build --shrink` entry point and its current pattern-based behavior. Compare the requested `aggressive`, `report`, and `--shrink-keep` modes against the five analysis layers; done would preserve conservative default behavior while providing validated reachability-based removal and reporting. The issue names no files or tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
clojure, java, rust
Domain
build-system, performance
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.