kurosame’s diary

日々やったことで気になったことをメモしてます

webpack + TypeScript 環境でのバンドル速度改善

会社の webpack が遅くなってきたので、TypeScript 周りでバンドル速度が改善できるか調べてみました
そして、以下の記述に見つけて、バンドル速度改善をする上で割と重要なオプションな気がしたので実装してみようと思います
GitHub - TypeStrong/ts-loader: TypeScript loader for webpack

今回実装したコードの結果は以下にあげてます github.com

では、簡単ですが実装を説明していきます


実装

ビルドプロセスを並列化する方法として、HappyPackthread-loaderのどちらかを使う方法があるそうです
ただ、HappyPack の GitHub ドキュメントを見ると、HappyPack はメンテナンスモードに入るそうなので、今回は thread-loader を使うことにします

以下のように他の loader の前に記述することで、以降の loader の処理を並列化します
thread-loader は複数の Worker スレッドで loader を実行することで並列化を実現しています

// webpack.config.js
module: {
  rules: [
    {
      test: /\.tsx?$/,
      use: [
        {
          loader: 'thread-loader',
          options: {
            workers: require('os').cpus().length - 1
          }
        },
        'babel-loader',
        'ts-loader',
        'tslint-loader',
        'stylelint-custom-processor-loader'
      ],
      exclude: /node_modules/
    }
  ]
}

thread-loader を使う設定ができたら、次は ts-loader の happyPackMode をtrueにします
happyPackMode をtrueに設定すると transpileOnly オプションが暗黙的にtrueになるみたいです
ts-loader は JS へのトランスパイルと静的型チェックを行ってくれるのですが、transpileOnly オプションをtrueにすると JS へのトランスパイルのみを行います
静的型チェックを行わない場合や他のプラグインで代替する場合は、transpileOnly オプションをtrueにすることでコンパイル速度を上げることができます

// webpack.config.js
module: {
  rules: [
    {
      test: /\.tsx?$/,
      use: [
        {
          loader: 'thread-loader',
          options: {
            workers: require('os').cpus().length - 1
          }
        },
        'babel-loader',
        {
          loader: 'ts-loader',
          options: {
            happyPackMode: true
          }
        },
        'tslint-loader',
        'stylelint-custom-processor-loader'
      ],
      exclude: /node_modules/
    }
  ]
}

次にFork TS Checker Webpack Pluginを使って型チェックを行います
checkSyntacticErrors オプションをtrueにしてますが、HappyPack や thread-loader を使用している場合は必須の設定のようです
Fork TS Checker Webpack Plugin は Syntax エラーと Semantic エラーの両方をチェックする機能を備えているのですが、checkSyntacticErrors オプションはデフォルトはfalseなので Semantic エラーのみをチェックします
しかし、transpileOnly オプションがtrueでも Syntax エラーはチェックするので、checkSyntacticErrors オプションをtrueにする必要は本来は無いのですが、happyPackMode をtrueにした場合は、Syntax エラーはチェックされないみたいなので、checkSyntacticErrors オプションをtrueにする必要があります

分かりづらいですね、、しかも今回やろうとしてる速度改善とはあまり関係がありません
でもとりあえず設定しておいた方が良さそうです
ちなみにこのことは以下の checkSyntacticErrors の説明の所に書いてました
GitHub - Realytics/fork-ts-checker-webpack-plugin: Webpack plugin that runs typescript type checker on a separate process.
翻訳間違ってたらすみません

// webpack.config.js
const ForkTsChecker = require('fork-ts-checker-webpack-plugin')

module: {
  rules: [
    {
      test: /\.tsx?$/,
      use: [
        {
          loader: 'thread-loader',
          options: {
            workers: require('os').cpus().length - 1
          }
        },
        'babel-loader',
        {
          loader: 'ts-loader',
          options: {
            happyPackMode: true
          }
        },
        'tslint-loader',
        'stylelint-custom-processor-loader'
      ],
      exclude: /node_modules/
    }
  ]
},
plugins: [
  new ForkTsChecker({ checkSyntacticErrors: true })
]

実装は以上です


検証

とりあえず実行
f:id:kurosame-th:20190421150748p:plain
約 15 秒
あまり速くなってない。。

試しに thread-loader の Worker の数を 1 つにして実行
f:id:kurosame-th:20190421151046p:plain
こっちの方が倍速いじゃないか!

thread-loader の Worker の数を 2 つにして実行
f:id:kurosame-th:20190421151028p:plain
Worker の数を増やす度に遅くなってる。。😇

原因として今回検証に利用したReact Boilerplateはかなり小規模な検証環境だったので Worker の起動やプロセス間通信にかかるオーバーヘッドの方が大きかったのかなと思います
会社のプロジェクトであれば、そちらはかなり肥大化しているので、今度試してみます