# Tree Shaking Testing and Analysis

This document explains how to test and measure tree shaking effectiveness in this project.

## Overview

Tree shaking is a technique used by modern bundlers to eliminate unused code from your final bundle. This project has been optimized for tree shaking with:

- ✅ `"sideEffects": false` in `@selfxyz/common`
- ✅ ESM modules (`"type": "module"`)
- ✅ Granular exports in `package.json`
- ✅ Code splitting with tsup
- ✅ Optimized import patterns

## Quick Start

### 1. Test Tree Shaking Effectiveness
```bash
# Run comprehensive tree shaking tests
yarn test:tree-shaking

# This will create test apps with different import patterns and compare bundle sizes
```

### 2. Analyze Current Bundle
```bash
# Analyze import patterns in your codebase
yarn analyze:tree-shaking:imports

# Analyze web bundle after building
yarn web:build
yarn analyze:tree-shaking:web

# Analyze React Native bundles
yarn analyze:tree-shaking:android
yarn analyze:tree-shaking:ios
```

### 3. View Visual Bundle Analysis
```bash
# Build web app with visual analysis
yarn web:build

# Open dist/bundle-analysis.html in your browser
# This shows a treemap of your bundle with tree shaking results
```

## Understanding the Results

### Tree Shaking Test Output

The `yarn test:tree-shaking` command will show output like:

```
🧪 Testing: full-import
📝 Import everything from @selfxyz/common (worst case)
   📊 Bundle size: 2.45 MB

🧪 Testing: granular-constants
📝 Only constants via granular import (best case)
   📊 Bundle size: 156 KB

📊 TREE SHAKING EFFECTIVENESS REPORT
=====================================

Bundle Sizes (smallest to largest):
🏆 granular-constants    156 KB (93.6% smaller, saves 2.29 MB)
🥈 granular-utils        234 KB (90.4% smaller, saves 2.21 MB)
🥉 granular-mixed        267 KB (89.1% smaller, saves 2.18 MB)
📦 mixed-import          891 KB (63.6% smaller, saves 1.56 MB)
📦 full-import           2.45 MB

🎯 Maximum tree shaking benefit: 93.6% reduction (2.29 MB saved)
```

### Import Pattern Analysis

The import analyzer will categorize your imports:

- ⭐ **Namespace imports** (importing entire modules) - Prevents tree shaking
- 📝 **Named imports** (`import { ... }`) - Moderate tree shaking
- 🎯 **Granular imports** (`import { ... } from '@selfxyz/common/constants'`) - Best tree shaking

### Tree Shaking Score

You'll get a score based on your import patterns:
- 🟢 **80-100%** - Excellent (mostly granular imports)
- 🟡 **50-79%** - Good (mix of patterns)
- 🔴 **0-49%** - Poor (many star imports)

## Import Patterns

### ❌ Avoid: Star Imports
```typescript
// This imports everything, preventing tree shaking
import common from '@selfxyz/common';
console.log(common.API_URL);
```

### ⚠️ Moderate: Named Imports
```typescript
// Better, but could be more granular
import { API_URL, hash, buildSMT } from '@selfxyz/common';
console.log(API_URL);
```

### ✅ Good: Level 2 File-Based Imports
```typescript
// Good - granular file-level imports
import { API_URL } from '@selfxyz/common/constants/core';
import { hash } from '@selfxyz/common/utils/hash';
console.log(API_URL, hash('test'));
```

### 🚀 Recommended: Level 3 Function-Based Imports
```typescript
// ⭐ OPTIMAL - maximum granularity with clean re-exports
import { API_URL } from '@selfxyz/common/constants/core';
import { hash } from '@selfxyz/common/utils/hash/sha';
console.log(API_URL, hash('test'));
```

### ⚡ Level 2 Examples - Good Tree Shaking
```typescript
// Hash utilities only (no passport parsing, certificates, etc.)
import { hash, poseidon } from '@selfxyz/common/utils/hash';

// Passport operations only (no circuit generation, certificates, etc.)
import { generateCommitment } from '@selfxyz/common/utils/passports';

// Core constants only (no country data, vkey, etc.)
import { API_URL, PASSPORT_ATTESTATION_ID } from '@selfxyz/common/constants/core';

// App types only
import type { SelfApp } from '@selfxyz/common/types/app';
```

### 🚀 Level 3 Examples - Maximum Tree Shaking
```typescript
// ⭐ OPTIMAL: Function-level imports with clean re-exports
// Only specific hash functions (not entire hash module)
import { hash } from '@selfxyz/common/utils/hash/sha';
import { flexiblePoseidon } from '@selfxyz/common/utils/hash/poseidon';

// Only specific passport functions (not entire passports module)
import { generateCommitment } from '@selfxyz/common/utils/passports/commitment';
import { initPassportDataParsing } from '@selfxyz/common/utils/passports/core';

// Only specific circuit generators (not entire circuits module)
import { generateCircuitInputsDSC } from '@selfxyz/common/utils/circuits/dscInputs';

// ✅ 60-90% smaller bundles vs Level 2
// ✅ Zero regression risk from clean re-exports
```

## Available Import Paths

The `@selfxyz/common` package provides these granular imports:

### Level 1: Category-Based (Good)
```typescript
// Constants (URLs, country codes, etc.)
import { API_URL, countryCodes } from '@selfxyz/common/constants';

// Utility functions (hashing, parsing, etc.)
import { hash, generateCommitment } from '@selfxyz/common/utils';

// Type definitions (eliminated at compile time)
import type { PassportData } from '@selfxyz/common/types';
```

### Level 2: File-Based (Better - NEW!)
```typescript
// Core constants only (API URLs, attestation IDs)
import { API_URL, PASSPORT_ATTESTATION_ID } from '@selfxyz/common/constants/core';

// Country data only
import { countryCodes, commonNames } from '@selfxyz/common/constants/countries';

// Hash utilities only
import { hash, poseidon } from '@selfxyz/common/utils/hash';

// Passport utilities only
import { generateCommitment, generateNullifier } from '@selfxyz/common/utils/passports';

// Circuit utilities only
import { generateCircuitInputsDSC } from '@selfxyz/common/utils/circuits';

// Certificate parsing only
import { parseCertificateSimple } from '@selfxyz/common/utils/certificates';

// App-related types
import type { SelfApp } from '@selfxyz/common/types/app';

// Passport-related types
import type { PassportData } from '@selfxyz/common/types/passport';
```

### Complete Level 2 Import Reference

#### Constants
- `@selfxyz/common/constants/core` - API URLs, attestation IDs, basic constants
- `@selfxyz/common/constants/countries` - Country codes and names
- `@selfxyz/common/constants/vkey` - Verification keys
- `@selfxyz/common/constants/skiPem` - SKI PEM data
- `@selfxyz/common/constants/mockCerts` - Mock certificates
- `@selfxyz/common/constants/hashes` - Sample data hashes

#### Utilities

- `@selfxyz/common/utils/attest` - Proving Attestation Utils
- `@selfxyz/common/utils/hash` - Hash and Poseidon functions
- `@selfxyz/common/utils/bytes` - Byte manipulation
- `@selfxyz/common/utils/trees` - SMT and leaf operations
- `@selfxyz/common/utils/scope` - Endpoint formatting
- `@selfxyz/common/utils/proving` - Proving Utils
- `@selfxyz/common/utils/appType` - SelfApp definitions
- `@selfxyz/common/utils/date` - Date utilities
- `@selfxyz/common/utils/arrays` - Array helpers
- `@selfxyz/common/utils/passports` - Core passport functions
- `@selfxyz/common/utils/passportFormat` - Passport formatting
- `@selfxyz/common/utils/passportMock` - Mock passport generation
- `@selfxyz/common/utils/passportDg1` - DG1 specific operations
- `@selfxyz/common/utils/certificates` - Certificate parsing
- `@selfxyz/common/utils/elliptic` - Elliptic curve operations
- `@selfxyz/common/utils/curves` - Curve definitions
- `@selfxyz/common/utils/oids` - OID handling
- `@selfxyz/common/utils/circuits` - Circuit input generation
- `@selfxyz/common/utils/circuitNames` - Circuit name logic
- `@selfxyz/common/utils/circuitFormat` - Circuit formatting
- `@selfxyz/common/utils/uuid` - UUID utilities
- `@selfxyz/common/utils/contracts` - Contract utilities
- `@selfxyz/common/utils/sanctions` - OFAC/sanctions
- `@selfxyz/common/utils/csca` - CSCA operations

#### Types
- `@selfxyz/common/types/passport` - Passport and document types
- `@selfxyz/common/types/app` - SelfApp and disclosure types
- `@selfxyz/common/types/certificates` - Certificate data types
- `@selfxyz/common/types/circuits` - Circuit-related types

### Main export (less optimal for tree shaking)
```typescript
import { API_URL } from '@selfxyz/common';
```

## Testing Commands

### Basic Analysis
```bash
# Quick import pattern check
yarn analyze:tree-shaking:imports

# Full analysis including bundle sizes
yarn analyze:tree-shaking
```

### Platform-Specific Analysis
```bash
# Web bundle analysis (after yarn web:build)
yarn analyze:tree-shaking:web

# Mobile bundle analysis
yarn analyze:tree-shaking:android
yarn analyze:tree-shaking:ios
```

### Comprehensive Testing
```bash
# Test different import strategies with real bundlers
yarn test:tree-shaking

# Run all analysis tools
yarn analyze:tree-shaking all
```

## Continuous Integration

Tree shaking is automatically tested in CI:

1. **Bundle Size Monitoring**: Bundle analysis runs on every PR
2. **Size Thresholds**: Builds fail if bundles exceed size limits
3. **Visual Reports**: Bundle analysis HTML reports are generated

## Optimizing Your Code

### 1. Replace Star Imports
```diff
- import common from '@selfxyz/common';
+ import { API_URL } from '@selfxyz/common/constants';
+ import { hash } from '@selfxyz/common/utils';
```

### 2. Use Granular Imports
```diff
- import { API_URL, hash, countryCodes, buildSMT } from '@selfxyz/common';
+ import { API_URL, countryCodes } from '@selfxyz/common/constants';
+ import { hash } from '@selfxyz/common/utils';
```

### 3. Import Only What You Use
```diff
- import { generateCommitment, buildSMT, hash } from '@selfxyz/common/utils';
+ import { hash } from '@selfxyz/common/utils';  // Only import what you use
```

## Understanding Bundle Analysis

### Web Bundle Treemap
After running `yarn web:build`, open `dist/bundle-analysis.html` to see:
- Visual representation of your bundle
- Which modules are taking up space
- Tree shaking effectiveness by module

### React Native Bundle Reports
Bundle reports show:
- Total bundle size vs. thresholds
- Module-by-module breakdown
- Optimization opportunities

## Troubleshooting

### Tree Shaking Not Working?
1. Check `"sideEffects": false` in `package.json`
2. Use ESM imports (`import`), not CommonJS (`require`)
3. Avoid dynamic imports where possible
4. Check for circular dependencies

### Bundle Still Large?
1. Run `yarn analyze:tree-shaking:imports` to find star imports
2. Check the visual bundle analysis for large modules
3. Consider lazy loading for large features
4. Review vendor chunk sizes

### Different Results Between Platforms?
- React Native and Web use different bundlers
- Some optimizations only work on specific platforms
- Check platform-specific bundle configurations

## Examples

See the `/docs/examples/tree-shaking/` directory for:
- `level3-optimal-example.ts` - Shows Level 3 function-based imports (best)
- `level3-migration-guide.ts` - Migration guide from Level 2 to Level 3


## Further Reading

- [Tree Shaking Guide](https://webpack.js.org/guides/tree-shaking/)
- [ESM and Tree Shaking](https://developers.google.com/web/fundamentals/performance/optimizing-javascript/tree-shaking)
- [Vite Tree Shaking](https://vitejs.dev/guide/features.html#tree-shaking)
