feat: use optional chaining in generated runtime code where supported#21186
Conversation
Add a RuntimeTemplate.optionalChaining helper that emits optional chaining when output.environment.optionalChaining is supported, and an equivalent && short-circuit otherwise. Use it in the load-script, auto-public-path and deferred-namespace runtime modules.
…sites Use RuntimeTemplate.optionalChaining in the chunk-loading (jsonp, import, readFile, require, importScripts), async-module, css-loading and module federation (remote/share/consume) runtime modules. Only convert property-access guards and method calls whose receiver is always object/array/null/undefined; keep `if (x)` guards where x can be a falsy non-nullish value (e.g. the `0` parent-callback sentinel), since optional chaining only short-circuits on null/undefined.
🦋 Changeset detectedLatest commit: 15c6491 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
This PR is packaged and the instant preview is available (793aae6). Install it locally:
npm i -D webpack@https://pkg.pr.new/webpack@793aae6
yarn add -D webpack@https://pkg.pr.new/webpack@793aae6
pnpm add -D webpack@https://pkg.pr.new/webpack@793aae6 |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #21186 +/- ##
==========================================
- Coverage 92.68% 92.68% -0.01%
==========================================
Files 587 588 +1
Lines 64011 64027 +16
Branches 17754 17760 +6
==========================================
+ Hits 59328 59341 +13
- Misses 4683 4686 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Cover both the optional-chaining and && fallback output for property, call, method and computed access forms.
Merging this PR will improve performance by ×2.2
Performance Changes
Tip Curious why this is faster? Comment Comparing |
The optional-chaining output shrinks the publicPath runtime below 1 KiB, so verbose/detailed stats now report it in bytes.
Optional-chaining output reduces the entry asset size by a few bytes.
The test harness executes generated bundles in the same Node.js process, and Node < 14 cannot parse `?.`. Default output.environment.optionalChaining to the running Node's capability in the Config/Watch/Test/Hot templates so old Node gets the `&&` fallback while modern Node still exercises `?.`.
Those cases assert the target-derived output.environment, so forcing optionalChaining off on Node < 14 broke their snapshots. Keep the Node version guard for the other (execution-based) config cases.
It executes the federation bundle (with `promise?.then`) in-process via vm, which Node < 14 can't parse; gate optionalChaining on the running Node.
Summary
output.environment.optionalChainingalready exists, but the generated runtime code almost never used it. This adds aRuntimeTemplate.optionalChaining(object, access)helper that emitsobj?.xwhen the target environment supports optional chaining and falls back to the existingobj && obj.xshort-circuit otherwise, then applies it across the runtime modules where it is safe (chunk loading for jsonp/import/readFile/require/importScripts, async modules, css loading, module federation remote/share/consume, load-script, auto-public-path, and deferred namespaces). No related issue.Only property-access guards and method calls whose receiver is always object/array/null/undefined are converted;
if (x)guards wherexcan be a falsy non-nullish value (e.g. the0parent-callback sentinel in the jsonp callback) are intentionally left as-is, because optional chaining only short-circuits onnull/undefined.What kind of change does this PR introduce?
feat
Did you add tests for your changes?
No new tests — the change only affects generated runtime code, which is executed end-to-end by the existing
HotTestCasesandConfigTestCasessuites. The&&fallback output is byte-identical to the previous code, and the?.output is exercised by the default modern-target runs; both were verified against baseline (no new failures).Does this PR introduce a breaking change?
No.
If relevant, what needs to be documented once your changes are merged or what have you already documented?
n/a
Use of AI
AI was used: Claude (Claude Code) helped locate candidate sites, write the
optionalChaininghelper and the edits, and run/compare the test suites. A test-driven review caught and reverted two unsafe conversions before submission. All changes were reviewed by me.Generated by Claude Code