docs/node-modules-optimization.md
This document captures the analysis and optimization strategies for reducing Bit's node_modules size in BVM (Bit Version Manager) distributions, based on investigation conducted in September 2025.
Monaco Editor: 77MB total
dev/ folder: 34MBesm/ folder: 20MBmin-maps/ folder: 11MBmin/ folder: 11MB (production-ready, minified)Source Maps: 124MB total (14,697 files)
date-fns: 24MB total
@teambit packages: 339MB (core functionality)
Added overrides to consolidate duplicate packages:
"postcss@8": "^8.4.19""ajv@6": "^6.12.6"Tested savings: 16.9MB reduction in fresh installations
Note: Using version-specific keys (e.g., postcss@8) to handle conflicting major versions
scripts/cleanup-node-modules.js: Post-install optimization script.circleci/config.yml: Integrated cleanup into bundle jobsdev/, esm/, min-maps/ folders, keeps min/ (~64MB saved)node_modules/@types directory (~17MB saved)--dry-run: Preview changes--keep-source-maps: Keep all source maps--keep-teambit-maps: Keep only @teambit source maps for debugging--remove-esm: Remove duplicate ESM builds (keep CJS for current Bit)--remove-cjs: Remove duplicate CJS builds (keep ESM for future migration)--remove-source: Remove source directories when compiled versions exist--verbose: Detailed outputSee Results section below for detailed measurements.
node-linker=hoisted reduces size from ~1.2GB to ~800MB by avoiding nested .pnpm duplicatesdate-fns (24MB) only needed for bit start --dev, not productionbit start uses pre-built bundles; bit start --dev rebuilds via webpackbundle_version_linux (x64 and arm64)bundle_version_macos (x64 and arm64)bundle_version_windows (x64)Created optimize_node_modules command with optional platform parameter for DRY code.
Setup Job: setup_bundle_simulation (runs once)
pnpm add @teambit/bit with hoisting + overrides)Test Job: e2e_test_bundle_simulation (parallelized 25x)
bit-cleaned binary link (avoids conflicts with repo binary)e2e-test-results-cleaned.xml)Triggers: Both jobs only run on branches matching patterns:
optimize-node-modules*cleanup-script**cleanup*script*This approach optimizes CI by doing expensive setup once while maintaining full parallel test coverage. Ensures cleanup script changes are thoroughly tested before production deployment without affecting regular CI runs.
bit start works without UI deps (uses pre-built bundles)bit start --dev requires UI deps (rebuilds bundles dynamically)bit status, bit compile, etc.) work after cleanup@types Directory Removal (Safe - 17MB saved)
The node_modules/@types directory can be safely removed from BVM installations because:
Cleanup Implementation: The cleanupTypeDefinitions() function automatically removes the entire @types directory without requiring a flag, as this optimization is safer than UI dependency removal and has minimal impact on functionality.
Attempted to use esbuild bundling (PR #7180) to generate a definitive list of required files via metafile analysis.
Results:
Conclusion: While esbuild provides tree-shaking insights, it doesn't represent the full runtime requirements for a production CLI tool. The approach was abandoned in favor of targeted package analysis.
bit start --dev unavailable in BVM installs--dev modedate-fns from BVMbit ci merge or tag: UI components bundled via webpackbit start: Serves pre-built bundlesbit start --dev: Rebuilds bundles dynamically--keep-teambit-maps for BVM releasesdate-fns and other UI-only dependencies from BVM--dev mode limitations for BVM usersOriginal approach using execSync with find command failed due to ENOBUFS error when scanning 14,697+ files. Fixed by implementing recursive filesystem traversal.
Updated (September 2025): Changed from du command to Node.js fs.statSync() for size calculations:
du -sk (macOS) / du -sb (Linux) - reported disk usage (allocated blocks)fs.statSync().size - reports logical file size (actual bytes)--keep-teambit-mapsBased on macOS testing (September 2025):
| Scenario | Final Size | Space Saved | Reduction | Breakdown |
|---|---|---|---|---|
| Default mode | 507.8 MB | 186.6 MB | 26.9% | Monaco: 62.3MB, Maps: 101MB, @types: 17MB, Locales: 14.6MB |
| With --keep-teambit-maps | 534.1 MB | 160.3 MB | 23.1% | Monaco: 62.3MB, Maps: 74.7MB, @types: 17MB, Locales: 14.6MB |
| With --remove-esm | 483.9 MB | 210.5 MB | 30.3% | Monaco: 62.3MB, Maps: 101MB, @types: 17MB, Locales: 14.6MB, Duplicate ESM: 15.7MB |
| With --remove-source | 488.9 MB | 205.5 MB | 29.6% | Monaco: 62.3MB, Maps: 101MB, @types: 17MB, Locales: 14.6MB, Source: 10.7MB |
| With --remove-ui-deps | 491.7 MB | 202.7 MB | 29.2% | Monaco: 62.3MB, Maps: 101MB, @types: 17MB, Locales: 14.6MB, UI: ~8MB |
Total optimization potential: 786.9 MB → 465.3 MB (321.6 MB saved, 40.9% reduction) with all flags
Note: Results based on logical file size calculation using Node.js fs.statSync() rather than disk usage
esm/ and cjs/ folders (e.g., @modelcontextprotocol/sdk, @sinclair/typebox).mjs and .mjs files (e.g., Prettier plugins)zod/src/ + v3/, moment/src/ + min/)src/ when compiled versions existdate-fns, react-syntax-highlighter, d3-* only needed for bit start --dev