Conversation
Replace Babel with acorn for AST parsing in the detector (~3-5x faster parsing), add a module resolution cache to skip redundant follow() calls, and batch independent fs.stat() calls with Promise.all(). The acorn parser tries module mode first, falling back to script mode for legacy packages using strict-mode-incompatible syntax (with statements, octal escapes). The resolution cache deep-clones markers on cache hit to prevent shared mutation from stepActivate. Benchmarked on zwave-js-ui: - SEA no-bundle (walker-heavy): -29.5% (38.5s → 27.2s) - SEA + bundle: -11.6% (10.1s → 9.0s) - Standard PKG + bundle: -11.6% (16.7s → 14.8s) Binary sizes unchanged. All 94 test-50-* tests pass. Closes #239 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Research Notes: Approaches Investigated & Future Optimization OpportunitiesDocumenting findings from the research phase to avoid re-investigating in the future. Worker Threads (investigated, NOT worth it)Prototyped a batch-by-level worker pool approach using
Results on zwave-js-ui:
Why it's slower: With acorn, per-file parse times are only ~1-2ms. The structured clone overhead per file (~0.1-0.5ms) + worker startup cost (~50-100ms total) outweighs the parallelism gain. Workers would have been worthwhile with Babel (~5-15ms per file) but not with acorn. Don't retry unless the detection step becomes significantly heavier. Also evaluated: Bundler Replacement (esbuild/Rolldown — investigated, NOT viable as walker replacement)The walker does far more than "find imports." Bundlers can't handle:
esbuild's Acorn Edge Cases (addressed in this PR)
Resolution Cache Edge Cases (addressed in this PR)The cache stores Future Optimization Opportunities (not in this PR)Ranked by estimated impact on zwave-js-ui:
|
Additional Investigation: Bytecode Parallelization & Async ResolutionParallel Bytecode Compilation (investigated, no improvement)Implemented a child process pool in Results on zwave-js-ui (Standard PKG + bundle):
Why no improvement: With esbuild pre-bundling, the build produces a single large JS file — there are very few STORE_BLOB stripes to parallelize. The bottleneck is compiling one big file, not many small ones. Parallelization would help on non-bundled builds with hundreds of JS files, but those typically fail on ESM projects anyway. Async Module Resolution (investigated, 5 test failures)Converted Result: 5 test failures ( Estimated gain was only 10-20% on the derivatives phase (which is already heavily cached). Not worth the regression risk. ConclusionThe three optimizations in this PR (acorn parser, resolution cache, batched I/O) represent the sweet spot — maximum gain with zero functional regressions. Further optimization would need to target the non-walker phases (compression, SEA blob assembly) or wait for a major architectural change (e.g., replacing the Multistream pattern with a pre-computed buffer approach). |
Summary
@babel/parser+@babel/generatorwith acorn in the dependency detector (~3-5x faster parsing)follow()calls for the same specifier from the same directoryfs.stat()calls withPromise.all()inappendFilesFromConfig()--debug)The acorn parser tries module mode first, falling back to script mode for legacy packages using strict-mode-incompatible syntax (
withstatements, octal escapes). The resolution cache deep-clones markers on cache hit to prevent shared mutation.@babel/*deps are retained —lib/esm-transformer.tsstill uses them.Benchmarks (zwave-js-ui)
Binary sizes unchanged. All 94
test-50-*tests pass.Test plan
yarn buildpassesyarn lintcleantest-50-*integration tests passCloses #239
🤖 Generated with Claude Code