Skip to content

feat(react-compiler): expose reactCompiler.environment.enableFunctionOutlining#12030

Open
imjordanxd wants to merge 2 commits into
swc-project:mainfrom
imjordanxd:feat/react-compiler-enable-function-outlining
Open

feat(react-compiler): expose reactCompiler.environment.enableFunctionOutlining#12030
imjordanxd wants to merge 2 commits into
swc-project:mainfrom
imjordanxd:feat/react-compiler-enable-function-outlining

Conversation

@imjordanxd

@imjordanxd imjordanxd commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Description:

The Babel React Compiler lets consumers configure environment options, but SWC's reactCompiler config previously exposed none of them — the compiler's EnvironmentConfig was always left at its defaults, unreachable from .swcrc.

This adds a curated environment object to the reactCompiler config that mirrors Babel's reactCompiler.environment shape. It currently exposes a single field, enableFunctionOutlining, wired through to EnvironmentConfig::enable_function_outlining:

{
  "jsc": {
    "transform": {
      "reactCompiler": {
        "environment": { "enableFunctionOutlining": false }
      }
    }
  }
}

The object is a deliberate allowlist rather than a passthrough of the full EnvironmentConfig: unset fields leave the compiler defaults untouched, so a partial object overrides only what it names, and the public surface stays small and intentional. New fields can be added one at a time as they are wired and tested.

EnvironmentConfig is re-exported from swc_ecma_react_compiler so the config layer can name the type (it was already reachable via the public PluginOptions.environment).

Tests:

  • unit test covering environment.enableFunctionOutlining deserialization;
  • fixture environment-function-outlining-disabled: with outlining off, a
    closure that captures a local binding stays inline;
  • fixture environment-function-outlining-enabled: with outlining on (default),
    a closure that captures nothing is outlined into a top-level helper.

BREAKING CHANGE:

None. environment is a new optional field; existing configs are unaffected.

Related issue (if exists):

N/A

Add a curated `environment` object to the reactCompiler .swcrc config that
currently exposes a single field, `enableFunctionOutlining`, wired through to
the compiler's EnvironmentConfig. Unset fields leave compiler defaults intact.

Re-export EnvironmentConfig from swc_ecma_react_compiler so the config layer
can name the type.

Tests:
- unit test for parsing environment.enableFunctionOutlining
- fixture -disabled: a closure capturing a local stays inline (correct)
- fixture -enabled: a non-capturing closure is outlined to a top-level helper

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@imjordanxd
imjordanxd requested a review from a team as a code owner July 17, 2026 04:59
@changeset-bot

changeset-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 265cca2

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@imjordanxd imjordanxd changed the title feat(swc): expose reactCompiler.environment.enableFunctionOutlining feat(swc): expose reactCompiler.environment.enableFunctionOutlining Jul 17, 2026
@imjordanxd imjordanxd changed the title feat(swc): expose reactCompiler.environment.enableFunctionOutlining feat(react-compiler): expose reactCompiler.environment.enableFunctionOutlining Jul 17, 2026
@codspeed-hq

codspeed-hq Bot commented Jul 17, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 189 untouched benchmarks
⏩ 61 skipped benchmarks1


Comparing imjordanxd:feat/react-compiler-enable-function-outlining (beffc05) with main (516bf3c)2

Open in CodSpeed

Footnotes

  1. 61 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on main (762e5d2) during the generation of this report, so 516bf3c was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@kdy1
kdy1 requested a review from magic-akari July 17, 2026 05:06

@magic-akari magic-akari left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

  1. Please use identical input examples for the enabled and disabled fixtures, changing only enableFunctionOutlining. The current inputs differ, so they cannot serve as a meaningful comparison.
    I tested this locally by reversing the enableFunctionOutlining values, and both tests still passed without any output changes.

  2. The JavaScript configuration exposes only enableFunctionOutlining, while the Rust API now publicly re-exports the entire react_compiler_hir::environment_config::EnvironmentConfig. Could you explain why the broader Rust API exposure is necessary?

Respond to review feedback on the enableFunctionOutlining exposure:

- Make the enabled/disabled function-outlining fixtures use an identical
  input so they differ only by the flag, and produce genuinely different
  output (inline callback vs. outlined top-level helper). The previous
  inputs differed, so they were not a meaningful comparison.
- Stop publicly re-exporting the upstream
  `react_compiler_hir::environment_config::EnvironmentConfig`; instead the
  config layer applies overrides via `&mut PluginOptions`, so only the
  curated field is exposed.
- Expose `environment.enableFunctionOutlining` in the `@swc/types` Node API
  so the typed surface matches the Rust `.swcrc` config.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@imjordanxd
imjordanxd requested a review from a team as a code owner July 20, 2026 00:44
@imjordanxd

Copy link
Copy Markdown
Contributor Author

Thanks for the review @magic-akari — you raised some good points!

1. Identical fixture inputs

You were right — the two fixtures used different inputs, so they never formed a real comparison. Both -enabled and -disabled now share the identical Counter input and differ only in enableFunctionOutlining, and the outputs genuinely diverge:

  • false → callback stays inline (t0 = function t0() { … }, _c(2))
  • true → callback outlined to a top-level _temp helper (_c(1))

On the "flipping the values changed nothing" observation — that's on me twice over: the old inputs were a poor demonstrator, and I hadn't documented that these fixtures only run under --features react-compiler (they early-return otherwise via the #[cfg(not(feature = "react-compiler"))] guard in projects.rs). With the shared input, this now shows the flag taking effect:

cargo test -p swc --features react-compiler environment_function_outlining

2. Rust API surface

Agreed — re-exporting the whole EnvironmentConfig was more than necessary. Reverted to a private use; the config layer now applies the override through &mut PluginOptions (already public), so only the curated enableFunctionOutlining is exposed.

Your question here also made me check the Node side, and I found @swc/types didn't type environment at all — it only worked at runtime via JSON pass-through. I've added environment.enableFunctionOutlining to ReactCompilerOptions, so the .swcrc and Node API surfaces now match, both exposing exactly that one field. Thanks for prompting that.

Pushed in beffc05e20.

@imjordanxd
imjordanxd requested a review from magic-akari July 20, 2026 00:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants