🦕

DenoのスクリプトからDeno実行環境のバージョンを確認し、古い場合に更新を促す方法

2021/08/23に公開

先日、以下のDenoteというサービスを作りました。

https://zenn.dev/kawarimidoll/articles/e00d79b97042ee

こちらのツールをCLIとしてもインストールできるようにしたのですが、そこでDenoのバージョンによるエラーが発生してしまいました。
これに対処するため、Denoのスクリプト内でDeno自体のバージョンを検査する処理を実装したので、やり方を紹介します。

問題:Denoのバージョンによっては--unstableが必要な機能がある

Denoteでは、ローカルでの表示確認用にdenote serveというコマンドを提供しています。
しかし、これを使用した際にDeno.serveHttp(...) is not a functionというエラーが出たという報告が上がりました。

https://github.com/kawarimidoll/denote/issues/2

Deno.serveHttp()はDeno v1.13.0で正式リリースとなったAPIです。それ以前のバージョンでは--unstableフラグを付けて実行する必要がありました。
Denoteでは、ユーザーがv1.13.0未満のDenoを使用していた場合、このエラーが発生します。

https://zenn.dev/magurotuna/articles/deno-release-note-1-13-0

未だv1.13.0リリースから日が浅いため、これは対策を取らなければ再発しうると認識し、以下の二通りの対策を考えました。

  • denoteのインストールスクリプトに--unstableをつける
  • ユーザーにDenoの最新版(というかv1.13.0以降)を使ってもらう

非常に感情的な理由なのですが、せっかく正式リリースになったのにわざわざ--unstableフラグを付けるというのはスマートではないな、と感じます。
今回は2つめの方法を取り、これを検査する処理を追加することにしました。

対処:スクリプト内でDenoのバージョンを調べる

DenoのRuntime APIとして、Deno.versionという定数が用意されています。
ここにはdenov8typescriptというプロパティが含まれているので、Deno.version.denoでDenoのバージョンを取得できます。

https://doc.deno.land/builtin/stable#Deno.version

こうして取得したDenoのバージョンと、スクリプト内で保持する要求最低バージョンとの比較を行います。
バージョンナンバーの文字列の比較になるので、semverモジュールを使うことにしました[1]

https://deno.land/x/semver

具体的には以下のような処理を実装しています。

cli/denote.ts
export { lt as semverLessThan } from "https://deno.land/x/semver@v1.4.0/mod.ts";

const MINIMUM_DENO_VERSION = "1.13.0";

if (semverLessThan(Deno.version.deno, MINIMUM_DENO_VERSION)) {
  console.error("The Deno version you are using is too old.");
  console.error(`Please update to Deno ${MINIMUM_DENO_VERSION} or later.`);
  console.error("To do this run `deno upgrade`.");
  return 1;
}
// 以下略

Deno.version.denoMINIMUM_DENO_VERSION未満のバージョンの場合、エラーメッセージを表示して終了しています。

実際のファイルはこちらです[2]

https://github.com/kawarimidoll/denote/blob/main/cli/denote.ts

なお、この実装はDeno Deployのローカル実行ツールであるdeployctlを参考にしました。

https://github.com/denoland/deployctl/blob/main/deployctl.ts

おわりに

v1.13.0でNative HTTPが正式リリースとなったことで意気揚々と導入したのですが、全てのユーザーが更新に対応できているとは限らない…ということに想像が至っていませんでした。
環境依存の問題というのは公開してみないと表面化しづらいということもあるので、早々に判明してよかったと思っています。

また、今回のように自作ツールに重要な更新を加えても、その更新がユーザーの環境に反映されなければ、これもまた意味がありません。
上記で紹介したdeployctlには、「deployctl自身の更新を監視する機能」と「deployctl自身を更新するサブコマンド」があるため、こちらも導入したいと考えています。

脚注
  1. 今回の比較だとそれほど複雑でもないので、自分で実装しても良かったかもしれません ↩︎

  2. インポート元がdeps.tsだったり、比較部がメソッドに含まれていたりするなど、記事中のコード例とは微妙に異なります ↩︎

Discussion