Note: The goal is to identify clear-cut hot-spots and provide enough context to extract a small repro. The repro can then be used as the basis of a bug report or a starting point for manual code inspection or profiling.
The short version is to run these commands:
tsc -p path/to/tsconfig.json --generateTrace traceDir npm install --no-save @typescript/analyze-trace npx analyze-trace traceDir
Each of these commands do the following:
- Building your project with
--generateTracetargeting a specific directory (e.g.
tsc -p path/to/tsconfig.json --generateTrace traceDir) will create a new
traceDirdirectory with paired trace and types files. Note that running with
--buildmode works as well.
@typescript/analyze-tracemakes its various commands available in your project.
npx analyze-trace traceDiroutputs a sorted list of compilation hot-spots - places where TypeScript is taking a high amount of time.
The analyzer tries to refer back to files from your project to provide better output, and uses relative paths to do so.
If your project changed since running
tsc --generateTrace, or you moved your trace output directory, then the tool's results may be misleading.
For best results, re-run
--generateTrace when files and dependencies are updated, and ensure the trace output is always in the same relative location with respect to the input project.
You can run
npx analyze-trace --help to find out about other options including:
||Suppress events that take less than the specified number of milliseconds. Reduce this value to see more output (maybe on faster machines), and increase it to reduce clutter.|
||Report all un-skipped events that take longer than the specified number of milliseconds. Reduce it to reveal more potential hot-spots that the built-in heuristic will not flag. Note that
||Color the output to make it easier to read. Turn this off when redirecting output to a file.|
||Expand the names of types when printing them. Turn this off when types are too verbose.|
||Experimental and unstable: Produce JSON output for programmatic consumption.|
For a simplified view of a
types.json file (useful when investigating an individual trace), you can run
npx simplify-trace-types traceDir/types.json output.txt.
Note that the resulting file is for human consumption and should not be passed to the analyzer (i.e. don't clobber the original).
analyze-trace output will try to highlight the most expensive portions of a compilation that it was able to measure (a.k.a. "hot spots").
Each hot spot may have a breakdown of other contributing hot spots.
analyze-trace will also try to point out when multiple versions of the same npm package were loaded and type-checked.
Output may look like the following:
Hot Spots ├─ Check file /some/sample/project/node_modules/typescript/lib/lib.dom.d.ts (899ms) ├─ Check file /some/sample/project/node_modules/@types/lodash/common/common.d.ts (530ms) │ └─ Compare types 50638 and 50640 (511ms) │ └─ Compare types 50643 and 50642 (511ms) │ └─ Compare types 50648 and 50644 (511ms) │ └─ Determine variance of type 50492 (511ms) │ └─ Compare types 50652 and 50651 (501ms) | └─ ... ├─ Check file /some/sample/project/node_modules/@types/babel__traverse/index.d.ts (511ms) └─ Check file /some/sample/project/node_modules/@types/react/index.d.ts (507ms)
Each step here is annotated with check times (e.g. checking two types in lodash took over 500ms).
Some common messages include the following:
|"Compare types 1234 and 5678"||TypeScript had to check whether two types with internal IDs
|"Determine variance of type 1234"||TypeScript had to check whether a
|"Emit declaration file"||Generating the declaration file for the current file took a while.|
Other messages correspond roughly to specific functions in the compiler, but are typically self-explanatory.
File names will be the first indicators of where to look.
Often, type IDs are used in place of more precise (but often verbose) type names, regardless of whether
--expandTypes is on.
types.json file will provide a way to look these up.
analyze-trace will point out instances of duplicate packages in
These can be caused by multiple projects in a mono-repo that use different versions of the same package, or possibly from dependencies in
node_modules that all specify different versions a library.
Duplicate packages may or may not be expected, but loading up multiple copies of a library can have negative effects on a build. For one, they add more time to TypeScript's parsing, binding, and possibly checking stages. Beyond that, duplicate copies of the same types may end up being passed around and compared to each other. Because these types don't share the same root identities, fewer optimizations can be made around them.
Acting on Results
Once you've found the "culprit" code that's making your build slow, try to create a minimal version of this code to isolate the issue and experiment. In some cases you can try to rewrite or simplify your code, and our team has a few suggestions for common issues here. If culprit code occurs in a library, it may be worth filing an issue with that library or sending a pull request to provide simplifications.
If you believe you have a minimal isolated reproduction of the issue that might be worth optimizing in TypeScript itself, you are encouraged to file an issue.
Updating projects within your monorepo to share the same dependencies may be one way to fix this issue.
Updating your dependencies may be another, though it won't always be the case that the most up-to-date versions of your dependencies list their dependencies in a compatible way.
If libraries you consume cannot be updated to list compatible dependency ranges, consider using
package.json for npm or for pnpm, or
package.json for Yarn.
Iterating on Results
You may want to tweak the
--forceMillis options to uncover hot spots that
analyze-trace may not reveal.
You may also want to try visualizing a performance trace) for a more detailed view.
Iterating between the
analyze-trace tool and an interactive visualizer might be a helpful workflow.
Reading up further on the TypeScript compiler's performance diagnostics page may provide ideas and options for your team as well.
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.