🚀

filesize-analysisというGithub Actionを作った話

2022/04/30に公開

GW初日からもくもくと草を生やしている @apple-yagi です。
filesize-analysisというGithub Actionを作ったので紹介します。

filesize-analysis とは

各PRのリポジトリ内にある指定されたディレクトリ内の指定された拡張子のファイルのサイズを取得し、コメントをしてくれるGithub Actionです(こんな感じ↓)。
demo
実際にコメントしているPR

4月29日から作り始めて、本日(4月30)リリースしたので、まだクオリティは低いですが、自分がやりたかった最低限の事はできてると思ってます(プッシュするたびに新しいコメントを作るのがちょっとうざいけど、ファイルサイズの遍歴が見れるからこれはこれでありかも?)。

作った背景

フロントエンド開発において、アプリケーションをビルドした後のファイルサイズは気になるところです。
例えば、Webpackにはwebpack-bundle-analyzerというライブラリがあり、出力されたバンドルファイルのサイズや、バンドルの中に入っているモジュールを確認することができます。

しかし、プルリクエストを出す度にいちいちそういったライブラリでファイルサイズを確認するのは少し面倒です。そして、少し面倒な事はいずれやらなくなります。(そして、バンドルサイズは気付かぬ内に肥大化していく...

そこでエンジニアは、各プルリクエストのコメントにバンドルサイズを表示すれば良いじゃんと思います(私はそう思いました)。
Webpackであれば、以下のようなGithub actionがあります。
https://github.com/chronotruck/webpack-stats-diff-action

このGithub actionは便利なのですが、Github Actionsのworkflowの記述量がとても多くなってしまいます。。。

見たい方はこちらを
name: Diff bundle stats

on: [pull_request]

jobs:
  build-base:
    name: Build base
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v2
      with:
        ref: ${{ github.base_ref }}

    - name: Install dependencies
      run: npm ci
      env:
        NODE_AUTH_TOKEN: ${{secrets.TOKEN_REPO}}

    - name: Build
      run: npm run build-demo

    - name: Upload base stats.json
      uses: actions/upload-artifact@v2
      with:
        name: base
        path: ./demo/demo-dist/stats.json
        retention-days: 1

  build-pr:
    name: Build PR
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v2
  
    - name: Install dependencies
      run: npm ci
      env:
        NODE_AUTH_TOKEN: ${{secrets.TOKEN_REPO}}
  
    - name: Build
      run: npm run build-demo
  
    - name: Upload base stats.json
      uses: actions/upload-artifact@v2
      with:
        name: pr
        path: ./demo/demo-dist/stats.json
        retention-days: 1

  report:
    name: Generate report
    runs-on: ubuntu-latest
    needs: [build-base, build-pr]
  
    steps:
    - name: Checkout PR
      uses: actions/checkout@v2
  
    - name: Download base stats
      uses: actions/download-artifact@v2
      with:
        name: base
        path: base
  
    - name: Download PR stats
      uses: actions/download-artifact@v2
      with:
        name: pr
        path: pr
  
    - name: Get diff
      id: get-diff
      uses: NejcZdovc/bundle-size-diff@v1
      with:
        base_path: './base/stats.json'
        pr_path: './pr/stats.json'
  
    - name: Comment
      uses: NejcZdovc/comment-pr@v1.1.1
      with:
        file: 'comment.md'
      env:
        GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
        OLD: ${{steps.get-diff.outputs.base_file_string}}
        NEW: ${{steps.get-diff.outputs.pr_file_string}}
        DIFF: ${{steps.get-diff.outputs.diff_file_string}}
        DIFF_PERCENT: ${{steps.get-diff.outputs.percent}}

個人的にはCI(typecheck, Unit Test, etc...)用のworkflowの中に軽い気持ちで差し込みたいなと思っていたので、これは。。。となりました。
また、webpack-bundle-analyzerで出力されるstats.jsonからバンドルサイズなどを引っ張ってきているため、esbuildviteを使用したときは使えないのでは?と思っています。

なので、今回filesize-analysisを作成しました。

filesize-analysis のコンセプト

filesize-analysisは前述した背景から以下のようなコンセプトで作成しました。

Github Actionsの記述量を少なくする

filesize-analysisを使用するためのworkflowの記述量はこれだけです。

on:
  pull_request:

permissions:
  pull-requests: write  # PRにコメントするために必要

jobs:
  analysis:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout PR
        uses: actions/checkout@v2

      - name: Install & Build
        run: yarn --frozen-lock && yarn build:production

      - name: Analysis
        uses: apple-yagi/filesize-analysis@v1
        with:
          out_dir: "./dist" # ファイルサイズを表示したいファイルが入っているディレクトリ
          ext: "bundle.js|chunk.js" # ファイルサイズを確認したい拡張子(単数の場合 -> "bundle.js")
          github_token: ${{secrets.GITHUB_TOKEN}}

filesize-analysisを使用するstep以外にも無駄なものを書いてますが、実質最後の6行だけで以下のようなコメントを出力してくれます(便利✨)。
demo

個人的にpermissionspull-requests: writeを与えないといけないところが気に食わないですが、CIの最後とかにスッと入れても良いと思えるくらいの記述量でファイルサイズを教えてくれます🎉

特定のフロントエンドツールに依存しない

ある特定のツール(webpack-bundle-analyzerなど)の出力結果からバンドルサイズを取得してしまうと、別のツール(esbuildviteなど)に乗り換えた時に使用できなくなってしまうので、そういったものに依存しないようにしました。

これを実現するためにユーザーが指定したout_dirextから対象のファイルを抽出し、対象のファイルのサイズを見にいくようにしています。

最後に

この記事を書きながら、もしかしてこんなツールもう作っている人いるかな?と思って少し調べたら、こんなものを見つけてしまい、これで良いじゃん、と自分自身思ってしまってます。。。
https://github.com/marketplace/actions/compressed-size-action
が、filesize-analysispackage.jsonがなくても動く(特定のプログラム言語にも依存していない)ので、別のところで使えるかな(CやGoをビルドした後のファイルサイズとか?)と思ったりしています(diffを出すには特定の言語に縛る必要がある気がしていますが)。

Discussion