Speed of Awesome-typescript-loader vs ts-loader
IAMtheIAM opened this issue ยท 10 comments
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!
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 :).
@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!
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.
With recent update to Angular 5 we had a huge performance issue on our CI:
[at-loader] Using typescript@2.5.3
[INFO] Time: 446008ms
[at-loader] Using typescript@2.6.1
[INFO] Time: 1007675ms
temporary solution was to downgrade typescript.
Are there any plans for looking into this?
I believe that some critical performance problems were fixed in #517 (version 3.4.0-0), so please give it a try :-)
@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 ๐
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)
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