denoはnodejsに代わる次世代javascript/typescriptランタイムです。
つい最近v1.0.0がリリースされたので触ってみたのですが、めちゃくちゃいい感じだったので感想をまとめます。
denoってそもそも何?というのは
https://qiita.com/so99ynoodles/items/c3ba2a528052827e3b3c
などがわかりやすいです。
(なお、サラッと触ってみただけなので間違いがある可能性があります。)
インストール
mac使いなので
brew install deno
で入りました。
直接installする場合は
curl -fsSL https://deno.land/x/install/install.sh | sh
で良さそうです。
チュートリアル
https://deno.land/manual/getting_started/first_steps
公式ドキュメントが死ぬほど読みやすい・・・
HelloWorld
最初のスクリプトは以下のURLに置いてありました。
当然のように拡張子は.tsです。
$ curl https://deno.land/std/examples/welcome.ts
console.log("Welcome to Deno 🦕");
実行してみます
$ deno run https://deno.land/std/examples/welcome.ts
Welcome to Deno 🦕
web上のtypescriptがそのまま実行されている・・・すごい!
httpリクエスト
denoはnodejsよりブラウザ互換なAPIを提供しているようです。
fetch()
が使えます。
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
const url_ = Deno.args[0];
const res = await fetch(url_);
// TODO(ry) Re-enable streaming in this example.
// Originally we did: await Deno.copy(res.body, Deno.stdout);
// But maybe more JS-y would be: res.pipeTo(Deno.stdout);
const body = new Uint8Array(await res.arrayBuffer());
await Deno.stdout.write(body);
地味にトップレベルでawaitが使われていて感動。
これはさっきと同じコマンドでは実行できません。denoは明示的に権限を与えないとネットワークアクセスができないからです。
エラーメッセージも明瞭ですね。 --allow-net
を付けて再実行します
ちなみに初回実行時は Download https://deno.land/std/examples/curl.ts
などが標準エラー出力に出てくるようです。
2回目以降の実行ではキャッシュされているので出てきません。
また --allow-net
オプションはドメインを指定しないと任意のドメインを許可するようです。
ファイル読み込み
for (let i = 0; i < Deno.args.length; i++) {
let filename = Deno.args[i];
let file = await Deno.open(filename);
await Deno.copy(file, Deno.stdout);
file.close();
}
(大事な部分はカット)
IOも明示的な許可が必要です。 --allow-read
でディレクトリ単位に制限した読み込み許可を与えます。
TCPサーバ
const listener = Deno.listen({ port: 8080 });
console.log("listening on 0.0.0.0:8080");
for await (const conn of listener) {
Deno.copy(conn, conn);
}
for awaitは非同期反復子をイテレートするjavascriptの構文ですね。(普段あまり使う機会ないので急に出てきてビックリした)
deno run --allow-net https://deno.land/std/examples/echo_server.ts
ネットワークへのフルアクセスを付けて実行できます。
CLI
deno
コマンドは リリース を見るとシングルバイナリ(!)のCLIとして提供されています。
deno run
以外のサブコマンドをいくつか触ってみます
repl
deno repl
でREPLが起動します。サブコマンド無指定の deno
でも同じです。
repl内では import
はできないっぽい?
bundle
deno bundle
はimportを辿って依存スクリプトを全てシングルファイルにバンドルしてくれます。
lodashはpureなjavascriptだからdenoで実行できると聞いたので、これを使って試してみました
import isString from "https://raw.githubusercontent.com/lodash/lodash/master/isString.js";
console.log(isString("abc")); // true
$ deno run hello.ts # denoでは実行可能
true
$ node run hello.ts # 当然nodeでは実行できない(importできないから)
internal/modules/cjs/loader.js:1023
throw err;
^
Error: Cannot find module '/Users/moajo/deno/run'
...(略)
$ deno bundle hello.ts > bundle.js # bundle.jsにバンドル結果を吐く
Bundling "file:///Users/moajo/deno/hello.ts"
$ node bundle.js # nodeでも実行可能に!
true
install
denoで書いたスクリプトを呼び出すshell scriptを~/.deno/bin以下に置いてくれるコマンドです
せっかくなので依存があっても大丈夫かも検証します(例によってlodash)
// 引数は10より小さいときにtrue,そうじゃないときにfalseを返すコマンド
import lt from "https://raw.githubusercontent.com/lodash/lodash/master/lt.js";
console.log(lt(parseInt(Deno.args[0]), 10));
特に役に立たないコマンドですがinstallしてみます。
$ deno install lt10 lt10.ts
Compile file:///Users/moajo/deno/lt10.ts
Download https://raw.githubusercontent.com/lodash/lodash/master/lt.js
✅ Successfully installed lt10
/Users/moajo/.deno/bin/lt10
$ lt10 9
true
$ lt10 10
false
ちなみにdeno install
したときにPATHが通ってないとちゃんと指摘してくれます。優しい。
ℹ️ Add /Users/moajo/.deno/bin to PATH
export PATH="/Users/moajo/.deno/bin:$PATH"
実行可能ファイルの中身はこんな感じでした
$ cat `which lt10`
#!/bin/sh
# generated by deno install
deno "run" "file:///Users/moajo/deno/lt10.ts" "$@"
シンプルですね
typescriptサポート
denoは標準でtypescriptをサポートしているので、特に理由がなければ基本的にtypescriptを使ったほうが良さそうです。
一方で、型定義のないjavascriptコードを参照するためのサポートもちゃんと用意されています
compiler-hintをコメントで付けることで型定義を読み込んでくれます。型定義も当然URLで指定できるようです。
// @deno-types="./foo.d.ts"
import * as foo from "./foo.js";
tsconfigはデフォルトでstrictなオプションが指定されるようですが、-c
オプションで指定することもできます。
deno run -c tsconfig.json mod.ts
個人的にはX-TypeScript-Typesカスタムヘッダーで型定義を指定できる機能がめちゃくちゃかっこよくて好きです。そのうちこれに対応したホスティングサービスも出てくるんでしょうか?
最後に
さらっと触ってみただけですが、UXが最高すぎて完全に惚れました。流行ってくれ!
ドキュメンテーションもわかりやすいですし、機能的にもめちゃくちゃ使いやすいです。
仕様上npmパッケージとの互換性がないのが唯一にして最大のつらみポイントですが、今後の発展に期待です。
リンク
日本のユーザコミュニティのscrapbox?
slackもある
参考