Skip to content

Commit cb327ee

Browse files
authored
fix: generateTrace with newer TypeScript versions and build: false (#730)
Closes: #722
1 parent d2fe738 commit cb327ee

File tree

4 files changed

+69
-19
lines changed

4 files changed

+69
-19
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -347,10 +347,10 @@ yarn add --dev @types/webpack
347347

348348
## Profiling types resolution
349349

350-
Starting from TypeScript 4.1.0, you can profile long type checks by
350+
When using TypeScript 4.3.0 or newer you can profile long type checks by
351351
setting "generateTrace" compiler option. This is an instruction from [microsoft/TypeScript#40063](https://github.com/microsoft/TypeScript/pull/40063):
352352

353-
1. Set "generateTrace": "{folderName}" in your `tsconfig.json`
353+
1. Set "generateTrace": "{folderName}" in your `tsconfig.json` (under `compilerOptions`)
354354
2. Look in the resulting folder. If you used build mode, there will be a `legend.json` telling you what went where.
355355
Otherwise, there will be `trace.json` file and `types.json` files.
356356
3. Navigate to [edge://tracing](edge://tracing) or [chrome://tracing](chrome://tracing) and load `trace.json`

src/typescript/worker/lib/program/program.ts

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { getConfigFilePathFromProgram, getParsedConfig } from '../config';
44
import { updateDiagnostics, getDiagnosticsOfProgram } from '../diagnostics';
55
import { emitDtsIfNeeded } from '../emit';
66
import { createCompilerHost } from '../host/compiler-host';
7+
import { startTracingIfNeeded, stopTracingIfNeeded } from '../tracing';
78
import { typescript } from '../typescript';
89

910
let compilerHost: ts.CompilerHost | undefined;
@@ -16,6 +17,7 @@ export function useProgram() {
1617
compilerHost = createCompilerHost(parsedConfig);
1718
}
1819
if (!program) {
20+
startTracingIfNeeded(parsedConfig.options);
1921
program = typescript.createProgram({
2022
rootNames: parsedConfig.fileNames,
2123
options: parsedConfig.options,
@@ -26,6 +28,7 @@ export function useProgram() {
2628

2729
updateDiagnostics(getConfigFilePathFromProgram(program), getDiagnosticsOfProgram(program));
2830
emitDtsIfNeeded(program);
31+
stopTracingIfNeeded(program);
2932
}
3033

3134
export function invalidateProgram(withHost = false) {

src/typescript/worker/lib/tracing.ts

+24-17
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,44 @@ import { getConfigFilePathFromCompilerOptions } from './config';
44
import { typescript } from './typescript';
55
import { config } from './worker-config';
66

7-
// write this type as it's available only starting from TypeScript 4.1.0
7+
// these types are internal in TypeScript, so reproduce them here
8+
type TracingMode = 'project' | 'build' | 'server';
89
interface Tracing {
9-
startTracing(configFilePath: string, traceDirPath: string, isBuildMode: boolean): void;
10-
stopTracing(typeCatalog: unknown): void;
11-
dumpLegend(): void;
10+
startTracing?: (tracingMode: TracingMode, traceDir: string, configFilePath?: string) => void;
11+
12+
tracing?: {
13+
stopTracing(): void;
14+
dumpLegend(): void;
15+
};
1216
}
1317

1418
// eslint-disable-next-line @typescript-eslint/no-explicit-any
15-
const tracing: Tracing | undefined = (typescript as any).tracing;
19+
const traceableTypescript: Tracing = typescript as any;
1620

1721
export function startTracingIfNeeded(compilerOptions: ts.CompilerOptions) {
18-
if (compilerOptions.generateTrace && tracing) {
19-
tracing.startTracing(
20-
getConfigFilePathFromCompilerOptions(compilerOptions),
21-
compilerOptions.generateTrace as string,
22-
config.build
22+
if (
23+
typeof compilerOptions.generateTrace === 'string' &&
24+
typeof traceableTypescript.startTracing === 'function'
25+
) {
26+
traceableTypescript.startTracing(
27+
config.build ? 'build' : 'project',
28+
compilerOptions.generateTrace,
29+
getConfigFilePathFromCompilerOptions(compilerOptions)
2330
);
2431
}
2532
}
2633

27-
export function stopTracingIfNeeded(program: ts.BuilderProgram) {
34+
export function stopTracingIfNeeded(program: ts.Program | ts.BuilderProgram) {
2835
const compilerOptions = program.getCompilerOptions();
2936

30-
if (compilerOptions.generateTrace && tracing) {
31-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
32-
tracing.stopTracing((program.getProgram() as any).getTypeCatalog());
37+
if (
38+
typeof compilerOptions.generateTrace === 'string' &&
39+
typeof traceableTypescript.tracing?.stopTracing === 'function'
40+
) {
41+
traceableTypescript.tracing.stopTracing();
3342
}
3443
}
3544

3645
export function dumpTracingLegendIfNeeded() {
37-
if (tracing) {
38-
tracing.dumpLegend();
39-
}
46+
traceableTypescript.tracing?.dumpLegend();
4047
}

test/e2e/type-script-tracing.spec.ts

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import path from 'path';
2+
3+
import { extractWebpackErrors } from './driver/webpack-errors-extractor';
4+
5+
describe('TypeScript Tracing', () => {
6+
it.each([
7+
{ build: false, typescript: '~4.3.0' },
8+
{ build: true, typescript: '~4.3.0' },
9+
{ build: false, typescript: '~4.6.0' },
10+
{ build: true, typescript: '~4.6.0' },
11+
])('can generate trace files for %p', async ({ build, ...dependencies }) => {
12+
await sandbox.load(path.join(__dirname, 'fixtures/typescript-basic'));
13+
await sandbox.install('yarn', { ...dependencies });
14+
15+
// enable tracing
16+
await sandbox.patch(
17+
'tsconfig.json',
18+
'"outDir": "./dist"',
19+
'"outDir": "./dist",\n"generateTrace": "./traces"'
20+
);
21+
22+
await sandbox.write(
23+
'fork-ts-checker.config.js',
24+
`module.exports = ${JSON.stringify({ typescript: { build } })};`
25+
);
26+
27+
const webpackResult = await sandbox.exec('yarn webpack --mode=development');
28+
const errors = extractWebpackErrors(webpackResult);
29+
expect(errors).toEqual([]);
30+
31+
expect(await sandbox.exists('dist')).toEqual(true);
32+
33+
expect(await sandbox.list('./traces')).toEqual(
34+
expect.arrayContaining([
35+
expect.objectContaining({ name: expect.stringMatching(/types.*\.json/) }),
36+
expect.objectContaining({ name: expect.stringMatching(/trace.*\.json/) }),
37+
])
38+
);
39+
});
40+
});

0 commit comments

Comments
 (0)