本セッションの登壇者
セッション動画
よろしくお願いします。Denoの最近の動向について話していきます。
さっそくですが、2022年6月にDenoは資金調達をしました。2100万ドル(約29億3600万円)という、この界隈ではかなり大きめな調達だったのでざわざわしたりしました。

7月にはBunというけっこう有力なライバル企業が登場してきて、Deno社内はざわざわしたりしていました。

そして、8月にnpm互換性をリリースして、これはかなり反響が大きかったです。

10月には「Deno Offsite」というイベントが開催されて、「Deno社員が初めてオフラインで会う!」みたいなことが起こったりしました。

そんなイベント盛りだくさんだった2022年でしたが、2022年のDenoの変化のキーとなったブログポストというものがありまして、それが8月に掲載された「Big Changes Ahead for Deno」です。今日はおもにこの話をしようと思います。

ここでちょっと簡単に自己紹介なんですけど、「ひのさわ」といいます。Twitterは@kt3kというアカウントでやっています。2009年からWebエンジニアをしていて、2011年からDenoの開発会社であるDeno Landのソフトウェアエンジニアとして働いています。Deno歴、Denoとの関わりで言うと、プロジェクト初期の2018年からOSSとしてのDenoにずっとコントリビュートしていて、2020年末ごろに作者に誘われてDeno Landに転職しました。現在はフルタイムでDenoとDeno Deployを開発しています。直近で言うとかなりDeno側の比率が自分は多くなっています。

本日のアジェンダです。Deno全体のおさらいをして、さっき言った「Big Changes Ahead for Deno」の話をします。

開発者体験にフォーカスしたJSランタイム
知っているという人もいると思いますがもう一度おさらいすると、Denoとは開発者体験(DX)にフォーカスしたJavaScript runtimeです。

どういう点がDXにフォーカスしているのかというと、ひとつにはビルトイン開発ツールがあります。「deno lint」「deno fmt」「deno test」のようなツールがビルトインで実装されていて、Nodeで言う「prettier」「eslint」「jest」「vitest」に対応するものです。サードパーティに頼らなくてもこういった基本的な開発ツールが全部手元に揃っているという特徴があります。

ほかには、TypeScriptビルトインというものがあります。NodeでTypeScriptを利用するとなると、TypeScript自体をインストールして、TSやTSに対応するバンドルアダプタをインストールして…とインストールが多く、さらにtsconfigでcompiler optionsを書かなければなりませんが、こういった設定が不要なので便利です。

また、モジュール機構がとても整理されています。NodeやBunでは、CJSかESMかという話があるんですね。モジュールモードかスクリプトモードかで言語としても微妙に違うところがあって、その結果、.cjs、.mjs、それに対応したTSの.cts、.mtsといった拡張子があったり、パッケージなので "type": "module|commonjs"
みたいなことを書いたりという、かなり複雑なものがあるんですけど、Denoだと整理されてESM onlyになっています。その結果として、.tsと.jsしかありません。

先日、こういうミームをTwitterに流してみたのですが、わりと多くの人が同意してくれました。.jsや.tsだけで書きたいというのは皆さん思っているようです。

強固なセキュリティと豊富なWeb API
DenoのDXでほかに良いところとしては、サプライチェーン攻撃に対する防御機構がすでにビルトインされていることが挙げられます。Nodeも作ろうとしているという話がありましたが、まだできてないようです。たとえばここで deno run
という実行コマンドを打って実行したときに、サプライチェーン攻撃が含まれているとします。たとえばgoogle.evilserver.comにクレデンシャルを盗んで送る攻撃が仕込まれてしまったときに、Denoはこのような感じで「そこにアクセスしていいですか?」と聞いてきます。ここでdenyを選べば、何も盗まれずに済みます。

これをどうやって実現しているかというと、内部でV8のサンドボックス機構というものをうまく活用しています。詳細は公式ドキュメントの「Permissions」ページを参照してください。

また、DenoのDXの良い点として、Web互換APIがたくさんあります。fetch()
とか TypedArray
とか prompt()
とか、ほんの一例ですがこのようなものがあります。

ブラウザで使える同じ知識でDenoのコードを書けるので、よけいなAPIを覚えなくてよいということですね。すべてのリストが「list of every web API」というブログ記事に載っているので、よければ見てみてください。

このような感じで、DenoはJS runtimeのあるべき姿というのを模索しているのかなと思っています。
Denoの3つの「Big Changes」
さて、今日の本題の「Big Changes Ahead for Deno」の話に入っていこうかと思います。Bunが出た話にも少し関係するのですが、「今までDXにフォーカスしてDenoを作ってきたけどちょっと変えなきゃいけないことがあるよね」ということで、どういう点を変えていくのかという思想のようなものを8月に発表しました。

その中で、今後起こる3つの変化を記載しています。1つ目が「npm互換性をやります」という話です。npmを何らかの形でDenoから使えるようにするということをブログ記事の中で言いました。この時点ではまだどういうふうに互換されるのかというのは決まっていませんでした。
2つ目の軸として「パフォーマンスを向上します」と宣言しました。この記事の時点でも、DenoのたとえばHTTPのパフォーマンスは、Nodeと比べて互角か若干優位ぐらいのパフォーマンスが出ていたのですが、そこで満足せずにもっとパフォーマンスを上げていく、そして最も速いJS runtimeであることを常に目指すということを表明しました。
3つ目としては今までの延長線ですが、「DXをもっと向上していきます。とくにモジュールの検索性にフォーカスして機能拡張していきます」ということを言いました。
これらを宣言した結果として、社内ではこの3つにかなりフォーカスした作業をすることになりました。それがどういう結果になったかというのを見ていきましょう。

npm互換性 - npm: specifier
npm互換性については、8月に入れると宣言して、ちょうど今週月曜(11/14)にnpm: specifierというものを正式に導入することになりました(参考ブログ)。
このサンプルのように npm:express
という形でnpmモジュール名を npm:
という独自のURLのようなものからインポートできます。このサンプルで言うと、import express from "npm:express";
でnpmモジュールが自動的にダウンロードされて、さらに展開されてインポートされて、npmモジュールのexpressがDenoの中で動きます。このサンプルを最新版のDenoで実行すると、ポート3000でサーバが立ち上がって Hello World!
を表示できるようになりました。

ちなみに自分はこの辺の作業を主にやっていて、とくにspecifier自体ではなく、npm互換の中で動くNode.jsのshimのAPIを実装し直す作業を主にしています。Deno標準モジュールの中のnode/
というディレクトリがあって、そこの下にNode.jsの lib/
というものがあるんですけど、それをひたすらAPIとして移植をしています。

パフォーマンス向上 - すでに高速だったDenoをさらにチューン
2つ目の軸のパフォーマンス向上については、このためにDenoの社内でパフォーマンスだけを専門的にやるチームが発足しました。その成果として、Deno.serveという新しいAPIを作ることになりました。社内でのコードネームは「Flash」と呼ばれており、開発中です。すでに既存のHTTPであるDeno.serveHttpより圧倒的に速いパフォーマンスが出ています。

新しいホームページでは、HTTP1.1でのパフォーマンスをwrkというベンチマークツールで1秒間に何リクエスト処理できるか(リクエスト/s)というベンチマークを取っています。Denoでは1秒に200kリクエスト処理できて、Nodeでは90kになっています。ただの「Hello World」のHTTPサーバだとNodeの倍ぐらいパフォーマンスがすでに出るようになっています。ちなみにBunは、ここに載せていませんが175kちょいなので、「Hello World」のHTTPでは今はDenoのほうがパフォーマンスが良いという状態になっています。

DX向上 - 検索性の改善を
3つ目の軸のDX向上ですが、まずどうしてここにフォーカスするという形になったのかというと、Denoはモジュールの検索性がすごく悪いという問題がありました。npmではnpm自体がnpm searchのようなサービスをマージして持っていて、コードの人気度やクオリティといったいろいろな軸でindexingしてあるなど、モジュールが適切に検索できる工夫がされています。それがnpmの強さのひとつでもあるのですが、Denoはそこにかなり遅れを取っていたということがありました。
例として、Deno界で一番有名な「oak」というWebフレームワークをDenoのレジストリで検索すると、なぜかoakではないものが1ページ目の10エントリ分を占めてしまって、oakは2ページ目の一番上に出てくるといった残念な状況になっていました。

それを8月以降に改善して、今では人気順というものを加味できるようになりました。今では普通にoakを検索したらoakが一番上にくるようになっています。

ここにとどまらず、DX向上について、シンボル検索というものを実装しました。シンボル検索というのはモジュール単位の検索ではなく、exportされているすべてのシンボルを検索の対象として横断的に検索するものです。モジュール検索のようにサードパーティだけを検索するのではなく、本体のAPI、標準モジュールのAPI、サードパーティのAPIのexportされているすべてのシンボルを混ぜて、その中から横断的に検索できます。これはもう実装されています。

このようにDenoのホームページの一番上からこの検索ボックスを表示できて、たとえば assert
と入力すると「シンボル」タブの中で「assert」という標準のAPIや、「assertThrows」「assertSnapshot」などサードパーティを含めた「assert*」というAPIを全部表示できます。この検索はたぶんNodeでは難しくて、最初からESMに絞って、exportされているものが静的に全部解析できるDenoのシステムならではの機能かなと思います。

このようにBig Changesで3つの軸を出したことで、Denoの中でプライオリティがかなり明確化されて、目的意識を持った深い開発ができるようになったかなと思っています。
まとめ
まとめですが、DenoはDXにフォーカスしたJavaScript runtimeです。現在のDenoは「パフォーマンス」「npm互換」「開発体験向上」の3つの軸で開発が進んでいます。

ちょっと早いですが以上になります。ありがとうございました。