Avatar for the swc-project user
swc-project
swc
BlogDocsChangelog

Performance History

Latest Results

chore: Add changeset
chenjiahan:chenjiahan/dedupe-icu
11 minutes ago
fix(binding/node): Return an error when a file cannot be read instead of panicking (#12379) ## Description `parse_file_sync` and `transform_file_sync` call `.expect()` on `load_file`, so a path that cannot be read panics. The release profile sets `panic = "abort"` ("Abort on panic to remove unwinding code"), so the `catch_unwind` inside `try_with` never sees it: the panic takes the whole Node process down. With the published 1.16.2, on macOS arm64 and node 24.18.0: ``` $ node -e "require('@swc/core').parseFileSync('/definitely/not/here.js', { syntax: 'ecmascript' })" thread '<unnamed>' panicked at bindings/binding_core_node/src/parse.rs:237:22: failed to read program file: Os { code: 2, kind: NotFound, message: "No such file or directory" } $ echo $? 134 ``` The async entry points beside them already do the right thing: `parse_file` and `transform_file` use `.context(...)?` and surface a rejected promise. This gives the two sync entry points the same handling. I ran into it through dependency-cruiser, whose swc parser calls `parseFileSync`: a module that disappears between the file listing and the parse, or a broken symlink, ends the whole cruise instead of failing one module. ## Test `packages/core/__tests__/parse/api_test.js` gets two cases: `parseFile` rejects for a path that is not there, and `parseFileSync` throws. For reviewers: in a debug build both pass with or without the fix, because unwinding is on there and `catch_unwind` turns the panic into an error. In a release build, which is what npm ships, the unfixed sync case aborts the runner. ## Verified locally macOS arm64, Rust 1.92, node 24.18.0: - `cargo check -p binding_core_node` is clean. - `npm run build:dev` in `packages/core`, then `rstest` over that file: 8 passing. Happy to add a changeset if you want one; the change is in the node binding only.
main
4 hours ago
feat(es/minifier): honor `/*#__PURE__*/` on property reads and destructuring patterns (#12384) SWC supports a `pure_getters` compress option, but it is a whole-program promise that *no* property read anywhere has side effects. This adds a per-site opt-in — `/*#__PURE__*/` on an individual property read and destructuring pattern. Rollup and esbuild read the annotation the same way. [Playground (before)](https://play.swc.rs/?version=1.15.46&code=H4sIAAAAAAAC%2F1WQMU%2FEMAyF9%2FyKp7LAiWt3TgwM7Ahxc%2BU2bgmkceQkIHTiv5OoQojR1vP3PtltUTTjApne8I1FZUPn3dSdjBkGPIQgmTLbO1BKZWOLLJgYhOQsH3lZeM7HRZmhTPYWSeAyXIJViZFtb4bD1Tg%2BnZ8fx%2FEwtJ6efql7yTnQX01UTqwfXFETz1RS61o5Z1bMUryFlgDSyWUl%2Fao7y71p1OjJhZ348lqvdqaTmvbV6lP0PaFNsJyyljkXdWFFpAYPvZklpIz%2FuhdQFamfuW%2Fmld5C4rn3sl53VgJ3NyfzA4fr7vBGAQAA) ```js import { obj } from "lib"; /*#__PURE__*/ obj.annotated; // dropped obj.plain; // preserved const /*#__PURE__*/ { a, b } = obj; // dropped ``` --- ### 1. `feat(es/minifier): drop ignored property accesses under pure_getters` `pure_getters` was consulted in exactly one place — `take_pat_if_unused`, which only decides whether unused bindings can be dropped out of a destructuring pattern. A property access in statement position was *always* preserved, even with `pure_getters: true`, because `ignore_return_value` had no `Expr::Member` arm. So the option bought considerably less than its name suggests. This adds that arm. When the option allows it, the access is replaced by the side effects of its operands: `x().y` becomes `x()`, and `({p: 1}).p` disappears. The object is evaluated before a computed key, preserving evaluation order (`x()[y()]` → `x(), y()`). `can_assume_pure_getter` implements all three variants of the option rather than only `Bool(true)`: - `Str` consults the allow list, including string-literal computed keys. - `Strict` stays **disabled** — in terser it relaxes nullish checks, not getter effects. Writes are untouched: assignment, compound assignment, update and `delete` can all run a setter, and the write is the point of the statement. This unblocks four terser fixtures (`issue_2313_6`, `issue_2938_3`, `issue_2938_4`, `impure_getter_2`), which now match terser's output. `issue_2838` stays postponed — it needs dead *assignment* removal, a separate optimization. ### 2. `feat(es/minifier): honor /*#__PURE__*/ on property reads and destructuring patterns` Pure marks normally ride on a node's `SyntaxContext`, but `MemberExpr`, `ObjectPat` and `ArrayPat` have none, so annotations on them go in a side table keyed by source position. It is collected by `info_marker` during the traversal it already performs, and read by `pure_optimizer` and `take_pat_if_unused`. #### Why a side table rather than `ctxt` on `MemberExpr` Very feasible but API breaking for the JS-visible AST structures, hence the side-table. **Testing:** New `tests/fixture/pure-getters/` suite covering the three option variants, evaluation order, annotation ownership, nullish assertion, survival through inlining, and the boundaries where the optimization must not fire (writes, optional chaining, `strict`). - `cargo test -p swc_ecma_minifier` — green, no snapshot churn - `cargo test -p swc` — green - `cargo check --workspace --all-targets` — clean - `cargo clippy -p swc_ecma_minifier --all-targets -- -D warnings` — clean - `cargo fmt --all` — applied **BREAKING CHANGE:** None. Both changes are opt-in: the first only activates under an explicit `pure_getters` setting, the second only where the user wrote an annotation. **Related issue (if exists):** None. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
main
4 hours ago
feat(es/minifier): honor `/*#__PURE__*/` on property reads and destructuring patterns `pure_getters` is a whole-program promise that no property read anywhere has side effects, which is too blunt to enable safely. This adds a per-site opt-in: an annotation on a single access or destructuring pattern, so a library can mark the places it knows are safe without turning on the unsound global option. Pure marks normally ride on a node's `SyntaxContext`, but `MemberExpr`, `ObjectPat` and `ArrayPat` have none. Adding one to `MemberExpr` is feasible (the `Expr` enum has room, and `CallExpr` already sets its size), but `ctxt` is serialized into the JS-visible AST, so it would put a new key on every member expression in `swc.parse()` output and in the plugin AST schema. That is a breaking change, and not one worth spending before the optimization has proven itself. So annotations on those nodes go in a side table keyed by source position, collected by `info_marker` during the traversal it already performs and read by `pure_optimizer` and `take_pat_if_unused`. It is held by shared reference, which keeps `Parallel::create` for `Pure` a plain copy. Keying on `lo` rather than the whole span is deliberate: a pass may rebuild a node with a different `hi`, but `lo` is where a leading comment attaches. A fixture covers an annotated access that survives inlining into its caller, which was the failure mode I was most worried about. Annotation ownership needed care. A member expression starts at the same position as its object, so the comment in `/*#__PURE__*/ x().y` is found by a lookup on either node. It belongs to the call, which already consumes it, and claiming it for the read would drop `x()` — a real miscompile I hit and fixed before it could land. The table only claims an annotation when the object could not have taken it. On a pattern the annotation carries more weight than on a call: it asserts both that the reads are pure and that the initializer is not nullish, since dropping the pattern also removes the `TypeError` that destructuring `null` would throw. That is documented at the use site and pinned by a fixture. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
lukesandberg:lukesandberg/pure_annotations_on_property_access
16 hours ago

Latest Branches

CodSpeed Performance Gauge
-2%
feat(es/minifier): honor `/*#__PURE__*/` on property reads and destructuring patterns#12384
14 hours ago
71f6dd6
lukesandberg:lukesandberg/pure_annotations_on_property_access
CodSpeed Performance Gauge
0%
20 hours ago
a926ff0
kurovskyiii:fix/sync-file-bindings-return-an-error
CodSpeed Performance Gauge
0%
21 hours ago
6cfcccd
fix/parser-asserts-linebreak
© 2026 CodSpeed Technology
Home Terms Privacy Docs