Skip to content
This repository has been archived by the owner on Dec 1, 2019. It is now read-only.

Speed of Awesome-typescript-loader vs ts-loader #497

Closed
IAMtheIAM opened this issue Sep 25, 2017 · 10 comments
Closed

Speed of Awesome-typescript-loader vs ts-loader #497

IAMtheIAM opened this issue Sep 25, 2017 · 10 comments

Comments

@IAMtheIAM
Copy link

IAMtheIAM commented Sep 25, 2017

After using awesome-typescript-loader for over a year, I decided to switch to TS-loader to test the speed difference. I'm glad I did. My angular 4 webpack-dev-server build went from 41 seconds down to 15 seconds, with absolutely no changes at all to config, only adding fork-ts-checker-webpack-plugin, which awesome-typescript-loader does by default.

Also, since TS-loader is compatible with HappyPack for parallel build processes, I got devserver build time down to 13 seconds. With webpack thread-loader (instead of HappyPack) i got it down to 12 seconds

My AOT production build dropped from 122 seconds down to 93 seconds. With HappyPack/thread-loader, down to 79 seconds. Awesome!!

Awesome-typescript-loader, thanks for your hard work, the plugin works but ts-loader is much faster (for my specific setup) and that is important.

My question is, why is ts-loader so much faster than awesome-typescript-loader - or why perhaps might it be? 30 seconds saving is a lot of time.

In case anyone wants to see my new setup that is down to about 12 seconds, here it is

(this is for Angular 4+)

/**
          * TypeScript loader support for *.ts files
          */

         {
            test   : /\.ts$/,
            exclude: [ENV !== 'test'
               ? /\.(spec|e2e)\.ts$/
               : '//'],
            use    : [

               // {
               //    // If any of the npm packages or loader configutation changes, you need to invalidate/delete the .cache folder. It should happen automatically though.
               //    loader: 'cache-loader',
               //    options: {
               //       cacheDirectory: isDevServer
               //          ? Helpers.root('./.cache/cache-loader/dev/[confighash]')
               //          : isDebug
               //              ? Helpers.root('./.cache/cache-loader/debug/[confighash]')
               //              : Helpers.root('./.cache/cache-loader/prod/[confighash]')
               //       }
               //    },
               {
                  loader : '@angularclass/hmr-loader',
                  options: {
                     pretty: !isProduction,
                     prod  : isProduction
                  }
               }, {
                  /**
                   * Lazy Module loader
                   *  MAKE SURE TO CHAIN VANILLA JS CODE, I.E. TS COMPILATION OUTPUT.
                   */
                  loader : 'ng-router-loader',
                  options: {
                     loader: 'async-import',
                     genDir: 'compiled',
                     aot   : AOT
                  }
               }, {
                  loader : 'thread-loader',
                  options: {
                     // there should be 1 cpu for the fork-ts-checker-webpack-plugin
                     // workers: require('os').cpus().length - 1,
                     workers: isDevServer
                        ? 3
                        : require('os').cpus().length - 1 // fastest build time for devServer: 3 threads; for production: 7 threads (os cpus minus 1)
                  }
               },

               {
                  loader : 'ts-loader',
                  options: {
                     // disable type checker - we will use it in fork plugin
                     transpileOnly: true,
                     happyPackMode: true
                  }
               }, {
                  loader: 'angular2-template-loader'
               }]
         },

Basically you just pipe ts-loader to thread-loader.

As an EXTRA bonus, I just learned about hard-source-webpack-plugin. Using this plugin affects the above config like this, taking it from 14 seconds to:

Initial build: 22 seconds (twice as slow)
Rebuild: 6 seconds (double as fast)

What is does is write cache to disk, and makes it slower at first, but really fast on rebuild.

Here's how to enable that. I set it up to use a different cache for webpackDevServer, debug-production, and production build.

plugins: [
 /**
       * Makes a hard cache of webpack builds to speed up build times.
       *
       * Increases initial build time by double but decreases subsequent rebuilds by 2X-4X
       * If any of the npm packages or any webpack configutation changes (excluding comments), a new cache will be generated automatically, and the old can be
       * deleted manually.
       *
       * See: https://github.com/mzgoddard/hard-source-webpack-plugin
       */

      new HardSourceWebpackPlugin({
         cacheDirectory : isDevServer
            ? Helpers.root('./.cache/hard-source/dev/[confighash]')
            : isDebug
               ? Helpers.root('./.cache/hard-source/debug/[confighash]')
               : Helpers.root('./.cache/hard-source/prod/[confighash]'),
         recordsPath    : isDevServer
            ? Helpers.root('./.cache/hard-source/dev/[confighash]/records.json')
            : isDebug
               ? Helpers.root('./.cache/hard-source/debug/[confighash]/records.json')
               : Helpers.root('./.cache/hard-source/prod/[confighash]/records.json'),
         configHash     : require('node-object-hash')({ sort: false }).hash,
         environmentHash: {
            directories: ['node_modules'],
            files      : ['npm-shrinkwrap.json', 'yarn.lock'],
            root       : process.cwd()
         }
      }),
]

An alternative version of HardSourceWebpackPlugin is cache-loader. Its very similar, but a little faster on initial and a little slower on rebuild compared to HardSourceWebpackPlugin

Instead of being a plugin, its a loader, that goes as the very FIRST loader in the array, which means its the last loader executed by webpack. It is commented out in my example above for reference.

I hope this helps!

@domehead100
Copy link

I have an uneducated guess, something to do with relying on Typescript's own module resolution logic. We've been using at-loader in a small project inside of a larger project, so there are nested node_modules folders. I was getting errors on modules I don't even use (not in my package.json, not imported in any code I'm using) because TS apparently goes searching for a whole crapload of type definitions for libraries that "might be somewhere in the folder tree, regardless of whether they're actually used or not." I found that there were 163K CreateFile calls looking for *.d.ts files (this api is also used to open files on Windows) when attempting to build my small project.

Putting some typeRoots in the tsconfig.json helped some, but I've switched to ts-loader and it's running noticeably faster with forking in place.

Again, just a wild guess :).

@gregbown
Copy link

gregbown commented Oct 9, 2017

@IAMtheIAM verified, My JIT/development Angular build went from 40 seconds down to 14 seconds.
AOT/production build is altogether different so not really an option there.

Once I figured out the right HappyPack configuration got it down to 12 seconds!

    module: {
      rules: [
        {
          test: /\.ts$/,
          use: [
            { 
              loader: 'ng-router-loader',
              options: {
                loader: 'async-import',
                genDir: 'compiled',
                aot: AOT
              }
            },
            // 40 Second dev build
            // {
            //   loader: 'awesome-typescript-loader',
            //   options: {
            //     configFileName: 'tsconfig.webpack.json'
            //   }
            // },
            // 12 Second dev build
            {loader: 'happypack/loader?id=ts'},
            {
              loader: 'angular2-template-loader'
            }
          ]
        },
...
    plugins: [
      /** Use only when using ts-loader  */
      new ForkTsCheckerWebpackPlugin({ checkSyntacticErrors: true }),
      new HappyPack({
        id: 'ts',
        threads: 2,
        loaders: [
          {
            path: 'ts-loader',
            query: { happyPackMode: true }
          }
        ]
      }),

Thank you for the tip!

@s-panferov
Copy link
Owner

Thank you for your feedback guys. I see that most of performance errors are coming from folks using angular2 stack on Windows OS. Personally I use neither Angular nor Windows, so it is very hard for me to debug this problem. ATL still works faster for my own tasks (and my company tasks). If you found out that ts-loader works faster for you — this is great.

I'm leaving this open for documentation reasons, but I doubt that I can do anything without a really deep investigation.

@MariMax
Copy link

MariMax commented Nov 10, 2017

With recent update to Angular 5 we had a huge performance issue on our CI:
[at-loader] Using [email protected]
[INFO] Time: 446008ms

[at-loader] Using [email protected]
[INFO] Time: 1007675ms

temporary solution was to downgrade typescript.
Are there any plans for looking into this?

@s-panferov
Copy link
Owner

s-panferov commented Nov 17, 2017

I believe that some critical performance problems were fixed in #517 (version 3.4.0-0), so please give it a try :-)

@MariMax
Copy link

MariMax commented Nov 17, 2017

@s-panferov works even faster than before
local build times:
TS 2.5.3
Time: 69559ms
TS 2.6.1
Time: 42355ms
Thanks for that 👍

@ozknemoy
Copy link

ozknemoy commented Feb 3, 2019

for me awesome-typescript-loader (TS ^3) initial build(with WDS) 70-80s and incremental - 0.8(!)s. when ts-loader 30s (initial) and ~5s(incremental). i did a lot of research (hard-source-webpack-plugin, autoDll plugin, etc etc) and none of solutions have better incremental time(for dev its most needed then initial build time)

@bengrunfeld
Copy link

bengrunfeld commented Apr 25, 2019

Firstly, I think awesome-typescript-loader truly is an awesome project 😉. Thank you for taking the time to create this excellent tool!! That said, here are results from today using the Unix time command. The results are from real, and not user or sys. Run on a MacBook Pro 2015 model (MacOS Sierra). The project is React and Redux based with some TypeScript love. I tried to implement Webpack's thread-loader but couldn't because, apparently, I'm a muppet. Full project can be found at https://github.com/bengrunfeld/mathochist. Please let me know if I'm not using ATL properly.

ATL Dev build: 0m38.939s
ATL Prod Build: 0m43.913s
ts-loader Dev Build: 0m27.057s
ts-loader Prod Build: 0m35.233s
ts-loader Dev Build with ForkTsCheckerWebpackPlugin: 0m26.526s
ts-loader Prod Build with ForkTsCheckerWebpackPlugin: 0m27.525s

@fatso83
Copy link

fatso83 commented Nov 12, 2019

@ozknemoy What is "WDS" in your comment? Webpack-...?

@ozknemoy
Copy link

@fatso83 webpack dev server

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

No branches or pull requests

8 participants