Deno 1.0.0 がリリースされて、ちょっと遊んでみたので、その感想。

圧倒的ゼロインストール感

自分は mac なので brew install deno しました。deno コマンドが入ります。セットアップはこれで終わり。

GitHub の trending に上がっていた https://github.com/oakserver/oak という web server を試してみます。

// server.ts
import { Application } from "https://deno.land/x/oak/mod.ts";
const app = new Application();

app.use((ctx) => {
  ctx.response.body = "Hello World!";
});

await app.listen({ port: 8000 });

このコードを保存して、実行します

deno run --allow-net server.ts

これだけ。コマンド実行時に https://deno.land/x/oak/mod.ts から依存がダウンロードされて、サーバーが立ちます。

ここで、インストールコマンドを何も叩いてないのに注目してください。Deno では実行時に URL が静的に解決されて実行されます。パッケージや package.json といったものがありません。

--allow-net も特徴的ですね。deno ではデフォルトでは権限が限定されています。ローカルファイルに触るには、 --allow-read--allow-write が必要になります。

開発環境

ここはまだ難があるように思います。

Deno ではモジュールシステムやパス解決が純粋な TypeScript と非互換(.ts の拡張子省略ができない) ので、 vscode 拡張などで専用の typescript server を起使う、といったソリューションが試みられています。 で、axetroy/denojustjavac/deno があるんですが、どちらも中途半端です。どちらも import-map 対応のオプションがあるように見えるんですが、動きません。ちょっと変なことをすると、すぐ動かなくなります。

deno-ja の slack で聞いた限りでは justjavac の方が公式に近い立ち位置なんですが、 axetroy/deno の fork らしいんですが、まだ axetroy/deno のがちゃんと動いてるみたいです。

(そもそも deno やってる人たちは vscode を TS の違反の警告を無視するのになれてるらしく、エディタ支援はない前提っぽいで書いてる人が多い印象)

モジュールシステム

公式には deno.land/std と、サードパーティ相当の deno.land/x があります

それとは別に、ESM で node の標準ライブラリに頼らずビルドされたコードは import できます。 npm をバックエンドにした CDN としては、以下のようなものがあります。

Next.js クローンを作ろうとしてみた

mizchi/toxen っていうリポジトリで、 next.js っぽいサーバー書いて遊んでました。(まだ実験中です)

技術スタック

  • deno
  • snowpack
  • oak
  • preact
  • htm

snowpack は一種のフロントエンド向けのバンドラーなんですが、webpack に頼らずネイティブ ESM で動くモジュールを吐いて、その際に snowpack が生成する import-map.json を deno の importmap として使う、といった方法を選んでみました。

やってみた感じ、 import { h } from "preact" という感じの、比較的 node と似たような書き味で、快適です。

ただ、事前に snowpack でビルドして、動的に pages/*.ts を読んで、 dist/*.js に吐き出して…とやっていたら、結局こんな感じの実行スクリプトに

snowpack && deno run --unstable --allow-write --allow-read --allow-net --importmap web_modules/import-map.json server.ts

権限を厳密に管理するので、多少辛いですね…

deno ならではの工夫として、next.js のクローンなので pages/*.ts のエンドポイントをターゲットに SSR する必要があるんですが、webpack や rollup のバンドラを使うのではなく Deno.bundle(Deno.cwd() + "/pages/foo.ts") みたいなコードで Deno の内部バンドラをそのまま使って、静的な JS を吐いてブラウザに食わせています。

あと、 amp + amp-script(worker-dom) で動かしているので、 amp ページでありながら動的に動く画面を作れます。 worker-dom は技術的な詳細はここでは解説しませんが、動的なコンポーネントを初期化するには SSR が必須です。

Documentation: <amp-script> - amp.dev

React ではなく preact なのは、 amp-script の 150kb 制限をクリアするためです。tsx を使っていなくて htm なのは、preact pragma を使って tsx を書くと React の型がないので、実行時例外になるのをかわすためのワークアラウンドです。

今後の TODO として、動的 URL に対応する、Deno ライブラリとして抽象的にする、export できるようにする、といった方向性があると思ってるんですが、これを本気で開発するかはまだ悩んでいて、もうちょっと Deno 自体が安定してほしい気持ちもありますね。

ただ、このブログのような SSG なら、ランタイムに deno がいないので、比較的安心して採用できる気がしました。

Universal JavaScript を考え直す

ここまでやってみて、 Deno に対応する、というのは 2 つの水準があると思いました。

  • CLI ツールなど向けに、 deno の標準ライブラリを使って、 .ts で deno べったりで書き直す
  • Universal な JavaScript として、 rollup でビルドして配布する

要は esm に対応してさえいれば読み込みはできるので、Universal な JavaScript としては、rollup でビルドしていると deno 対応している、と言えなくはないです。npm にあげてしまった後は、npm の CDN である jsdelivr を経由して読み込むといいでしょう。

deno を使っていくかどうかはともかく、 snowpack など esm 前提の実行環境なども増えてるので、この辺を意識しておくと、将来的な可用性が増えるのではないでしょうか。

History
d01650c - Fix Sun May 17 22:50:27 2020 +0900 
104726f - Fix typo Sun May 17 22:45:34 2020 +0900 
8bc249a - Update Sun May 17 22:43:59 2020 +0900