Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Very slow incremental compilation (2.6x slower) compared to tsc #549

Open
esprehn opened this issue Dec 1, 2017 · 29 comments
Open

Very slow incremental compilation (2.6x slower) compared to tsc #549

esprehn opened this issue Dec 1, 2017 · 29 comments
Labels

Comments

@esprehn
Copy link

esprehn commented Dec 1, 2017

With "gulp-typescript": "3.2.3",

Expected behavior:

Should be as fast as tsc -w

Synchronizing program
Files:           289
Lines:        121510
Nodes:        524773
Identifiers:  184342
Symbols:      244975
Types:         51810
Memory used: 263018K
I/O read:      0.03s
I/O write:     0.09s
Parse time:    2.55s
Bind time:     0.63s
Check time:    4.13s
Emit time:     2.57s
Total time:    9.87s
9:21:12 PM - Compilation complete. Watching for file changes.

9:21:20 PM - File change detected. Starting incremental compilation...
Synchronizing program
...
Total time:    3.34s
9:21:23 PM - Compilation complete. Watching for file changes.
9:21:29 PM - File change detected. Starting incremental compilation...
Synchronizing program
...
Total time:    2.81s

Actual behavior:

Very slow, gulp does:

[21:17:49] Finished 'compileSources' after 9.31 s
... change a file ...
[21:18:04] Finished 'compileSources' after 7.4 s

Your gulpfile:

const ts = require('gulp-typescript');
const tsProject = ts.createProject('tsconfig.json');
gulp.task('compileSources', () =>
  tsProject.src()
      .pipe(tsProject())
      .js.pipe(gulp.dest('artifacts'))
);

tsconfig.json

Include your tsconfig, if related to this issue.

{
    "compilerOptions": {
        "target": "es6",
        "module": "commonjs",
        "allowJs": true,
        "jsx": "react",
        "moduleResolution": "node",
        "importHelpers": true,
        "outDir": "artifacts",
        "rootDir": ".",
        "rootDirs": [
            "src",
            "node_modules/include-common"
        ],
        "sourceMap": true,
        "noImplicitAny": true,
        "suppressImplicitAnyIndexErrors": true,
        "strictNullChecks": true,
        "lib": ["dom", "es2017", "es2016", "es2015"],
        "baseUrl": ".",
        "paths": {
            "escodegen": ["node_modules/escodegen"],
            "esprima": ["node_modules/esprima"],
            "esquery": ["node_modules/esquery"],
            "firebase": ["node_modules/firebase"],
            "firebase-admin": ["node_modules/firebase-admin"],
            "firebase-safekey": ["node_modules/firebase-safekey"],
            "include-common/*": ["node_modules/include-common/*"]
        },
        "skipLibCheck": true,
        "types": [
            "color",
            "d3-format",
            "d3-scale",
            "esprima",
            "estree",
            "react",
            "react-native",
            "react-native-fs",
            "react-navigation",
            "react-redux",
            "redux-actions"
        ]
    },
    "compileOnSave": false,
    "include": [
        "ourTypings/**/*.d.ts",
        "src/**/*.ts",
        "src/**/*.tsx",
        "node_modules/include-common/**/*.ts",
        "node_modules/include-common/**/*.tsx"
    ],
    "exclude": [
        "android",
        "artifacts",
        "gruntfile.js",
        "node_modules/include-common/artifacts",
        "node_modules/include-common/node_modules"
    ]
}
@ivogabe
Copy link
Owner

ivogabe commented Dec 23, 2017

I'm afraid I cannot do anything without seeing the project. I do see that you have a complicated configuration with rootDir, rootDirs, paths, include and exclude, that might have some influence on the performance. Could you maybe check whether the performance problems are caused by tsProject.src()?

@esprehn
Copy link
Author

esprehn commented Dec 23, 2017

Sure! How would I do that?

@ivogabe
Copy link
Owner

ivogabe commented Dec 24, 2017

You could create a task which only invokes tsProject.src() and measure its running time.

gulp.task('foo', () =>
  tsProject.src()
);

@ivogabe
Copy link
Owner

ivogabe commented Feb 7, 2018

@esprehn Have you tried to measure the performance of tsProject.src()?

@GregRos
Copy link

GregRos commented Feb 19, 2018

I have a simpler example. I haven't really seen a difference between the first time gulp-typescript compiles and the next.

Runtimes

tsc -w

Initial: 9 seconds
Change in 1 file: <2s

gulp-typescript

Initial: ~9 seconds
Change in 1 file: ~9 seconds

The snippet you posted

Instantaneous

Details

Versions

node: v8.2.1
gulp: 3.9.1
typescript: 2.7.1
gulp-typescript: 4.0.1, also tried with 3.* and got similar results

gulpfile.js

const appProject = ts.createProject('tsconfig.json', {

});

gulp.task('build', function() {
    let appStream = appProject.src()
        .pipe(appProject())
        .pipe(gulp.dest("dist/"));

    return appStream;
});

gulp.task('watch', ['build'], function() {
    gulp.watch(["src/**/*.ts"], ["build"]);
});

I tried changing the src() to various glob patterns, but nothing changed anything.

tsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "node",
    "noImplicitAny": false,
    "noImplicitThis": true,
    "preserveConstEnums": true,
    "removeComments": true,
    "sourceMap": true,
    "skipLibCheck": true,
    "target": "ES6",
    "lib": [
      "dom",
      "es2015"
    ],
    "allowUnreachableCode": true,
    "outDir": "dist",
    "baseUrl": "."
  },
  "include": [
    "src/**/*",
    "src/*"
  ],
  "exclude": [
    "dist",
    "node_modules",
    "src/apps/guest-subsystem/**/*"
  ]
}

tsc -w --diagnostics

Initial

15:02:29 - Starting compilation in watch mode...


Synchronizing program
Files:          1020
Lines:        106017
Nodes:        482795
Identifiers:  157375
Symbols:      151459
Types:         19056
Memory used: 233559K
I/O read:      0.26s
I/O write:     0.46s
Parse time:    3.71s
Bind time:     0.90s
Check time:    2.91s
Emit time:     1.77s
Total time:    9.29s
15:02:39 - Compilation complete. Watching for file changes.

After change in one file

15:03:03 - File change detected. Starting incremental compilation...


Synchronizing program
Files:          1019
Lines:        106005
Nodes:        482730
Identifiers:  157353
Symbols:       98221
Types:           288
Memory used: 241529K
I/O read:      0.00s
I/O write:     0.01s
Parse time:    2.03s
Bind time:     0.04s
Check time:    0.04s
Emit time:     0.06s
Total time:    2.18s
15:03:06 - Compilation complete. Watching for file changes.

@esprehn
Copy link
Author

esprehn commented Feb 21, 2018

@ivogabe Sorry I didn't get a chance to look at this. We switched all our projects to calling tsc directly instead since it was so much faster. I'll see if I can try using gulp-typescript again later this week,

const { execSync, spawn } = require('child_process');

gulp.task('compileSources', () => new Promise((resolve, reject) => {
  const tsc = spawn('tsc', [], { stdio: 'inherit' });
  tsc.on('exit', (code) => {
    if (!code) {
      resolve();
    } else {
      reject();
    }
  });
}));

gulp.task('watchSources', () => {
  spawn('tsc', ['-w'], { stdio: 'inherit' });
});

@ivogabe
Copy link
Owner

ivogabe commented Feb 26, 2018

@GregRos could you measure the running time of appProject.src()? You can just modify your build task to:

gulp.task('build', function() {
    return  appProject.src();
});

@esprehn I understand that. Could you add a simple task to measure the performance of .src()? That way you don't have to bring back full compilation using gulp-typescript. You can use something like this:

const tsProject = ts.createProject('tsconfig.json');
gulp.task('foo', () =>
  tsProject.src()
);

@esprehn
Copy link
Author

esprehn commented Feb 26, 2018

That completes in 100ms for me. Testing it looks like tsc 2.7.2 takes the same amount of time (if not longer) on the first compile, and then is nearly instant for later compiles. It's a lot more than 2.6x now, close to 100x faster (0.07 seconds vs 6.6 seconds). gulp-typescript seems to always take 6-8 seconds.

Looking at the diagnostics difference I think tsc is not reloading all the types for each incremental compile (57770 for first compile, 238 for second, see below) while gulp-typescript is.

gulpfile.js

const gulp = require('gulp');
const { spawn } = require('child_process');
const ts = require('gulp-typescript');

const tsProject = ts.createProject('./tsconfig.json');

gulp.task('compileWithGulpTypeScript', () => {
  const t1 = Date.now();
  const src = tsProject.src();
  console.log('.src()', Date.now() - t1);
  const t2 = Date.now();
  const transformer = tsProject();
  console.log('transformer', Date.now() - t2);
  return src
    .pipe(transformer)
    .pipe(gulp.dest('artifacts'));
});

gulp.task('compileWithGulpTypeScript-watch', () => {
  gulp.watch(['src/**/*.ts'], ['compileWithGulpTypeScript'])
});

gulp.task('watchSources', () => {
    // tsc --watch clears the shell, so we use a gross hack around it.
    // https://github.com/Microsoft/TypeScript/issues/21295#issuecomment-367571059
    spawn(`tsc -w | awk '{ gsub(/\\033c/, "") system("")}1'`, {
        stdio: 'inherit',
        shell: true,
    });
});

Output from gulp-typescript

$ gulp compileWithGulpTypeScript-watch
[13:00:00] Using gulpfile /Checkouts/grasshopper/packages/app/gulpfile.js
[13:00:00] Starting 'compileWithGulpTypeScript-watch'...
[13:00:00] Finished 'compileWithGulpTypeScript-watch' after 79 ms
[13:00:59] Starting 'compileWithGulpTypeScript'...
.src() 135
transformer 0
[13:01:09] Finished 'compileWithGulpTypeScript' after 9.27 s
[13:01:11] Starting 'compileWithGulpTypeScript'...
.src() 100
transformer 0
[13:01:18] Finished 'compileWithGulpTypeScript' after 7.28 s
[13:01:21] Starting 'compileWithGulpTypeScript'...
.src() 87
transformer 0
[13:01:28] Finished 'compileWithGulpTypeScript' after 6.71 s
[13:01:46] Starting 'compileWithGulpTypeScript'...
.src() 101
transformer 0
[13:01:53] Finished 'compileWithGulpTypeScript' after 6.64 s

Output from tsc

$ tsc -v
Version 2.7.2
$ gulp watchSources
[13:02:41] Using gulpfile /Checkouts/grasshopper/packages/app/gulpfile.js
[13:02:41] Starting 'watchSources'...
[13:02:41] Finished 'watchSources' after 3.8 ms
13:02:42 - Starting compilation in watch mode...
13:02:52 - Compilation complete. Watching for file changes.
13:02:59 - File change detected. Starting incremental compilation...
13:02:59 - Compilation complete. Watching for file changes.
13:03:05 - File change detected. Starting incremental compilation...
13:03:05 - Compilation complete. Watching for file changes.
13:03:14 - File change detected. Starting incremental compilation...
13:03:14 - Compilation complete. Watching for file changes.
13:03:17 - File change detected. Starting incremental compilation...
13:03:17 - Compilation complete. Watching for file changes.

tsc with --diagnostics turned on

$ gulp watchSources
[13:08:24] Using gulpfile /Checkouts/grasshopper/packages/app/gulpfile.js
[13:08:24] Starting 'watchSources'...
[13:08:24] Finished 'watchSources' after 4.03 ms
13:08:24 - Starting compilation in watch mode...

Synchronizing program
Files:           367
Lines:        161504
Nodes:        628499
Identifiers:  217633
Symbols:      276782
Types:         57770
Memory used: 296777K
I/O read:      0.05s
I/O write:     0.18s
Parse time:    2.68s
Bind time:     0.86s
Check time:    4.35s
Emit time:     2.93s
Total time:   10.82s
13:08:35 - Compilation complete. Watching for file changes.

13:08:43 - File change detected. Starting incremental compilation...

Synchronizing program
Files:           367
Lines:        161504
Nodes:        628499
Identifiers:  217633
Symbols:      129934
Types:           238
Memory used: 238081K
I/O read:      0.00s
I/O write:     0.00s
Parse time:    0.01s
Bind time:     0.00s
Check time:    0.04s
Emit time:     0.01s
Total time:    0.07s
13:08:43 - Compilation complete. Watching for file changes.

@GregRos
Copy link

GregRos commented Feb 28, 2018

@ivogabe By the following part of my message:

The snippet you posted
Instantaneous

I meant that the .src thing runs instantaneously pretty much.

@marcghorayeb
Copy link

Hello - we're seeing this as well. The incremental builds are an order of magnitude slower than what tsc gives. Any news regarding this?

@GregRos
Copy link

GregRos commented Jun 8, 2018

@marcghorayeb I've pretty much lost interest in this project personally and switched to invoking tsc and gulp separately.

@marcghorayeb
Copy link

@GregRos That's what I'd like to avoid ;) On a side note, how do you handle launching both at the same time?

@GregRos
Copy link

GregRos commented Jun 9, 2018

@marcghorayeb I don't. I keep tsc running and rerun gulp whenever I want to publish/start the application.

@ivogabe
Copy link
Owner

ivogabe commented Jun 11, 2018

I haven't been able to replicate this yet. Could you try this with the latest alpha release? You can install it with npm install [email protected].

@marcghorayeb
Copy link

@ivogabe I tried the alpha.1, unfortunately the results are the same (even worse in most cases).
Previous build during watch (when saving a file, without modifying its content) was taking ~10 seconds, it's taking up twice as long with the alpha.

@goloveychuk
Copy link

goloveychuk commented Jun 25, 2018

Maybe it's possible to use new typescript watch api with gulp?
Example of usage
https://github.com/s-panferov/awesome-typescript-loader/blob/0d39ed51dc02665b1c573c4038d83287c738f997/src/checker/runtime.ts#L142

@marcghorayeb
Copy link

marcghorayeb commented Jun 25, 2018

I've stopped debugging/using this plugin... Lack of time to debug it unfortunately.
@goloveychuk I'm actually using the tsc command line in my gulp workflow. Works quite well.
Here's my setup: https://gist.github.com/marcghorayeb/a092cdac015a960dca6dd87abe8c7b00

@mashaalmemon
Copy link

mashaalmemon commented Oct 1, 2018

Any progress on this issue? It is quite slow for me as well. I'm using:

"gulp-typescript": "^5.0.0-alpha.3"

@mrogunlana
Copy link

Is it safe to assume that this project is abandoned?

@ivogabe
Copy link
Owner

ivogabe commented Dec 2, 2018

I personally don't have enough interest in this issue to invest my time in it, currently. We probably need to adapt a newer API from TypeScript. If someone wants to work on this, I'd suggest to dive into the TypeScript api and we could chat if you run into problems.

@mheiber
Copy link

mheiber commented Feb 20, 2019

I'm interested in this issue, but a prerequisite is understanding what is causing performance issues.
I asked this StackOverflow question about how the incremental compilation currently works: https://stackoverflow.com/questions/54716548/how-does-gulp-typescript-incremental-compilation-work.

If someone following this issue has the knowledge needed to answer the question, I appreciate your help!

@ivogabe
Copy link
Owner

ivogabe commented Feb 25, 2019

I've posted an answer on your StackOverflow question, let me know if anything is unclear.

@mheiber
Copy link

mheiber commented Feb 28, 2019

Thanks @ivogabe , this is very helpful. Do you think it would help if the TS Compiler API enabled us to do async io instead of relying on fs.readFileSync for files not available in the vinyl stream?

@ivogabe
Copy link
Owner

ivogabe commented Mar 1, 2019

I think that the compilation is compute-bound, not IO-bound. Most of the time is spent on the real type checking and the emit, the cost for IO is probably only a small part. Async IO would then not give a (major) improvement in compile times, but it would increase the complexity of the compiler. But that's just my guess, maybe you can somehow profile how much time is spent doing IO stuff. You could maybe benchmark the compiler on a SSD and a HDD and take a look at the difference in compile time.

@DanielRosenwasser
Copy link

@ivogabe I'd watch microsoft/TypeScript#29978, and avoid spinning off a full language service if you don't need to. That can provide incremental subsequent compilations for both --build and non-build mode.

@mheiber
Copy link

mheiber commented Aug 2, 2019

TS Compiler API now supports --incremental 🎉 🎉 !

cc @DanielRosenwasser

@Lej
Copy link

Lej commented Jun 8, 2020

Any progress being made?

If not, is there any easy replacements for gulp-typescript?

1 similar comment
@wcldyx
Copy link

wcldyx commented Jun 18, 2020

Any progress being made?

If not, is there any easy replacements for gulp-typescript?

@pdemro
Copy link

pdemro commented Dec 9, 2020

Thanks to the team for creating gulp-typescript. Would love to see the incremental compile feature fixed! I wish our friends at Microsoft would help pony up a bounty since this is their recommended method for using TypeScript with Gulp

https://www.typescriptlang.org/docs/handbook/gulp.html

Thanks again

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests