概要
この記事ではDenoからリリースされた新しいパッケージレジストリであるJSRについて紹介します。JSRはTypeScriptとES Modulesで実装されたパッケージのためのレジストリです。
JSRを利用することで以下のようなメリットを享受しながらパッケージを利用した開発を行うことができます。
- ソースコードをもとにした充実したドキュメント
- ライブラリの実装をエディタ上で直接確認
JSRの仕組み
JSRにはTypeScriptとES Modulesで実装されたパッケージのソースコードを直接アップロードします。JSRのWebサイト上でこのソースコードやコメントから自動生成されたドキュメントを読むことができるようになっています。例えばWebサーバライブラリのoakのページを見てみましょう。
パッケージ内のモジュールやクラスなどが階層化されたページになっています。
それらのページで型情報やドキュメントを読むことができ、使い方を知ることができるようになっています。
同様の仕組みにdeno.land/xがあります。
こちらがDenoのパッケージレジストリであるのに対して、JSRはDeno以外のJavaScript/TypeScriptランタイムから利用することも念頭に置かれています。例えばNode.jsなどのTypeScriptを直接実行できない環境でもJSRのパッケージを利用することができるようになっています。その場合、JSRが自動的にビルドを行なってnode_modulesディレクトリにビルド済みのファイルがダウンロードされます。
こうした点から、JSRはJavaScript/TypeScriptエコシステム全体で利用できるパッケージレジストリとして考えられていることがわかります。パッケージの作成者はTypeScriptとES Modulesで実装している場合、JSRに直接アップロードするだけでどのランタイムでも利用できる形で配布することができます。
JSRのパッケージを利用する
JSRの利点をフルに活用できるのはTypeScriptを直接実行できるDenoから利用した場合です。あらかじめDenoとVSCodeの拡張機能をインストールしておきます。
Denoでは以下のコマンドでJSR上のパッケージをインストールすることができます。
deno add @oak/oak
このコマンドを実行すると以下の内容のdeno.json
ファイルが作成されます。
{
"imports": {
"@oak/oak": "jsr:@oak/oak@^14.2.0"
}
}
index.tsを作成してoakライブラリを使った簡単なWebサーバを書いてみましょう。
import { Application } from "@oak/oak/application";
import { Router } from "@oak/oak/router";
const router = new Router();
router.get("/", (ctx) => {
ctx.response.status = 200;
});
const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());
app.listen({ port: 8080 });
以下のコマンドでサーバーを起動します。deno run
コマンドを実行したタイミングでDenoがJSRからライブラリをダウンロードしてdeno.lockファイルを作成します。
deno run --allow-net index.ts
(動作確認)
curl localhost:8080 -I
HTTP/1.1 200 OK
content-length: 0
...
これでローカル環境にoakのソースコードがダウンロードされた状態になっています。そのため例えばインポートしたApplication
クラスを選んでVSCodeの「Go to Definition」機能を利用するか、F12キーでoakのソースコードにジャンプすることができます。
ただしNode.jsなどからJSR上のパッケージを利用する場合はエディタ上でソースコードを直接確認することはできません。この場合はパッケージがビルドされてダウンロードされているためです。この点がDenoがJSRの利点をフルに活用できる理由です。
JSRの素晴らしさ
以上がJSRの基本的な使い方です。これらの特徴の何が素晴らしいのかを以下で述べていきます。
まずWebサイト上でのパッケージのドキュメントがnpmよりも格段に充実します。npmのライブラリのページではREADME.mdの内容しか確認することができません。
これはnpmにはソースコードではなくパッケージのビルド済みファイルがアップロードされているためです。JSRにはソースコードをアップロードするため実装内容を直接確認することができます。さらに型情報やコメントとして書かれたドキュメントが自動的にWebサイトに変換されているため、GitHubでソースコードを確認する場合よりも読みやすくなっています。
またnpmのライブラリはビルド済みのファイルがダウンロードされるので、VSCodeなどのエディタでライブラリの実装内容を確認することができません。JSRではソースコードを直接ダウンロードすることができるため、利用している外部ライブラリが実際にどんな処理を行なっているのか直接確認することができます。
筆者個人としてnpmの外部ライブラリの実装内容を確認することができないことが非常に不便だと感じていました。型定義だけ分かっても実際の実装内容が分からないため、ライブラリの動作や利用方法を理解するのに非常に時間がかかっていました。JSRの登場によりこの問題が解決されることになります。
TypeScriptネイティブな世界観
JSRが開発された背景にはTypeScriptとES Modulesが普及したこと、またNode.js以外のJavaScriptランタイムの登場があるとされています。
筆者はDenoを「TypeScriptのランタイム」として捉えています。Denoではトランスパイラやバンドラの存在を意識せずに直接TypeScriptを書いて実行することができます。このようなTypeScriptネイティブなランタイムに加えて、JSRが登場したことでTypeScriptネイティブな世界観がより一層強化されることになります。
ライブラリの開発者も多くの場合TypeScriptで開発しています。そしてそのユーザーもTypeScriptで開発するわけで、一度ビルドしてから配布する必要はそもそもないはずです。つまりライブラリの開発者が実装したTypeScriptのソースコードをそのままダウンロードして利用するのが理想的です。JSRはそれを実現するための仕組みと考えることができます。
例えばRustなどコンパイル言語のパッケージレジストリはソースコードを直接アップロードして、それぞれのユーザーがダウンロードしてコンパイルする仕組みになっています。
そのためソースコードの情報とコメントから自動的にドキュメントを作成することができます。Rustのライブラリはdocs.rsというサイトで詳細な実装内容やドキュメントを確認できるようになっています。
JSRはこのようなコンパイル言語のパッケージレジストリの仕組みをTypeScriptの世界に持ち込んだと言えます。TypeScriptも結局はコンパイルに似た操作をおこなってから実行するので、パッケージレジストリに直接実行可能なファイルをアップロードする必要はないはずです。むしろソースコードを直接アップロードする仕組みのレジストリの方が、上記のようなメリットを得ることができて便利になります。
まとめ
この記事ではTypeScriptのための新しいパッケージレジストリであるJSRについて紹介しました。JSRを利用するとソースコードをもとにした充実したドキュメントを読むことができ、またライブラリの実装を直接確認しながら開発することができます。筆者個人としてnpmを利用した開発の不便さを解消するための素晴らしい仕組みだと感じています。ただしまだ新しいパッケージレジストリなので、今後JSRが普及していくことを期待しています。
参考文献