gulp-typescript 增量编译是如何工作的?

How does gulp-typescript incremental compilation work?

gulp-typescript 的自述文件说 supports incremental compilation 但没有解释该术语在此上下文中的含义。

有一篇 issue 讨论了 gulp-typescript 增量编译如何比 tsc 慢,但它没有解释原因或区别。

gulp-typescript 在 "incremental compilation" 时在做什么?

我试过的

我正在查看 gulp-typescript 的源代码,看起来 gulp-typescript 根本没有进行任何增量编译。 创建 Project 时,它会关闭 ProjectInfo 的实例,该实例具有 input 成员,即 FileCache。 FileCache 几乎是从文件名到源字符串的映射。在 gulp-打字稿 Project.

中没有维护太多其他状态

为了使用 TS 编译器 API 进行实际的增量编译(在后续构建中重用编译过程的产物),我希望看到以下内容之一:

但我在源代码中没有看到任何一个。

gulp-typescript缓存编译后的js文件,当某些文件改变时,它会编译一个 https://github.com/ivogabe/gulp-typescript/blob/master/lib/compiler.ts#L282

if (this.project.input.getFileChange(file.fileNameOriginal).state === FileChangeState.Equal) {
    // Not changed, re-use old file.

    const old = this.previousOutput[file.fileNameNormalized];
    this.write(file, old.fileName, old.diagnostics, old.content, old.sourceMap);

    return;
}

const output: ts.TranspileOutput = this.project.typescript.transpileModule(file.content, {
    compilerOptions: this.project.options,
    fileName: file.fileNameOriginal,
    reportDiagnostics: true,
    transformers: this.finalTransformers ? this.finalTransformers() : undefined,
});

即使是一个文件编译也会导致分析导入的依赖项,所以它不会比 tsc --watch

更快

Gulp-typescript 有两种不同的方式来编译你的文件。默认方法编译整个项目并进行类型检查。这是在 lib/compiler.ts 中的 ProjectCompiler 中实现的。另一个单独编译每个文件,并在您设置 isolatedModules: true 时激活。该方法在 lib/compiler.ts 中的 FileCompiler 中实现。

FileCompiler只需要编译发生变化的文件即可。未更改的文件被缓存,就像 Achmedzhanov 在他的回答中描述的那样。

然而,大多数用户使用 ProjectCompiler,因为类型检查可能是他们使用 TypeScript 的原因。我认为您的问题与此 ProjectCompiler 有关。增量编译通过调用 TypeScript API 导出的 ts.createProgram 来处理。通过传递旧程序,TypeScript API 将重用以前编译的一些信息。您可以在这里找到源代码:

https://github.com/ivogabe/gulp-typescript/blob/ea22fb7fe4295979e32a9d07b007e3f7473be8b5/lib/compiler.ts#L80

过去这足以获得增量编译,但在较新版本的 TypeScript 中已经发生了变化。我们将需要切换到新的 API,可能会使用您提到的 API 之一,但我不熟悉这些。

在您的问题中,您提到了 FileCache。这用于存储在输入流中传递的所有文件。 gulp API 即在流中给出所有文件,而 TypeScript API 是同步的。因此,我们需要等到我们拥有所有输入文件。此外,我们使用FileCompiler中的FileCache来检测文件是否发生变化,从而判断是否需要重新编译。