Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sucrase integration #1851

Open
8 tasks
cspotcode opened this issue Jul 27, 2022 · 1 comment
Open
8 tasks

Sucrase integration #1851

cspotcode opened this issue Jul 27, 2022 · 1 comment
Labels
research Needs design work, investigation, or prototyping. Implementation uncertain.
Milestone

Comments

@cspotcode
Copy link
Collaborator

cspotcode commented Jul 27, 2022

This issue tracks the work necessary on the ts-node side to offer first-class support for a sucrase transpiler.

Related to:
alangpierce/sucrase#726
alangpierce/sucrase#729

User should be able to ts-node --sucrase or add "sucrase": true to tsconfig, just as they can do for swc.

I will maintain a to-do list of tasks based on conversations with @alangpierce.

Interface between ts-node and sucrase (WIP)

These are the bits to lock down into a non-breaking interface of sorts, between sucrase and ts-node

  • What module specifier should ts-node require() when user enables "sucrase": true?
    • basically, this is the value of the "transpiler" option, but I think we do a bit of project-local and global fallback require() conveniences to make things "just work"
  • What is the name of the module, if different than above?
    • e.g when we fail to require('sucrase/ts-node-plugin') then we should suggest that users add sucrase` to their package.json
    • we must(?) also declare optional peerDep for strict package managers
  • way for transpiler to return diagnostics
    • errors and warnings
    • from both create() and transpile()
  • way for transpiler to indicate REPL continuation / recoverable input

TODOs (WIP)

  • Add "sucrase" option to config
  • Add --sucrase flag to CLI
  • Add --sucrase flag to CLI --help
  • Redo docs to describe SWC and sucrase under same umbrella
  • make @internal transpiler API bits public
    • /** @category Transpiler */
      export interface CreateTranspilerOptions {
      // TODO this is confusing because its only a partial Service. Rename?
      // Careful: must avoid stripInternal breakage by guarding with Extract<>
      service: Pick<
      Service,
      Extract<'config' | 'options' | 'projectLocalResolveHelper', keyof Service>
      >;
      /**
      * If `"transpiler"` option is declared in an "extends" tsconfig, this path might be different than
      * the `projectLocalResolveHelper`
      *
      * @internal
      */
      transpilerConfigLocalResolveHelper: ProjectLocalResolveHelper;
      /**
      * When using `module: nodenext` or `module: node12`, there are two possible styles of emit:
      * - CommonJS with dynamic imports preserved (not transformed into `require()` calls)
      * - ECMAScript modules with `import foo = require()` transformed into `require = createRequire(); const foo = require()`
      * @internal
      */
      nodeModuleEmitKind?: NodeModuleEmitKind;
      }
    • nodeModuleEmitKind
  • figure out how sucrase should send us diagnostics: errors or warnings
    • either from create() or transpile() calls
    • let plugins declare their own "name" to namespace the diagnostics: e.g. TSNODE-SUCRASE-123
    • Maybe becomes part of the interface described above, or maybe merely part of the transpiler API
  • accept sourcemap as object in transpiler API
  • expose api version? to make future breaks easier to detect by plugins?
@cspotcode cspotcode added this to the v11 milestone Jul 27, 2022
@cspotcode cspotcode added the research Needs design work, investigation, or prototyping. Implementation uncertain. label Jul 27, 2022
@alangpierce
Copy link

Thanks for writing all this up!

In terms of plugin interface improvements, my impression is that there won't be that many plugins in the first place, so extra capabilities (e.g. diagnostics) should probably take priority over ease of use for plugin authors (e.g. isJsx and isTs flags). The current interface is already much easier to use than trying to integrate with node and TS from scratch, of course.

I think the transpiler plugin interface would be useful in these other use cases:

  • esbuild (for people using it elsewhere who want consistency)
  • Babel (for people already using it or people who have custom Babel plugins)
  • Any other ambitious transpiler authors.
  • Internal company/project use cases. For example, maybe you want to apply some regex to rewrite imports before or after running the code through tsc or some other transpiler.

Thinking through potential plugin interface changes, two other possible future ones come to mind (maybe already on your radar):

  • Allowing async transformations. This wouldn't be useful for Sucrase, but I know that esbuild transformSync is slower than the async transform. (I see you're already familiar with the details: Faster sync API via worker_thread evanw/esbuild#590 .) Presumably the sync API is necessary for require hooks, but theoretically the plugin interface could prefer the async version (e.g. for ESM hooks) and fall back to a sync implementation when necessary.
  • Document that plugins must be stateless so you can run the transformation in parallel using worker threads. (Or maybe provide a mechanism for plugins to opt in or out of parallelism.)

I think both of these could be introduced in a backcompat way.

way for transpiler to indicate REPL continuation / recoverable input

Could you explain what you mean by this one?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
research Needs design work, investigation, or prototyping. Implementation uncertain.
Projects
None yet
Development

No branches or pull requests

2 participants