swc-project / swc-project/swc-node

Allow user-supplied `jsc.experimental` options

Open Beginner friendly
#1,034 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
2k
Forks
95
Avg merge
14d 11h
Merged PRs (30d)
1

Description

Summary

@swc-node/core's transformOption constructs jsc.experimental as a hardcoded { keepImportAttributes: true } literal with no way for callers to extend it (see here). This makes it effectively impossible to enable SWC plugins (e.g. @swc-contrib/mut-cjs-exports) when going through @swc-node/core or @swc-node/jest without re-implementing the entire transformOption body.

This is especially painful with @swc-node/jest: the only knob exposed by its public API is the Options argument, but Options has no experimental field, and overriding via swc: { jsc: {...} } clobbers every other tsconfig-derived jsc setting (target, paths, parser, transform, etc). See also #700.

Motivation

The most common reason users want to pass a plugin through @swc-node/jest is to make jest.mock / jest.requireActual / Sinon stubs work on modules with circular imports (exactly the use case in #713). The recommended fix in the SWC ecosystem is the @swc-contrib/mut-cjs-exports plugin, which turns ESM export const bindings (compiled to CJS getters by SWC) into plain assignments so they can be mocked.

There is currently no clean way to wire that plugin into @swc-node/jest. Users either:

  1. Drop @swc-node/jest and switch to @swc/jest + .swcrc (loses tsconfig integration), or
  2. Write a custom Jest transformer that calls core.transformJest with a manually-rebuilt jsc (~70 lines of code that re-implements transformOption), or
  3. Patch node_modules/@swc-node/core/lib/index.js (what I'm currently doing via patch-package).

Proposed change

Allow callers to pass an experimental field on Options and merge it into the constructed jsc.experimental. One spread, no behavior change for existing callers.

packages/core/index.ts: extend the Options interface:

 export interface Options {
   // ...existing fields...
   swc?: SwcOptions
   ignoreDynamic?: boolean
+  experimental?: {
+    plugins?: Array<[string, Record<string, unknown>]>
+    keepImportAttributes?: boolean
+  }
 }

packages/core/index.ts: merge inside transformOption:

                 baseUrl: opts.baseUrl,
                 experimental: {
                   keepImportAttributes: true,
+                  ...(opts.experimental ?? {}),
                 },

After this change, @swc-node/jest users get plugin support for free, with no other changes needed in @swc-node/jest:

// jest.config.js
module.exports = {
  transform: {
    "^.+\\.[tj]sx?$": [
      "@swc-node/jest",
      {
        experimental: {
          plugins: [["@swc-contrib/mut-cjs-exports", {}]],
        },
      },
    ],
  },
};

Backwards compatibility

  • New optional field; all existing call sites unaffected.
  • keepImportAttributes: true remains the default; user can opt out by passing experimental: { keepImportAttributes: false }.
  • No changes to @swc-node/jest's public API, it already spreads its second-arg options into core.transformJest.

Related

  • #713 - Mocking with jest doesn't work (the canonical "I need this plugin" ticket; this change unblocks the community-recommended workaround).
  • #700 - @swc-node/jest doesn't pass options from tsconfig to swc properly (related: swc: { jsc: {...} } is currently the only override path and is too coarse).

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in packages/core/index.ts at the Options interface and transformOption, then inspect how @swc-node/jest forwards its second-argument options to core.transformJest. Add support for merging the optional experimental settings while preserving the existing default, and verify that plugin options and keepImportAttributes overrides reach the constructed jsc.experimental object.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
testing, tooling
Issue type
Feature
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
82/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.