TypeStrong / ts-node

TypeScript execution and REPL for node.js
https://typestrong.org/ts-node
MIT License
12.92k stars 532 forks source link

Expose SWC plugins configuration #1937

Open dmaretskyi opened 1 year ago

dmaretskyi commented 1 year ago

Desired Behavior

SWC added support for WASM-based ast transformers. It would be useful to expose this in the configuration.

The config is JSON-compatible, so it could be read from the "ts-node" section in tsconfig.json:

{
  "compilerOptions": {
    ...
  },
  "ts-node": {
    "swc": true,
    "swcConfig": {
      "jsc": {
        "experimental": {
            "plugins": [
              ["my-plugin", { "pluginOption": true }]
            ]
        }
      }
    }
  }
}

Alternatives you've considered

We're currently using a PNPM patch to hack in this feature: https://github.com/dxos/dxos/pull/2220/files/09762cb5b7f322f8f7d999aae98011d14b27927e#diff-67ce40d8249e12d3c63b1a3aaa38589a39e22b32383a74e696933cf05a63fa8a

shawnmcknight commented 1 year ago

I think this is pretty important functionality to support in order to offer a complete experience with swc. I don't think ts-node can try to figure out what plugins should be provided as that would largely be a userland setup.

For my use case, I'd like to be able to use the transform-imports plugin. I can work around this and use @swc/node directly, but the ability to have a single configuration via ts-node is very convenient.

In reviewing the ts-node codebase, it seems like this would be fairly easy to implement if an additional tsconfig option were to be permitted. The swc transpiler seems to already accept the entire config object from the specific tsconfig. If a new option were to be exposed (e.g. swcPlugins) then it could accept the same format as the jsc.experimental.plugins option from .swcrc. That value could be passed to createSwcOptions and if defined simply merged into the experimental object as a new property plugins which would then allow swc to make use of the defined plugins.

I'd be interested in working on a PR to expose this possibility, but I'd like to make sure that this approach is suitable before doing so.

Summary

valeneiko commented 1 year ago

If no options are provided to swc.transformSync call made by ts-node then swc will read the config from .swcrc. I have applied the following patch package to resolve the issue (v10.9.1):

diff --git a/dist/transpilers/swc.js b/dist/transpilers/swc.js
index eeddd4fbb2f18a7e8b20bb628d5f5c806ae20594..6a6fd953355f650f3f681c856fdce3b83e1f6868 100644
--- a/dist/transpilers/swc.js
+++ b/dist/transpilers/swc.js
@@ -32,14 +32,14 @@ function create(createOptions) {
         swcInstance = swc;
     }
     // Prepare SWC options derived from typescript compiler options
-    const { nonTsxOptions, tsxOptions } = createSwcOptions(config.options, nodeModuleEmitKind, swcInstance, swcDepName);
+    // const { nonTsxOptions, tsxOptions } = createSwcOptions(config.options, nodeModuleEmitKind, swcInstance, swcDepName);
     const transpile = (input, transpileOptions) => {
         const { fileName } = transpileOptions;
-        const swcOptions = fileName.endsWith('.tsx') || fileName.endsWith('.jsx')
-            ? tsxOptions
-            : nonTsxOptions;
+        // const swcOptions = fileName.endsWith('.tsx') || fileName.endsWith('.jsx')
+        //     ? tsxOptions
+        //     : nonTsxOptions;
         const { code, map } = swcInstance.transformSync(input, {
-            ...swcOptions,
+            // ...swcOptions,
             filename: fileName,
         });
         return { outputText: code, sourceMapText: map };