JavaScriptに関するお知らせ

SINCE2019
>
【JS】Voltaのバージョン指定を単一のファイルに切り出す

【JS】Voltaのバージョン指定を単一のファイルに切り出す


こんにちは!Voltaの便利だけどちょっと融通がきかない所が愛おしいMizutani(@sirycity)です。pnpmのサポートはまだかな〜

今日はVoltaのバージョン指定部分を単一のファイルに切り出す方法と、そのメリットについてです。

結論

package.jsonにこれを書いて

{
  "volta": {
    "extends": "./volta.json"
  }
}

volta.jsonにこんな感じに書けばOK。

{
  "volta": {
    "node": "16.1.0",
    "yarn": "1.22.10"
  }
}

こちらを参考にしています。

Support alternative version pinning mechanism · Issue #282 · volta-cli/volta

はじめに

VoltaはNode.jsのバージョン管理ツールです。nodenvとかの仲間です。npmとかyarnのバージョンも管理できるのが特徴です。

問題?

Voltaは「nodeのバージョンはこれ!」みたいな情報をpackage.jsonに書きます。例えばvolta pin node@16.1.0って実行すると...

{
  "volta": {
    "node": "16.1.0"
  }
}

こんな感じになります。別にこんだけの話なので特に問題は無いんですが、voltaの設定だけで単独のファイルを作りたくないですか?package.jsonはあくまでライブラリの情報だけにしたいです。例えばESLintとかも.eslintrc.jsってファイルに設定書いていく方法がわりとベターかとも思いますが、べつにpackage.jsonの中に書いてしまうこともできます。まあ、この辺りは好き嫌いによる所も大きいかとは思いますけどね。

ちなみにnodenvは.node-versionっていうファイルを用います。もっと言うとこのnode-versionをvoltaで使えるようにしようって提案もあったりします↓

Support alternative version pinning mechanism · Issue #282 · volta-cli/volta

単一のファイルに切り出し

現時点ではvoltaが参照するのはpackage.jsonのみです。こういう名前のファイルを勝手に参照してくれる...みたいな機能はありません。残念。

なので、単一ファイルに切り出すには

  • 任意の名前のjsonファイルを作ってnodeのバージョンとかを記述
  • そのファイルをpackage.jsonから参照

の2工程が必要です。ちょっとめんどい。

任意の名前のjsonファイルを作成し記述

適当なjsonファイルを作りましょう。volta.jsonとかでいいでしょう。そしたらそこにバージョン情報書きます。ちなみにこの時voltaコマンドは使えません。voltaコマンド使うとpackage.jsonに書かれちゃうからね。

{
  "volta": {
    "node": "16.1.0",
    "yarn": "1.22.10"
  }
}

余談ですが、voltaは設定系は直接ファイルいじって大丈夫です。コマンド使うのと全く変わりません。

そのファイルをpackage.jsonから参照

そしてpackage.jsonに書くのはこんだけ。

{
  "volta": {
    "extends": "./volta.json"
  }
}

これはこのファイルから設定引き継ぐよって意味です。だからファイル名をvolta.json以外にしたらここも変えてね。

別ファイルにするメリット

見た目が綺麗ってのもありますが、別ファイルにする最大のメリットはキャッシュのキーにできるって点です。僕がよく使うGitHubActionsを例にしますが、JS系の開発ではnode_modulesをlockファイルの内容に応じてキャッシュするってのをよくやります。なぜならlockファイルが同じならnode_modulesは同じになるからです。毎回出力が同じなら、毎回インストールしなくてもとっておけばいいじゃん!みたいな発想。こんな感じ。

# node_modulesをキャッシュ
- uses: actions/cache@v2
  id: yarn
  with:
    path: node_modules
    key: yarn-${{ hashFiles('yarn.lock') }}
    restore-keys: yarn-

# node_modulesを生成(ただしキャッシュに引っかからなかった時のみ)
- name: install
  if: steps.yarn.outputs.cache-hit != 'true'
  run: yarn install --frozen-lockfile

↑の例だとyarn.lockが変更されない限りはnode_modulesの生成はパスされ、同じのが使われ続けます。

ただしこれには穴があって、yarn.lockが一緒でもnode_modulesが変わることがあります。それはnodeのバージョンが変わった時。厳密には他にも色々あるけど。本来生成されて然るべきnode_modulesが変わったのに、変わる前のnode_modulesを使い続けたりしたらたいへん。不具合の元です。

じゃあどうするかと言うと、nodeのバージョンが変わったらキャッシュをリセットすれば良いわけです。簡単だね。んで、nodeのバージョンはvolta.jsonに書いてあるわけですからそいつをキャッシュのキーに指定してやれば良いわけ。keyの部分をこんな感じに変更してやりましょう。

key: yarn-${{ hashFiles('volta.json') }}-${{ hashFiles('yarn.lock') }}

...とはいえ、実はこれでも完璧じゃないです。OSのバージョンとかもキーにした方がいいですね。

これだけ見るとvolta.jsonに切り出さなくてもpackage.json指定すればよくね? って思うかもしれませんが、そうするとバージョンに直接関係ないpackage.jsonの内容を変更した時にキャッシュが不必要にリセットされちゃいます。例えばnpm script変更した時とかね。

結論

voltaは新進気鋭のバージョン管理ツールなのでまだ仕様変更があるかもしれませんが、今の所はこのテクニックが使えるかと思います。将来的にはESLintみたいに.voltarc.jsみたいなJSファイルをネイティブサポートしてくれると嬉しいですね!以上。



PREV
2021-05-14
【JS】yarnからnpmに戻った僕が再びyarnにした理由

NEXT
2021-05-17
gitでaddとcommitとpushを一気に行う方法