虎の穴開発室ブログ

虎の穴ラボ株式会社所属のエンジニアが書く技術ブログです

MENU

Deno 1.20 へのアップデートと変更事項まとめ

f:id:toranoana-lab:20220331183002p:plain 皆さんこんにちは。おっくんです。

去る 2022 年 3月 17日に Deno 1.20 がリリースされました。 今回も、リリースノートを参考に 変更事項の気になるところを紹介します。

Deno 1.20

Deno 1.20 での変更事項をDeno 1.20 リリースノートを元に確認します。

Rust 実装の呼び出しが改善されました

Deno は、JavaScript 実行エンジンの V8 とRustで実装された部分があり、 この2つの間での通信が改善されたとのことです。

HTTP の応答が自動的に圧縮されるようになりました

Deno のネイティブ Web サーバーが新たにレスポンスの自動圧縮をサポートするようになりました。

次のようなシンプルなWebサーバーアプリケーションを用意して、 Deno 1.19.1 と Deno 1.20.3 とそれぞれで動かしてみます。

import { serve } from "https://deno.land/std@0.130.0/http/server.ts";

function handler(req: Request): Response {
  const body = "Response Text Response Text";
  return new Response(body, {
    headers: {
      "content-type": "text/plain; charset=utf-8",
    },
  });
}

serve(handler, { port: 8080 });

こちらを動かし、レスポンスヘッダーを確認してみると、content-encoding: gzip が含まれていることがわかります。

$ curl -I --url http://localhost:8080 -H "Accept-Encoding: gzip, deflate, br"
HTTP/1.1 200 OK
content-type: text/plain; charset=utf-8
vary: Accept-Encoding
content-encoding: gzip
content-length: 36
date: Mon, 21 Mar 2022 09:00:01 GMT

リリースノートでは、"content-type" :"application/json;" で返すものを公開されており、このブログでは、"content-type": "text/plain;" を確認しました。

自動圧縮の対応については、マニュアルに記載があります。

条件として、

  • リクエスト側がAccept-Encoding をサポートすること(curl では明示する必要有り)
  • 圧縮可能なContent-Type であること(deno/ext/http/compressible.rsのリストに有ること)
  • レスポンスボディが20バイトを越えること

があります。 現在はストリームには対応しませんが、将来的にはサポートするようです。

deno bench が追加されます

新たな unstable なサブコマンド ツールとして、deno bench が追加されます。 deno testDeno.test APIがあるように、Deno.bench API もこのリリースで追加されます。

次のようにベンチマークテストの準備を行います。

// 簡易的な記述
Deno.bench("URL parsing", () => {
  new URL("https://deno.land");
});

function plus(a: number, b: number): number {
  return a + b;
}

// 詳細な設定
Deno.bench({
  name: "function plus",
  fn: () => {
    plus(1, 2);
  },
});

実行すると、次のようになります。

$ deno bench --unstable bench/bench.ts
Check file:///usr/src/app/bench/bench.ts
running 2 benches from file:///usr/src/app/bench/bench.ts
bench URL parsing ... 1000 iterations 9,916 ns/iter (3,800..119,900 ns/iter) ok (43ms)
bench function plus ... 1000 iterations 700 ns/iter (400..4,600 ns/iter) ok (10ms)

bench result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (64ms)

詳細な使用方法は、マニュアルにあります。 上で示したように、Deno.bench のオーバーロードや、実行対象のフィルタリングについて書かれています。

deno task が追加されます

新たな サブコマンド ツールとして、deno task が追加されます。 npm スクリプトや、make に似たタスクランナーでクラスプラットフォームで動作します。

使うためには、deno.json の用意が必要です。

[deno.json]

{
  "tasks": {
    "exec": "deno run --allow-net --allow-read=. --allow-write=./log task/app.ts"
  }
}

実行するには、次の通りです。

$ deno task exec
Warning deno task is unstable and may drastically change in the future
Task exec deno run --allow-net --allow-read=. --allow-write=./log task/app.ts
Check file:///usr/src/app/task/app.ts
Listen 8080

実行時には大幅な変更がある可能性があるものとして警告が出ます。 使用可能な構文は、POSIX のサブセットになっています。 cp, mv, rm, mkdir, pwd, sleep, echo, exit が使え、実行前にlog用のディレクトリを作るといったことも可能です。

[deno.json]

{
  "tasks": {
    "exec": "mkdir ./task/log && deno run --allow-net --allow-read=. --allow-write=./log task/app.ts"
  }
}

より詳細な使用方法は、マニュアルにあります。

筆者は、タスクランナーとしてmakeを使っていたのですが、こちらに移行してしまおうかと考えています。 コマンドを連結して使えはするものの、あまり複雑なことはできないので、deno-dzx なども使って別のスクリプトとして切り出すのも手段なのかなと思います。

import-map.json を構成ファイル(deno.json)で指定できるようになりました

import-map を使用する際には、deno run --import-map=import_map.json" app.ts のような指定が必要でしたが、Deno 1.20 のリリースから、次のように構成ファイルに記述することで、コマンドラインに記述する必要がなくなりました。

{
  "importMap": "import_map.json"
}

また、構成ファイルは、deno.json(または、deno.jsonc)の名前で作成しておけば、--config=[ファイル名] のオプションも都度入力する必要がありません。

TLS/HTTPS 接続情報の指定方法が変更されます

TLS接続のためのAPIとして Deno.listenTls があります。 証明書のプロパティとしてディスク上のパスのみをこれまで受け付けていましたが、このリリースから任意の文字列として読み込むことができるようになります。

// 以前の記述方法
const listener = Deno.listenTls({
  hostname: "localhost",
  port: 443,
  certFile: "./localhost.crt", // <= パスを指定
  keyFile: "./localhost.key",
});

// Deno 1.20 以降の記述方法
const listener = Deno.listenTls({
  hostname: "localhost",
  port: 443,
  cert: await Deno.readTextFile("./localhost.crt"), //<= 任意の文字列を指定
  key: await Deno.readTextFile("./localhost.key"),
});

また、これまで使用していた、 certFilekeyFile は、このリリースで非推奨になっています。

HTTP 接続をアップグレードする Deno.upgradeHttp が追加されます

Deno.upgradeHttp が unstable なAPIとして、新たに追加されます。 リリースノートでは、HTTP からWebSocket へのアップデートを例に説明があります。 Deno 1.12 で、Deno.upgradeWebSocket というAPIが追加されていて、こちらもまた、HTTPからWebSocket へアップデートするAPIです。

このAPIは低レベルのAPIで、ほとんどのユーザーは触ることが無いだろうことが、リリースノートに記載があります。 普段扱うのは Deno.upgradeWebSocket でよいと思います。 より詳細な使用例など出てきた際に、再度確認が必要そうです。

AbortSignal.timeout(ms) のサポートが追加されます

AbortSignal の使い方として、一定時間経過してのタイムアウトは一般的なユースケースです。 一般的ではあるものの、次のように setTimeout() を使用して、実装するものでした。

const controller = new AbortController();
const reason = new DOMException("The request timed out", "TimeoutError");
setTimeout(() => controller.abort(reason), 1000);

let users = [];

try {
  const response = await fetch("[任意のURL]", {
    signal: controller.signal,
  });

  users = await response.json();
} catch (e) {
  if (e instanceof DOMException && e.name === "TimeoutError") {
    console.log("TimeOut");
  } else {
    throw e;
  }
}

より単純な実装のため、WHATWG が AbortSignal.timeout(ms) を採用しました。 使用すると次のように記述できます。

const controller = new AbortController();

let users = [];

try {
  const response = await fetch("[任意のURL]", {
    signal: AbortSignal.timeout(1000),
  });

  users = (await response.json()).users;
} catch (e) {
  if (e instanceof DOMException && e.name === "TimeoutError") {
    console.log("TimeOut");
  } else {
    throw e;
  }
}

スッキリしましたね。

その他

  • Deno.connect() の返すインターフェースが、TCP と Unix向けに追加
  • FFI が提供するグローバル且つスタティックな読み取り専用のリソースをサポート
  • deno test のリソースリークのトレースを、実行時オプションでの適用に変更
  • 付属のTypeScript のバージョンが、4.6にアップデート
  • V8 のバージョンが10.0へアップデート

まとめ

今回のリリースでは、deno task が印象強いものでした。 ツールが標準で Deno が充実しているので、その一環としてとても嬉しいものでした。 欲を言えば、タスクの並列実行の機能などあると、バックエンド向けサーバーと、フロント向けのアプリケーションをまとめて起動できるので期待しています。

Deno 2.0.0 が今年の前半にはリリースの予定と公表されていましたが、現在マイルストーンを見ると20%程度の進行状況のようです。 また、1.21 のマイルストーンもあり、もうしばらく1.0 系が続きそうです。 NPMに変わるパッケージ管理ソリューションについて 2021 年の Deno の活動について総括記事では、触れられていましたが、現在のところそういった内容はマイルストーンには無いようです。

次回の更新も追いかけていきます。

P.S.

採用情報

■募集職種
yumenosora.co.jp