Skip to content

feat: implement side-effect analysis relaxations to match rolldown behavior #12976

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Aug 10, 2025

This PR implements four key side-effect analysis relaxations in oxc to improve tree-shaking capabilities and match rolldown's behavior for better compatibility.

Background

Currently, oxc's side-effect analysis is overly conservative in several areas, preventing the removal of code that could safely be eliminated. This leads to larger bundle sizes compared to rolldown and other bundlers that have more sophisticated analysis.

Changes

1. Side-effect-free global constructors

Global constructors are now considered side-effect-free in specific argument shapes:

// These are now removable when unused:
new Map()
new Map([[key, value], ...])  // when all elements are arrays
new Map(null)
new Map(undefined)

new Set()
new Set([1, 2, 3])  // any array expression
new Set(null)
new Set(undefined)

new WeakMap()
new WeakSet()
new WeakMap(null)    // or undefined or []
new WeakSet([])

new Date()
new Date('2023-01-01')  // primitives only
new Date(123)
new Date(null)
new Date(undefined)

The constructors must be global references, and arguments are still evaluated for side effects.

2. Improved static class block analysis

Static class blocks now examine their content instead of assuming all non-empty blocks have side effects:

// Before: always considered side-effect-full
// After: can be removed when unused
class A {
  static {
    const x = 1;
    const y = 'hello';
  }
}

// Still considered side-effect-full (conservative)
class B {
  static {
    let x;        // TDZ effects
    this.prop = 1;  // assignment
  }
}

3. Known side-effect-free global member reads

Specific global property accesses are now whitelisted as side-effect-free:

// These reads are now side-effect-free:
Object.assign
Object.create
Object.prototype
Object.prototype.propertyIsEnumerable
JSON.stringify
Reflect.apply
Math.E
Symbol.asyncDispose

// Other reads still considered potentially side-effect-full:
Object.someOtherProp
Math.random

4. Symbol.iterator computed property keys

Computed property keys using Symbol.iterator are now side-effect-free:

// These are now side-effect-free:
const obj = { [Symbol.iterator]: function* () {} }
class MyClass { [Symbol.iterator]() {} }

5. Expanded global identifier whitelist

Added String and Proxy to the list of side-effect-free global identifier reads, joining NaN, Infinity, and undefined.

Testing

Added comprehensive test coverage for all new functionality:

  • 25+ test cases covering constructor relaxations
  • Tests for static block content analysis
  • Tests for global member read whitelisting
  • Tests for Symbol.iterator property keys
  • Tests for expanded identifier whitelist

All existing tests continue to pass, ensuring no regressions.

Impact

These changes will result in:

  • Better tree-shaking and smaller bundle sizes
  • Improved compatibility with rolldown behavior
  • More aggressive dead code elimination for common JavaScript patterns

The implementation maintains all existing configurability options and respects user preferences for side-effect analysis strictness.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copy link
Contributor

graphite-app bot commented Aug 10, 2025

How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • 0-merge - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

Copilot AI and others added 2 commits August 10, 2025 18:28
…tatic blocks, and member reads

Co-authored-by: sapphi-red <49056869+sapphi-red@users.noreply.github.com>
Co-authored-by: sapphi-red <49056869+sapphi-red@users.noreply.github.com>
@Copilot Copilot AI changed the title [WIP] ECMAScript side-effect analysis: relaxations for new Map/Set/WeakMap/WeakSet/Date, static class blocks, known global member reads, and [Symbol.iterator] keys feat: implement side-effect analysis relaxations to match rolldown behavior Aug 10, 2025
@Copilot Copilot AI requested a review from sapphi-red August 10, 2025 18:33
Copilot finished work on behalf of sapphi-red August 10, 2025 18:33
@github-actions github-actions bot added the A-minifier Area - Minifier label Aug 10, 2025
Copy link

codspeed-hq bot commented Aug 10, 2025

CodSpeed Instrumentation Performance Report

Merging #12976 will not alter performance

Comparing copilot/fix-3b7111b6-fa07-465e-a016-8b9080dba026 (6d087ef) with main (8c44a3d)

Summary

✅ 34 untouched benchmarks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-minifier Area - Minifier
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants