2020年5月13日、ついにver1.0がリリースされたDeno。
Node.jsとの違いをざっくりと解説します。
※以下、本記事の内容はDeno公式マニュアルの記述に基づきます
#そもそもDenoって何なの?
DenoはJavaScriptおよびTypeScriptの実行環境です。
V8, Rust, およびTokioによって作られています。
#え、Node.jsがあるじゃん?
Node.jsは2009年に誕生し、すでに10年を超える歴史を有しています。
たとえばNode.jsが生まれたとき、この世にPromiseはありませんでした。
2012年にはTypeScriptが生まれました。
この10年で、JavaScriptを取り巻く環境は大きく変わってしまったのです。
そして2020年。
Node.jsの問題を解決し、よりよい開発環境を提供するため、Node.jsの開発者であるライアン・ダールらの手によって生まれたのがDenoなのです(DenoはNodeのアナグラム)。
#DenoはNode.jsとどこが違うのか
##npmを使いません
モジュールは任意のURLまたはファイルパスからダウンロードされます。
import {hoge} from "fuga";
というNode.jsでの記述形式は、指定されたモジュールがどこにあるのか特定できないという問題を引き起こしていました。
fuga
モジュールはNPMサーバにあるのかもしれないし、ローカルのnode_modules
フォルダにあるのかもしれません。
import {hoge} from "https://your.domain.com/fuga.ts";
とすることで、fuga
ライブラリの場所は一意に定まります。
またこれは同時に、package.json
に相当するしかけを必要としないことをも意味します。
URLやファイルパスがそのままバージョンの指定にもなっていれば、わざわざ別ファイルでその依存性情報まで管理する必要はないからです。
##TypeScriptを標準でサポートします
追加のライブラリをインストールすることなく、TypeScriptをコンパイルしてくれます。
コンパイルは自動的に行われるので、コマンドを叩く必要もありません。
##セキュアです
明示的に許可されない限り、denoはネットワーク接続もファイル読み取りもできません。
例として、標準ライブラリとして公開されているcurl.ts
でURLへのアクセスを試してみるとエラーが返ります。
$> deno run https://deno.land/std/examples/curl.ts https://example.com
error: Uncaught PermissionDenied: network access to "https://example.com/", run again with the --allow-net flag
接続許可するドメインを--allow-net
フラグに設定することで初めて、URLへのアクセスが可能になります。
deno run --allow-net=example.com https://deno.land/std/examples/curl.ts https://example.com
よくわからないNPMパッケージを走らせたら、変なURLに接続されたりファイルシステムを触られたりするのではないか……という恐怖ともこれでおさらばです。
詳細: https://deno.land/manual/getting_started/permissions
##標準テストランナーがあります
Deno.test
を使えば、ライブラリをインストールすることなくテストを実行できます。
Deno.test("Hello deno test", () => {
const foo: string = "Hello";
if (foo !== "Hello") {
throw ("foo should be Hello.");
}
});
アサーションライブラリも用意されています。
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
Deno.test("Hello assertion", () => {
const foo: string = "Hello";
assertEquals(foo, "Hello");
});
実行するときは deno test [files]
コマンドを叩くだけ。かんたん!
詳細: https://deno.land/manual/testing
非同期のアクションはすべてPromiseを返します
Webサーバを記述する場合、Node.jsではこんな感じでしたが
var http = require('http');
http.createServer(function (req, res) {
res.write('Hello World!');
res.end();
}).listen(8080);
出典: https://www.w3schools.com/nodejs/nodejs_http.asp
Denoではawait
を使ってこんな感じになります。
import { serve } from "https://deno.land/std/http/server.ts";
const s = serve({ port: 8080 });
for await (const req of s) {
req.respond({ body: "Hello World!\n" });
}
出典: https://deno.land/std/http
予期せぬエラーが発生した場合は"常に"処理を終了します
Uncaught Exceptions in Nodeなどの記事に見られるように、Node.jsでは捕捉できないエラーをどう扱うかは開発者に任せられていました。
処理を終了させてもいいし、もみ消して続行させることもできました。
Denoでは常に処理が終了します。常にです。
#おまけ
Node.jsが抱える問題点、およびDenoが目指すゴールについては、ライアン・ダール自らによる以下のプレゼンテーションを見るとわかりやすいです。
Node.jsに関する10の反省点 Ryan Dahl - JSConf EU 2018