Skip to content

feat: scaffold parallel SWC v2 npm API#12015

Open
kdy1 wants to merge 4 commits into
swc-project:mainfrom
kdy1:kdy1/swc-v2-parallel-packages
Open

feat: scaffold parallel SWC v2 npm API#12015
kdy1 wants to merge 4 commits into
swc-project:mainfrom
kdy1:kdy1/swc-v2-parallel-packages

Conversation

@kdy1

@kdy1 kdy1 commented Jul 11, 2026

Copy link
Copy Markdown
Member

Description:

Establishes the repository and release structure needed to develop the SWC v1 and v2 npm APIs together on main without duplicating the Rust engine.

  • Adds the private swc_api_common crate for version-neutral compiler operations and direct version-selected AST wire encoding.
  • Keeps the existing Node and Wasm bindings as the v1 compatibility layer and adds separate v2 Node and Wasm binding packages.
  • Adds private core-v2 and types-v2 workspace sources. Removed v2 APIs such as bundle() and print() are not exported from the v2 facade.
  • Adds canonical npm release staging for @swc/core, platform packages, @swc/types, and @swc/wasm at a synchronized 2.x prerelease version.
  • Adds major-aware npm dist-tag enforcement, with v1 on latest and v2 previews on next.
  • Adds advisory v2 native and Wasm CI lanes, v1/v2 output comparisons, AST round-trip coverage, package identity checks, and schema-v1 plugin execution through the v2 native host.

This PR provides isolated v2 config and AST codec boundaries so milestone-specific API cleanup can be landed incrementally while v1 development continues against the same engine.

Existing v1 npm and Rust public APIs remain unchanged.

Validation:

  • cargo fmt --all
  • cargo clippy --all --all-targets -- -D warnings
  • cargo test -p swc_api_common
  • Existing packages/core build and test suite
  • v2 native API, AST round-trip, and v1 plugin compatibility tests
  • v1 and v2 Wasm binding test scripts
  • v2 staging, dist-tag, canonical loader, and tarball checks

Related issue (if exists):

@kdy1 kdy1 requested a review from a team as a code owner July 11, 2026 04:28
@changeset-bot

changeset-bot Bot commented Jul 11, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 6cc187a

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6cc187a009

ℹ️ 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".

set -euo pipefail
case "$PACKAGE" in
core | html | minifier | react-compiler) ;;
core | core-v2 | html | minifier | react-compiler) ;;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Add a root test script for core-v2

When publish-npm-v2-preview.yml invokes this reusable workflow with package: core-v2, the Linux binding test jobs pass this allow-list and later run pnpm "test:${PACKAGE}" from the repository root inside Docker. At this commit the root package.json only defines test:core, not test:core-v2, so both Linux binding test jobs fail with a missing script and publish-core never reaches the publish step. Add a root test:core-v2 script or special-case these jobs to run the package-local test command.

Useful? React with 👍 / 👎.

Comment on lines +16 to +17
#[cfg(all(not(feature = "api_v1"), not(feature = "api_v2")))]
compile_error!("Please enable api_v1 or api_v2 feature");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve no-default v1 binding builds

This new requirement breaks the existing publish matrix entries in .github/workflows/publish-npm-package.yml that build @swc/core with --no-default-features --features swc_v1 or swc_v1,plugin for several targets; those commands do not enable api_v1, so the build script now emits this compile_error! before any v1 artifact is built. Either make the swc_v1 feature imply api_v1 or update every no-default-features core build to pass api_v1.

Useful? React with 👍 / 👎.

import type { Options } from "@swc/types";

/** Public configuration accepted by the v2 JavaScript API. */
export type V2Options = Options;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don't advertise ignored JS plugins

Because v2 options are still exactly @swc/types Options, the published type surface includes plugin?: Plugin, but the v2 transform methods never apply that callback before serializing options to the native binding. For callers using the documented JS plugin form (transformSync(src, { plugin })), JSON serialization drops the function and the transform runs without the plugin or a warning; either keep the v1 plugin handling here or remove it from V2Options.

Useful? React with 👍 / 👎.

}

async parse(src: string, options?: ParseOptions): Promise<Program> {
const normalized = options ?? { syntax: "ecmascript" };

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Default syntax when parse options are partial

If a JavaScript caller supplies parse options without a syntax tag, such as { comments: true }, this path forwards that object unchanged to native deserialization. The Rust ParseOptions expects the flattened syntax tag unless the JS facade fills it in; v1 does options.syntax = options.syntax || "ecmascript", so these calls regress from parsing as ECMAScript to throwing. Apply the default whenever an options object is provided, and mirror it in the sync/file parse paths.

Useful? React with 👍 / 👎.

@codspeed-hq

codspeed-hq Bot commented Jul 11, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 189 untouched benchmarks
⏩ 61 skipped benchmarks1


Comparing kdy1:kdy1/swc-v2-parallel-packages (6cc187a) with main (ab66869)

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.

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.

1 participant