Skip to content

build: Update swc_core to v77.0.0 - #654

Merged
Donny/강동윤 (kdy1) merged 7 commits into
mainfrom
kdy1/core77
Aug 15, 2026
Merged

build: Update swc_core to v77.0.0#654
Donny/강동윤 (kdy1) merged 7 commits into
mainfrom
kdy1/core77

Conversation

@kdy1

Copy link
Copy Markdown
Member

No description provided.

Releases:
  @swc/plugin-react-remove-properties@13.0.0
  @swc/plugin-styled-components@13.0.0
  @swc/plugin-transform-imports@13.0.0
  @swc/plugin-swc-confidential@12.0.0
  @swc-contrib/mut-cjs-exports@15.0.0
  @swc/plugin-remove-console@13.0.0
  @swc/plugin-styled-jsx@14.0.0
  @swc/plugin-swc-magic@13.0.0
  @swc/plugin-formatjs@10.0.0
  @swc/plugin-prefresh@13.0.0
  @swc/plugin-emotion@15.0.0
  @swc/plugin-swc-sdk@13.0.0
  @swc/plugin-relay@13.0.0
  @swc/plugin-jest@13.0.0
  @swc/plugin-loadable-components@12.0.0
  @swc/plugin-noop@13.0.0
  @swc/plugin-experimental-feature-flags@0.19.0
  @swc-contrib/plugin-graphql-codegen-client-preset@0.32.0

[skip ci]
@kdy1
Donny/강동윤 (kdy1) marked this pull request as ready for review August 14, 2026 13:30
@changeset-bot

changeset-bot Bot commented Aug 14, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: bcffd4e

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.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

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

@kdy1
Donny/강동윤 (kdy1) enabled auto-merge (squash) August 14, 2026 13:30
@kdy1

Copy link
Copy Markdown
Member Author

Claude (@claude) Fix CI failures

@claude

claude Bot commented Aug 14, 2026

Copy link
Copy Markdown

Claude finished Donny/강동윤 (@kdy1)'s task in 15m 10s —— View job


Fixed the Rust compile failures; one remaining failure is blocked upstream

  • Gather context (CI logs, failing jobs)
  • Identify root causes
  • Fix Function::body type change (Option<BlockStmt>Option<FunctionBody>)
  • Fix JSXText::value type change (AtomWtf8Atom)
  • Verify cargo check --workspace --all-targets (clean)
  • Verify cargo check with RUSTFLAGS="--cfg swc_ast_unknown" (clean)
  • Verify cargo test --all (81/81 test binaries pass locally)
  • Investigate wasm integration-test failures → blocked on an @swc/core release built on swc_core v77
  • Commit & push (f508d17)

What was broken

Two swc_core v77 AST breaking changes:

1. Function::body is now Option<FunctionBody>, not Option<BlockStmt>

FunctionBody is a new node (span + stmts, no ctxt, since a function body does not introduce its own block scope). Fixed in:

  • contrib/mut-cjs-exports/src/utils.rs:38, contrib/mut-cjs-exports/src/lib.rs:202
  • packages/loadable-components/src/lib.rs:387

For the four quote!(… as Stmt).expect_block() sites in loadable-components, quote! can only produce Expr / Pat / Stmt / AssignTarget / ModuleItem, so I added a small converter in packages/loadable-components/src/util.rs and wrapped the quoted bodies with it:

pub(crate) fn expect_fn_body(stmt: Stmt) -> FunctionBody {
    let block = stmt.expect_block();

    FunctionBody {
        span: block.span,
        stmts: block.stmts,
    }
}

2. JSXText::value is now Wtf8Atom, not Atom

.chars() no longer resolves. Fixed packages/styled-jsx/transform/src/visitor.rs:827 using as_atom() — text containing lone surrogates is not whitespace-only, so it is kept as a child (same effective behaviour as before):

if let Some(value) = txt.value.as_atom() {
    if value.chars().all(char::is_whitespace) {
        return false;
    }
}

Still failing: Integration Test (not fixable in this repo)

packages/formatjs and packages/emotion wasm tests fail with:

failed to run Wasm plugin transform … : Failed to deserialize program received from host
    swc_plugin_runner: 30.0.0
    Dependencies: … swc_ecma_ast 25.0.0 …

The host is the @swc/core devDependency, and it is older than the plugins:

swc_core swc_ecma_ast Function::body
plugins in this PR 77.0.0 29.0.0 Option<FunctionBody>
@swc/core@1.15.43 (lockfile) 71.0.3 25.0.0 Option<BlockStmt>
@swc/core@1.15.47 (latest published) 75.0.0 27.0.0 Option<BlockStmt>

Because Function is encoded field-wise across the plugin ABI, the host's BlockStmt body (span, ctxt, stmts) no longer decodes into the plugin's FunctionBody (span, stmts). That is exactly why only the fixtures containing functions/JSX fail while the rest pass — e.g. emotion is 1 failed | 7 passed.

Bumping the @swc/core devDependency does not help: 1.15.47 is the newest published version (and 1.15.47-nightly-20260729.1 the newest nightly), and both still use swc_ecma_ast 27 with Option<BlockStmt>. This job should go green once an @swc/core built on swc_core v77 is published and the lockfile is bumped to it. I did not touch the tests, since skipping them would hide a real incompatibility.

Notes

  • packages/formatjs/transform does not compile under --cfg swc_ast_unknown (two non-exhaustive match on JSXAttrName / PropName). This is pre-existing — swc_plugin_formatjs, swc_formatjs_transform, swc_plugin_styled_jsx and styled_jsx are excluded from that CI job — so I left it alone.
  • packages/loadable-components/tests/fixture.rs:66 has pre-existing cargo fmt drift. I reverted rustfmt's change there to keep this commit scoped to the CI fix.
    • branch kdy1/core77

@claude

claude Bot commented Aug 14, 2026

Copy link
Copy Markdown

Review — build: Update swc_core to v77.0.0

The release plumbing in this PR is correct, but unlike #649 (v76) this bump is not a pure version bump: swc_core v77 ships two breaking AST changes, and the workspace no longer compiles. Details, with a verified patch, below.

🔴 Blocking — the workspace does not compile

Check (swc_ast_unknown) is red, but this is not cfg-specific — I reproduced it locally at this PR's head with a plain cargo check --workspace --all-targets (no RUSTFLAGS): 8 errors in 3 crates. All test jobs (Test - ubuntu/windows, both Integration Tests) are now failing too.

1. Function::body / Constructor::body changed from Option<BlockStmt> to Option<FunctionBody> (swc_ecma_ast 28 → 29). FunctionBody { span, stmts } is a brand-new struct — there is no From<BlockStmt> impl, so .into() won't rescue it. Sites:

file lines
contrib/mut-cjs-exports/src/utils.rs 38 (let body = BlockStmt {) → used at 49
contrib/mut-cjs-exports/src/lib.rs 202
packages/loadable-components/src/lib.rs 387, plus 427 / 465 / 497 / 530 (quote!(… as Stmt).expect_block() yields a BlockStmt)

For the two struct-literal sites the field sets are identical, so it's a one-word swap (BlockStmt {FunctionBody {; FunctionBody also derives Default). For the four quote! sites a tiny local helper keeps them readable:

trait IntoFunctionBody {
    fn into_function_body(self) -> FunctionBody;
}

impl IntoFunctionBody for BlockStmt {
    fn into_function_body(self) -> FunctionBody {
        FunctionBody {
            span: self.span,   // keep the real span, not DUMMY_SP,
            stmts: self.stmts, // so codegen/source maps don't shift
        }
    }
}

…then .expect_block().into_function_body().

2. JSXText::value changed from Atom to Wtf8Atom, which has no chars()packages/styled-jsx/transform/src/visitor.rs:827:

-if txt.value.chars().all(char::is_whitespace) {
+if txt.value.as_atom().is_some_and(|s| s.chars().all(char::is_whitespace)) {

as_atom() (already the idiom used in contrib/mut-cjs-exports/src/utils.rs:130) returns None only for non-UTF-8 text, and a lone surrogate is never whitespace, so is_some_and preserves the old behaviour exactly.

Worth noting for triage: styled_jsx and swc_formatjs_transform are excluded from the Check (swc_ast_unknown) job, so this second breakage never appears in that job's log — it only surfaces under cargo test --all. Might be worth revisiting those exclusions.

Verified: with just those four files patched as above, cargo check --workspace --all-targets is clean (0 errors) and cargo test -p swc_plugin_loadable_components -p swc_mut_cjs_exports -p styled_jsx passes 234/234 with no snapshot churn — so the AST migration is output-preserving.

🔴 Blocking — host/plugin ABI: @swc/core also needs bumping

Both Integration Test jobs fail with:

failed to invoke …/swc_plugin_emotion.wasm as js transform plugin … Please ensure the version of swc_core used by the plugin is compatible with the host runtime

That's not a code bug: the tests rebuild each plugin from source (now on swc_core 77) and run it through the root @swc/core dev dependency, which pnpm-lock.yaml pins at 1.15.43 (published 2026-06-22, i.e. the v76-era host). Neither the root package.json nor pnpm-lock.yaml is touched in this PR.

This matters beyond CI: publishing plugins built on swc_core v77 while no compatible @swc/core release exists would leave every published .wasm unloadable for users until they upgrade the host. Please bump @swc/core (latest is 1.15.47) to whichever release embeds swc_core v77, refresh the lockfile, and confirm the integration tests go green before publishing — or hold the PR until such a release is out.

🟡 Non-blocking — new warnings introduced by the bump

  • 6 × use of deprecated type alias BlockStmtOrExprArrowFunctionBody (block variant is now ArrowFunctionBody::FunctionBody): packages/styled-components/transform/src/visitors/transpile_css_prop/transpile.rs:232,273 and packages/swc-sdk/transform/src/lib.rs:6,161,187,240. All are ::Expr(...) uses, so this is a mechanical rename — and since this release is already breaking, it's a cheap moment to do it.
  • 2 × unreachable_patterns in crates/swc_feature_flags/src/stats.rs:114,164Lit and Callee are now fully covered by the explicit arms in default builds. ⚠️ Please don't just delete the _ arms: they are reachable under --cfg swc_ast_unknown (that job emits no such warning), so an #[allow(unreachable_patterns)] or a cfg-gated arm is the safe fix.

✅ Release metadata — checked, all good

  • Cargo.lock is in sync with every bumped member (swc_core 77.0.0, swc_ecma_ast 29.0.0, all 16 bumped workspace crates) — a --locked build won't trip.
  • All { path = …, version = … } requirements match the bumped crate versions (34 crates scanned, 0 mismatches), including the two-level ones like swc_icu_messageformat_parser 36.0.0 in packages/formatjs/transform.
  • Changeset severity is right per package: major for ≥1.0 packages, minor for the 0.x ones (@swc-contrib/plugin-graphql-codegen-client-preset 0.31→0.32, @swc/plugin-experimental-feature-flags 0.18→0.19).
  • CHANGELOG→README merge is consistent with each package's existing convention; the three packages without a README section (swc-confidential, mut-cjs-exports, graphql-codegen-client-preset) have never carried one, so nothing missing there.
  • Unpublished cdylib wrapper crate versions (0.19.4 etc.) correctly left untouched.

Test coverage

No new tests are needed for the bump itself, and existing fixtures already cover both migration sites (they caught nothing only because the code doesn't compile yet). The one thing to watch is span fidelity: when converting BlockStmtFunctionBody, carry block.span through rather than DUMMY_SP — with the span preserved, all 234 tests in the affected crates pass unchanged.


Summary: metadata and versioning are solid; this needs (a) the ~10-line AST migration in 4 files, and (b) an @swc/core host bump before the plugins can be published.

- `Function::body` is now `Option<FunctionBody>` instead of `Option<BlockStmt>`
- `JSXText::value` is now `Wtf8Atom` instead of `Atom`

Co-authored-by: Donny/강동윤 <29931815+kdy1@users.noreply.github.com>
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ kdy1
❌ github-actions[bot]
You have signed the CLA already but the status is still pending? Let us recheck it.

@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown

Review: build: Update swc_core to v77.0.0

Mostly a mechanical version bump, but it carries three real adaptations to upstream API breaks. I pulled the swc_ecma_ast@29.0.0, swc_atoms@10.0.0 and swc_ecma_quote_macros@45.0.0 sources to verify each one. All three look correct; everything below is a nit or a follow-up suggestion, nothing blocking.

FunctionBody split from BlockStmt

In v77, Function::body, Constructor::body and the block variant of arrow bodies (ArrowFunctionBody::FunctionBody, with BlockStmtOrExpr now a deprecated alias) are all FunctionBody { span, stmts } — note it has no ctxt field, unlike BlockStmt.

  • packages/formatjs/transform/src/lib.rs:1440 — adding visit_mut_function_body is exactly right and is a required change, not a cosmetic one: visit_mut_block_stmt used to fire for function/arrow/constructor bodies, so without this, bindings declared inside function bodies would silently stop being collected. __tests__/wasm.test.ts:182 ("static vars in function") covers that path, and since arrow and constructor bodies are also FunctionBody, coverage parity with the old behavior is preserved. StaticBlock is still a BlockStmt, so visit_mut_block_stmt remains needed too — both are correctly kept.
    • Nit: the two visitors are now identical 4-line bodies. Consider fn collect_stmts_bindings(&mut self, stmts: &[Stmt]) and calling it from both.
  • packages/loadable-components/src/util.rs:7 — the doc comment is accurate: quote! only supports Expr/Pat/Stmt/AssignTarget/ModuleItem (swc_ecma_quote_macros/src/ret_type.rs), so a StmtFunctionBody adapter really is the only option, and there's no From<BlockStmt> for FunctionBody upstream. Using block.span is right (FunctionBody::span is documented as "span including the braces"). The dropped BlockStmt::ctxt is a non-issue — the parser emits an empty ctxt for quoted code and Function::ctxt is what carries hygiene now. The refactor also removes four levels of indentation, which is a nice readability win.
  • contrib/mut-cjs-exports/src/{lib.rs,utils.rs} — both literals use ..Default::default(), so no stale span/ctxt hand-wiring. Good.

JSXText::value is now Wtf8Atom

packages/styled-jsx/transform/src/visitor.rs:828 — correct. Wtf8Atom::as_atom() returns Some iff the content is valid UTF-8, so for every input reachable today the filter behaves identically to the old &str version, and the fallback (treat non-UTF-8 text as non-whitespace) is the safe direction.

Two small notes:

  • Wtf8Atom derefs to Wtf8, so you can skip the atom wrapper and flatten the nesting: if let JSXElementChild::JSXText(txt) = child { if txt.value.as_str().is_some_and(|s| s.chars().all(char::is_whitespace)) { return false; } }.
  • Behavior worth being explicit about: a <style> child whose text contains a lone surrogate (reachable via a JSX entity like &#xD800;) is now counted as a child, so it trips the Expected one child under JSX style tag diagnostic instead of being dropped. That's the defensible choice, but it's untested — a fixture with an entity-escaped lone surrogate would lock in the intent behind the comment.

Versioning / release metadata

  • All published crates move consistently onto their next major (17.0.0 for the transform crates, 28.0.0 mut-cjs-exports, 36.0.0 messageformat parser, 40.0.0 formatjs transform); no crate on the old train was left behind. The wasm cdylib root crates keep their independent 0.x versions, matching existing practice.
  • graphql-codegen-client-preset (0.31→0.32) and feature-flags (0.18→0.19) getting Minor headings while everything else is Major is just changesets mapping major→minor for pre-1.0 packages — consistent, not a mistake.
  • Cargo.lock has no duplicated swc_* versions, which is the failure mode that usually bites on these bumps (two swc_commons in one wasm artifact). Checked.
  • contrib/mut-cjs-exports/package.json:44 bumps the @swc/core peer to ^1.16.0. That lines up: swc_core@77.0.0 was published 2026-08-14 13:12Z and @swc/core@1.16.0 2026-08-14 17:23Z. It's also the only package in the repo that declares an @swc/core peer range — every other plugin ships a wasm artifact ABI-locked to swc_core 77 with no declared host constraint, so users still on 1.15.x get a raw plugin-version-mismatch error instead of a resolution warning. Out of scope here, but since this recurs on every core bump it might be worth adding peer ranges repo-wide (or automating it in scripts/update-swc-core.sh).

Snapshots, tests, CI

  • The emotion / styled-components wasm snapshot deltas (if (!raw) raw = strings.slice(0);, } else obj[key] = value;) are host-side codegen changes — brace elision for single-statement if/else in the helpers emitted by @swc/core 1.16, not plugin output changes. Worth a sanity confirmation that this is the intended upstream change rather than something to report back to swc, but it looks deliberate.
  • cargo test --all is green on ubuntu and the swc_ast_unknown check passes. When I looked, Integration Test (ubuntu/macos) and Test - windows-latest were still pending — those are the jobs that actually exercise the formatjs visitor change and the wasm snapshots, so they're the ones to wait on. Note Check (swc_ast_unknown) excludes styled_jsx/swc_plugin_styled_jsx (pre-existing), so the Wtf8Atom change in styled-jsx isn't covered under that feature combination.
  • Performance: no new allocations or clones on any hot path. as_atom() is a borrow-only check, and the extra visit_mut_function_body replaces work that visit_mut_block_stmt previously did — net neutral.
  • Security: no new direct dependencies; the lockfile churn is all transitive patch/minor bumps, and Socket's PR alerts came back clean.

Nothing here needs to block the merge — just the two readability nits (dedupe the formatjs visitors, as_str() in styled-jsx) and, if you want it, a lone-surrogate fixture for the styled-jsx edge case.

@kdy1
Donny/강동윤 (kdy1) merged commit a93bcc0 into main Aug 15, 2026
10 of 11 checks passed
@kdy1
Donny/강동윤 (kdy1) deleted the kdy1/core77 branch August 15, 2026 02:30
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