Skip to content

Roadmap for experimental TypeScript support #217

Closed
@marco-ippolito

Description

@marco-ippolito

Intro

Since the previous discussion was successful in gathering feedback from the community, and I believe there is some consensus that this feature is something that the project wants to add, I want to summarize what are going to be the next steps and some technical solutions.
To be honest I'm very glad for the amount of feedback I received, it helped me to change my view on some aspects that I previously ignored.
Before I go into technical implementation, this is what the goals of this feature should be in my opinion:

Caution

These are long term goals and next steps, they might not reflect the current status.

  • Make sure Node.js can support TypeScript with the stability guarantees that has always offered.
  • Avoid breaking the ecosystem, this means creating a new "flavor" that only works on Node.js.
  • Performance.
  • Keeping it simple, we don't support everything, we want to user land tools to work in sync with Node, we provide the foundations to build on top.
  • Type stripping is the way to go.

Step 1: Initial implementation

The initial implementation is the proof of concept that I have created to gather feedback and consensus from the project collaborators.
It's very far from being perfect but it establishes some of the points we want to move forward with.
Current limitations:

  • No support forTypeScript features that require transformation (Enums, namespace, etc...).
  • No .js extension for .ts files.
  • No running TypeScript in node_modules.
  • No source maps, but not needed because we perform whitespacing (replace removed code with white space).

Important

Why no support for TypeScript features such as enums, namespaces, decorators, etc...?????

  • In the initial implementation I decided to start with the smallest subset possible.
  • Adding transformation means supporting source-maps so is more work.
  • Supporting features means adding more instability to the TypeScript syntax we support, without having a way to stay up to date with new features. As a general rule of thumb, the more you support the more likely to have breaking changes. This is a great challenge to overcome because we need to support transformations and new features but respect Node stability guarantees

Step 2: Decoupling

There is already a precedent for something that Node.js support, that can be upgraded seperately, its NPM.
Node bundles a version of npm that can upgraded separately, we could do the same with our TypeScript transpiler.

We could create a package that we bundle but that can also be downloaded from NPM, keep a stable version in core, but if TypeScript releases new features that we don't support or breaking changes, or users want to use the new shiny experimental feature, they can upgrade it separately.
This ensures that users are not locked, but also provides support for a TypeScript version for the whole 3 years of the lifetime of Node.js release.

Getting started

Create a new package called amaro that wraps swc with the current implementation. This package, which is released on npm, offers the same api that is currently used by Node, and it can be upgraded separately. The first challenge would be setup the project, make sure it can be upgraded by running npm install amaro@vX.Y.Z

Increase features

  • Support for transformation behind a flag

  • Enable support for TypeScript features that require transformation (Enums, mamespaces), now that we are decoupled we can expand on the amount of feature we support.

Caution

Currently there is consensus that Node.js should NOT run TypeScript files inside `node_modules.
It is not supported to avoid package maintainers to release TS only package.

Thanks @joyeecheung and @legendecas for the idea 💡

Step 3: Make it fast

With the project up and running, we can now start thinking about performance.
We could vendor SWC in Rust, build our own wasm, or compile it to static libraries that we could use in core, c++ rust FFI, etc...
I'm not a performance expert, but I think it is possible to optimize the interaction between Node and SWC and make it performant, without impacting the Node build process.
This is the phase where we measure the performance and make it usable in production without performance penalties.

Step 4: Add more features


Wont Fix

  • I strongly believe we should not support .js extension for .ts files.
    The reason is that the compiler/bundler should be responsible to resolve the correct extension at compile time.
    At runtime, the extension must be correct, it doesn't make sense to add overhead in production when it can be solved during development. Discussion happening here: Import specifiers in --experimental-strip-types #214.
    This is also supported by TypeScript from 5.7 Rewrite relative import extensions with flag microsoft/TypeScript#59767
  • Support tsconfig directly
    This would mean to run with typescript to support the latest flavors etc... Compilation and type checking should be done by user land tools during development.

Metadata

Metadata

Assignees

No one assigned

    Labels

    typescriptDiscussions related to TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions