Расследование длинных TypeScript времени компиляции

Я изучаю, почему время компоновки моего проекта Angular 2.0 TypeScript длилось от 4 секунд до примерно 15 секунд за относительно короткое время.

Я встретил очень полезный, но, казалось бы, недокументированный переключатель --diagnostics.

Например, вот что я получаю при запуске tsc --noEmit --diagnostics в моем проекте сейчас:

Files:             231
Lines:           50872
Nodes:          170067
Identifiers:     65994
Symbols:       7712123
Types:          407677
Memory used:   600554K
I/O read:        0.43s
I/O write:       0.00s
Parse time:      1.13s
Bind time:       0.34s
Check time:     10.17s
Emit time:       0.00s
Total time:     11.64s

Вот что я получаю, когда я запускаю ту же команду в более ранней версии проекта.

Files:             197
Lines:           30882
Nodes:          124208
Identifiers:     46201
Symbols:       5856945
Types:           10989
Memory used:    80412K
I/O read:        0.03s
I/O write:       0.00s
Parse time:      0.60s
Bind time:       0.27s
Check time:      0.93s
Emit time:       0.00s
Total time:      1.79s

Число Types пошло вверх, и поэтому имеет значение Check time.

Можно ли получить более подробный/подробный вывод из --diagnostics?

NodeJS v4.4.3, TypeScript v1.8.10. Это мой tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "system",
    "moduleResolution": "node",

    "noImplicitAny": false,
    "noEmitOnError": false,

    "experimentalDecorators": true,

    "emitDecoratorMetadata": true,
    "removeComments": false
  },
  "exclude": [
    "node_modules",
    "wwwroot",
    "typings/main.d.ts",
    "typings/main"
  ]
}

Ответы

Ответ 1

Кажется, я нашел виновника в моем случае. Я сделал это с трудом; мой процесс:

  • Найдите фиксацию, которая сделала компиляцию медленной. Пройдите проверку фиксации истории и проверьте время компиляции.
  • Прокомментируйте измененный код до тех пор, пока не будут найдены строки нарушения.

Перед нарушением фиксации я последовательно получал время компиляции около 2-4 секунд после фиксации - 13-17 секунд.

В моем случае у меня есть класс с полем accessTokenGetter, который был инициализирован в конструкторе:

export class JwtConfig {
    //...
    accessTokenGetter: () => Observable<string>;
    //...
      constructor(private config?: IJwtConfig) {
          // ...
          this.accessTokenGetter = this.config.accessTokenGetter || (() => Observable.of(null));
      }
}

Вторая часть инициализации || (() => Observable.of(null)); вызывала медленность. Комментируя это или добавляя аннотацию типа, время компиляции возвращается. Поскольку Observable является общим, кажется, что компилятору TypeScript нужен намек, чтобы сузить некоторые проверки типов, которые он должен выполнить. Моя инициализация теперь читается как:

//...
this.accessTokenGetter = this.config.accessTokenGetter || (() => Observable.of(<string>null));
//...

Observable.of(null as string)) также, похоже, выполняет эту работу. Там было еще несколько мест, где добавлена ​​компиляция аннотаций типа.

Надеюсь, это поможет кому-то.

Тем не менее, если в компиляторе есть средство для ответа быстрее - я был бы рад услышать его.

Ответ 2

Я мог бы ускорить процесс компиляции с 15 секунд. до 6-7 с. путем изменения этой отдельной строки кода:

// slow:
// ...
.flatMap((receivedObj: MyType) => {
    let nextObservable: Observable<MySecondType> = this.dependingPut(receivedObj);
    return nextObservable || new Observable((observer) => {
            observer.next(undefined);
        });
});


// fast:
.flatMap((receivedObj: MyType) => {
    let nextObservable: Observable<MySecondType> = this.dependingPut(receivedObj);  
    return nextObservable || new Observable<MySecondType>((observer) => { // <--- use the generics!
            observer.next(undefined);
        });
});

Из справочника Typescript (https://www.typescriptlang.org/docs/handbook/generics.html):

function identity<T>(arg: T): T {
    return arg;
}

// ...

let output = identity("myString");  // type of output will be 'string'

"Обратите внимание, что нам не нужно явно передавать тип в угол скобки (< > ), компилятор просто посмотрел на значение" myString "и установите T в его тип. Хотя вывод аргумента типа может быть полезным инструментом чтобы код был короче и читабельнее, вам может потребоваться явно передайте аргументы типа, как это было в предыдущем примере, когда компилятор не может вывести тип, что может произойти в более сложных примеры".

В моем случае это не подвело; вывод типа занял очень много времени (кстати, он также потреблял много памяти). Прежде чем приступать к созданию обходных решений, вернитесь в историю изменений и попытайтесь определить плохую ревизию. Чтобы убедиться, что компилятор является виновником, используйте опцию - diagnostics. Если возвращаемая статистика возвращает высокое значение "Проверить время", проверьте свой код на отсутствие типов.

Ответ 3

Для меня замедление было связано с импортом вроде import "./file.ts";. Удаление расширения .ts делает вещи на 90% быстрее: import "./file";

Ответ 4

Известно, что компилятор работает медленно, вы можете использовать компилятор в режиме просмотра tsc -w или переключиться на webpack и ts-loader, которые выставляют transpileOnly (без длительных проверок).

Ответ 5

В моем случае время компиляции составляло около 15-30 секунд. После команды tsc --noEmit --diagnostics я заметил, что я создаю 2k файлы. Решение заключалось в том, чтобы исключить все файлы из папки node_modules:

{
  "compilerOptions": {...},
   "exclude": [
     "node_modules"
   ]
}

Также рекомендуется исключить папку typings.