Skip to content

startup: Cache packaged ESM ASAR resolutions - #334769

Open
Dmitriy Vasyura (dmitrivMS) wants to merge 2 commits into
mainfrom
agents/cache-asar-resolutions
Open

startup: Cache packaged ESM ASAR resolutions#334769
Dmitriy Vasyura (dmitrivMS) wants to merge 2 commits into
mainfrom
agents/cache-asar-resolutions

Conversation

@dmitrivMS

@dmitrivMS Dmitriy Vasyura (dmitrivMS) commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • cache successful packaged ESM resolutions into node_modules.asar
  • key entries by specifier, normalized parent path, conditions, and import attributes
  • preserve closer-dependency precedence on the first resolution and avoid caching defaults or failures
  • add a packaged ASAR integration fixture that verifies hits are reused but isolated by parent

The cache is process-local and lives for the process lifetime, so it also helps repeated dynamic imports after startup. CommonJS, built-ins, Electron modules, external extension paths, closer dependencies, and failed resolutions are unchanged.

Performance

The motivating main-process trace found 33 ASAR resolution attempts from out/main.js for seven unique specifier-parent pairs, including 15 resolutions of @vscode/spdlog and eight of @vscode/policy-watcher.

Packaged resolver benchmark

40 alternating baseline/cached Electron runs, excluding five warmups, shaped as 33 import sites over seven unique contexts:

Metric Baseline Cached Change
Resolution workload median 44.184 ms 19.172 ms -25.012 ms / -56.61%
Electron process median 135.250 ms 109.649 ms -25.601 ms / -18.93%
Archive lookups 33 7 -78.79%

Main-process CPU profiles

Six packaged launches per variant, excluding one warmup:

Metric Baseline Cached Change
Active main CPU median 378.879 ms 360.334 ms -18.545 ms / -4.89%
Attributed JavaScript median 366.230 ms 347.248 ms -18.982 ms / -5.18%
internalModuleStat median 12.605 ms 4.880 ms -61.29%
Profiled elapsed median 1,926 ms 1,892 ms -1.77%

The profiler adds roughly 33-35% overhead in this local Code OSS package, so the CPU deltas are more reliable than the profiled wall-time delta.

Full packaged startup

Ten unprofiled launches per variant, excluding one warmup:

  • warm median: 1,422 ms -> 1,418 ms (-4 ms / -0.28%)
  • warm mean: 1,425.67 ms -> 1,408.67 ms (-1.19%)
  • run CV: 1.89% baseline, 1.55% cached

The median wall-time change is below run variance, so this PR does not claim a statistically significant end-to-end startup improvement. The demonstrated benefit is reduced resolver and main-process CPU, including for later repeated imports.

For the full-package A/B, the baseline forced the generated cache lookup to miss while retaining the small key/map overhead; every other application byte was identical. The standalone resolver benchmark compares the exact pre-change and changed bootstrap revisions.

Validation

  • npm run typecheck-client
  • targeted ESLint
  • focused bootstrap ESM tests: 6 passing
  • full vscode-win32-x64-min package build
  • packaged Code OSS startup A/B
  • git diff --check

Reuse successful archive resolutions for identical ESM contexts while preserving first-resolution precedence for closer dependencies. Cover cache hits and parent isolation with a packaged ASAR fixture.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The non-injective cache key can incorrectly reuse resolutions across distinct contexts.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review tier: Balanced
Findings: 1 High severity

New issues introduced by this change (1)
Severity Finding
High severity src/​bootstrap-esm.ts — The flattened key is not injective: conditions [..., &#39;type&#39;, &#39;json&#39;] with no attributes produce…
What changed in this PR

Adds process-local caching for packaged ESM ASAR resolutions.

Changes:

  • Caches resolutions by specifier, parent, conditions, and attributes.
  • Preserves closer-dependency precedence.
  • Adds packaged-ASAR integration coverage.

A critical cache-key collision can return incorrect resolutions; collections need structural encoding and regression coverage. Direct fallback caching for packages without exports also lacks coverage.

File Description
src/​vs/​code/​test/​node/​bootstrapESM.test.ts Adds cache reuse and parent-isolation tests.
src/​bootstrap-esm.ts Implements caching; requires collision-safe keys and fallback-path coverage.
Suppressed comments (1)

src/bootstrap-esm.ts:196

  • The new test package declares exports, so it only exercises the self-reference cache write above; this direct fallback cache path for packages without exports remains untested. Add a second archived package without exports and assert that repeated imports produce one archive lookup followed by a cache hit.
					const result = { url, shortCircuit: true };
					resolutionCache.set(cacheKey, result);

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/bootstrap-esm.ts
Encode conditions and import attributes as separate structural tuple fields and cover the boundary collision with conditional exports.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants