Repository navigation
perf(rewriter): defer transformer load to first rewrite - #10099
Conversation
Overall package sizeSelf size: 8.74 MB Dependency sizes| name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.4.0 | 127.33 kB | 447.04 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | dc-polyfill | 0.1.11 | 25.74 kB | 25.74 kB |🤖 This report was automatically generated by heaviest-objects-in-the-universe |
BenchmarksBenchmark execution time: 2026-09-02 19:57:46 Comparing candidate commit 655ed1c in PR branch Found 8 performance improvements and 0 performance regressions! Performance is the same for 2309 metrics, 11 unstable metrics.
|
|
BridgeAR
left a comment
There was a problem hiding this comment.
This is mainly LGTM! Thank you for the great startup improvement!
I just left two small suggestions for cleaning code up
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bdf7d1c9ab
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Co-authored-by: Ruben Bridgewater <ruben@bridgewater.de>
526ee45 to
655ed1c
Compare
* defer transformer load to first rewrite * Update packages/datadog-instrumentations/src/helpers/rewriter/index.js Co-authored-by: Ruben Bridgewater <ruben@bridgewater.de> * use variables instead of map --------- Co-authored-by: Ruben Bridgewater <ruben@bridgewater.de>
* defer transformer load to first rewrite * Update packages/datadog-instrumentations/src/helpers/rewriter/index.js Co-authored-by: Ruben Bridgewater <ruben@bridgewater.de> * use variables instead of map --------- Co-authored-by: Ruben Bridgewater <ruben@bridgewater.de>
* defer transformer load to first rewrite * Update packages/datadog-instrumentations/src/helpers/rewriter/index.js Co-authored-by: Ruben Bridgewater <ruben@bridgewater.de> * use variables instead of map --------- Co-authored-by: Ruben Bridgewater <ruben@bridgewater.de>
* defer transformer load to first rewrite * Update packages/datadog-instrumentations/src/helpers/rewriter/index.js Co-authored-by: Ruben Bridgewater <ruben@bridgewater.de> * use variables instead of map --------- Co-authored-by: Ruben Bridgewater <ruben@bridgewater.de>
What does this PR do?
Moves the vendored code transformer, the custom transforms and matcher construction out of
helpers/rewriter/index.jsmodule scope and behind a lazygetMatcher(moduleType), called fromrewrite()only after a file has matched a rewrite target and passed thedisabledcheck.Matchers are memoized per module type, so a CommonJS-only application never builds the ESM matcher
and vice versa. The
dc-polyfillspecifier is resolved as part of that construction rather than atload time.
require('./instrumentations')deliberately stays at module scope:helpers/instrument.jsloads thesame descriptors for any application that instruments anything, and keeping it there preserves the
proxyquireseam the rewriter unit tests are built on.Motivation
rewriter/index.jsis on the unconditional init path twice —helpers/register.jsrequires it fordisable(), andrewriter/loader.jsrequires it to install theModule.prototype._compilehook. Soevery application read, parsed and executed the 252 KiB (258,175 byte) transformer bundle, pulled in
./transforms→./compiler→vendor/dist/rfdc, and built both matchers, whether or not it everloaded a module the rewriter targets.
This is the follow-on to #9502, which deferred the ESM loader's require of the rewriter but left the
CommonJS loader and
register.jsloading it eagerly.require('./packages/datadog-instrumentations'), n=80 per arm, A/B interleaved in halves to cancelmachine drift, Node v25.8.0 darwin arm64:
before (module-scope init) mean=49.76ms median=49.56ms min=47.47ms
after (deferred to first rewrite) mean=43.73ms median=43.50ms min=41.75ms
6.03 ms / 12.1% off instrumentation load, and 69 → 65 modules resolved at init.
Additional Notes
create()itself measures 0.07 ms — the matcher is internally lazy, so nearly all of the win is thebundle require (~4.7 ms) plus
./transforms(~0.6 ms). The per-module-type splavoidable work rather than a measurable saving on its own.
One behavior change: construction is now wrapped in try/catch with the failure cached. Previously a
missing or broken bundle threw out of
require('dd-trace')for anyone not goininit.jsguardrails; now it logs once per module type and leaves rewriting off, per "never crash auser application."
New test
rewriter initialization › loads the code transformer on the first rew startupinstalls the real CommonJS loader hook in a child process and checksrequire.cachefor thebundle after the hook, after an untargeted dependency, and after a real
ai@4.0 asserting the rewrite fired. It fails on unchangedmasterwithloadedAfterHook: true, loadedAfterUntargetedModule: true`.Run locally:
mocha packages/datadog-instrumentations/test/helpers/rewriter/*.spec.{js,mjsst/loader-hook.spec.js— 52 passingnpm run test:instrumentations:misc— 185 passingmocha packages/datadog-instrumentations/test/webdriverio.spec.js— 44 passiPLUGINS=graphql SPEC=jit npm run test:plugins— 344 passingnpm run lint— clean under--max-warnings 0