TypeScriptを使うとBabelよりwebpackのバンドル速度が低下しました
上記のようにバンドル後のサイズが379kb程度だと約8秒かかってます
ちなみにBabelだと以下です
約2.5秒なので、約5.5秒の差があります
webpackの設定を比べてみると
■ Babelの場合
{
test: /\.js$/,
use: 'babel-loader?cacheDirectory',
exclude: /node_modules/
}
Babelは
ES2015をbabel-loaderでES5に変換
しています
■ TypeScriptの場合
{
test: /\.ts$/,
use: [
{
loader: 'babel-loader?cacheDirectory'
},
{
loader: 'ts-loader',
options: {
appendTsSuffixTo: [/\.vue$/]
}
}
],
exclude: /node_modules/
}
このようにTypeScriptの場合は、
TypeScriptをts-loaderでES2015に変換
ES2015をbabel-loaderでES5に変換
しているため、ts-loaderの変換の部分が遅くなってる原因だと分かります
今回はts-loaderの速度アップのため、2つの改善を行いました
どちらも簡単に設定できるので、Vue.js + TypeScript + webpackを使ってる人は試してみてください
全体のコードはこちらになります
https://github.com/kurosame/vuejs-boilerplate
ts-loaderを並列実行する
トランスパイルと型チェックを並列実行させます
具体的にはts-loaderはJSに変換するトランスパイルのみを行い、
型チェックはFork TS Checker Webpack Pluginというプラグインで(並列で)行います
https://github.com/Realytics/fork-ts-checker-webpack-plugin
$ yarn add --dev fork-ts-checker-webpack-plugin
const ForkTsChecker = require('fork-ts-checker-webpack-plugin')
...
{
test: /\.ts$/,
use: [
{
loader: 'babel-loader?cacheDirectory'
},
{
loader: 'ts-loader',
options: {
appendTsSuffixTo: [/\.vue$/],
transpileOnly: true // このオプションを追加
}
}
],
exclude: /node_modules/
}
...
plugins: [
new ForkTsChecker()
]
約2秒位速くなりました
キャッシュを使う
2通り方法があります
HardSourceWebpackPlugin
初回のwebpack実行時にnode_modules/.cache/hard-source
配下にキャッシュを作り
2回目以降のwebpack実行からはキャッシュを使います
$ yarn add --dev hard-source-webpack-plugin
const HardSource = require('hard-source-webpack-plugin')
...
plugins: [
new HardSource()
]
約3.5秒位速くなりました
Fork TS Checker Webpack PluginとHardSourceWebpackPluginを2つ使うことで
最初の約8秒から約2.5秒まで短縮させることができました
ただし、このプラグインのトラブルシューティングを見てみると
webpackとwebpack-dev-serverで同じwebpack.configを使っていても、それぞれ異なるキャッシュを持つ必要があるみたいです
https://github.com/mzgoddard/hard-source-webpack-plugin#troubleshooting
よってwebpack-dev-serverやNuxt.jsを使っている場合は、別途設定が必要で
webpack-dev-serverの場合は、contentBaseオプションに指定したディレクトリがルートになるので、
以下のような指定が必要になるかもしれません
new HardSource({
cacheDirectory: '.cache/hard-source/[confighash]',
})
Cache Loader
HardSourceWebpackPluginと同様に初回実行時にキャッシュを作り、2回目以降の実行からキャッシュを適用します
こちらはloader専用でloader個別に設定できます
$ yarn add --dev cache-loader
{
test: /\.ts$/,
use: [
{
loader: 'babel-loader?cacheDirectory'
},
{
loader: 'ts-loader',
options: {
appendTsSuffixTo: [/\.vue$/]
}
}
// ここから追加
{
loader: 'cache-loader',
options: {
// こちらのオプションは無くてもいいですが、デフォルトだとプロジェクトルート直下に
// キャッシュディレクトリを作るので、node_modules配下に作るように変更してます
cacheDirectory: path.resolve(
__dirname,
'node_modules/.cache/cache-loader'
)
}
},
// ここまで
],
exclude: /node_modules/
}
こちらも約3.5秒位速くなりました
HardSourceWebpackPluginと比べると若干遅いです
どっちを使うか
HardSourceWebpackPluginの方が設定も簡単で、速いっぽいので
基本的にはこちらの方が良いでしょう
ただし、HardSourceWebpackPluginと比べてcache-loaderはキャッシュの影響範囲を指定できるので、
HardSourceWebpackPluginで不具合起きる時は、部分的にキャッシュを導入できるcache-loaderを使った方が良い時もあると思います
https://github.com/webpack-contrib/cache-loader/issues/11
こちらのissuesで言われている通り、HardSourceWebpackPluginとcache-loaderを同時に使うことや
また、cache-loaderをあまり効果が望めないloaderに設定することは
キャッシュの生成コストやメンテナンスコストを増やすことになるだけなので止めましょう
補足
ts-loaderよりawesome-typescript-loaderを使った方が速いみたいですが、
前に試した時にVue.jsだと使えなかったので、ts-loaderを使ってます
他にも以下を試しましたが、あまり効果が出なかったので省きました
thread-loader
https://github.com/webpack-contrib/thread-loader
HappyPack
https://github.com/amireh/happypack