Repository: TypeScript
Issue: Support splitting transpilation into a worker in tsc
Labels: Suggestion,In Discussion

# Suggestion

<!--
  Please fill in each section completely. Thank you!
-->

## 🔍 Search Terms

<!--
  💡 Did you know? TypeScript has over 2,000 open suggestions!
  🔎 Please search thoroughly before logging new feature requests as most common ideas already have a proposal in progress.
  The "Common Feature Requests" section of the FAQ lists many popular requests: https://github.com/Microsoft/TypeScript/wiki/FAQ#common-feature-requests

  Replace the text below:
-->

isolatedModules, tsc, worker, parallel

## ✅ Viability Checklist

<!--
   Suggestions that don't meet all these criteria are very, very unlikely to be accepted.
   We always recommend reviewing the TypeScript design goals before investing time writing
   a proposal for ideas outside the scope of the project.
-->
My suggestion meets these guidelines:

* [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
* [x] This wouldn't change the runtime behavior of existing JavaScript code
* [x] This could be implemented without emitting different JS based on the types of the expressions
* [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
* [x] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).

## ⭐ Suggestion

For projects that have both `isolatedModules: true` and `verbatimModuleSyntax: true`, it is feasible to save end-to-end compile time by, after identifying changed source files, fork the transpilation part of the compilation into a worker (WebWorker on web, 'node:worker_threads' on NodeJs) so that it can be run in parallel with the type checker on the main thread (which gets `declarationOnly: true` injected into its config before emit).

I've prototyped this in the RC version of Heft here: https://github.com/microsoft/rushstack/pull/4120
However, it seems like a straightforward enough feature with enough of a performance benefit that it would be useful to have as part of core TypeScript.

## 📃 Motivating Example

<!--
  If you were announcing this feature in a blog post, what's a short explanation that shows
  a developer why this feature improves the language?
-->

With `isolatedModules: true` and `verbatimModuleSyntax: true`, the time calculations are thus:

`T_Transpile = Transform_js + Emit_js`
`T_Declaration = Check + Transform_dts + Emit_dts`
`T_Worker_Overhead = Parse + Bind`
`T_Startup = Resolve + Parse + Bind`
`T_Worker = T_Worker_Overhead + T_Transpile`

`T_Original = T_Startup + T_Transpile + T_Declaration`
`T_WithWorker = T_Startup + max(T_Declaration, T_Worker)`

Testing on a modestly large local project (816 source files) has
`T_Original = 19.7 s`
`T_Declaration = 10.0 s`
`T_Worker = 8.1 s`
`T_Worker_Overhead = 1.9 s`

Resulting in a net end-to-end savings of `6.2 s` out of `19.7 s` = `31%` with no change to the output.

## 💻 Use Cases

<!--
  What do you want to use this for?
  What shortcomings exist with current approaches?
  What workarounds are you using in the meantime?
-->

Granted, custom build tools can do this, but a lot of developers prefer to use `tsc` directly, and by making this a core feature, it incentivizes improvements to the duplication that occurs in the implmentation (namely Parse + Bind).