Deno v1.30がリリースされました。

この記事では主な変更点などについて解説します。

Node.js互換性の改善

2023年 Q1のロードマップで発表されていたNode.js組み込みパッケージの利用が正式にサポートされました。

以下のように、node:<パッケージ名>の形式でimportを記述すると、Node.js組み込みパッケージをDenoから利用することができます。

import { EventEmitter } from "node:events";

const emitter = new EventEmitter();
emitter.on("foo", console.log);
emitter.emit("foo", "bar");

また、Node-APIの互換性の改善も引き続き実施されており、以下のAPIなどの互換性が向上されています。

deno.jsonでのImport Mapsの定義がサポート

こちらも2023年 Q1のロードマップで発表されていた機能になります。

deno.jsonimportsscopesなどが定義されていると、--import-map使用時と同様に、deno.jsonの定義内容を元にDenoがbare specifierが解釈してくれます。

例えば、以下のような内容のdeno.jsonが存在したとします。

{
  "imports": {
    "dax": "https://deno.land/x/dax@0.24.0/mod.ts"
  }
}

この場合、ソースコードでは以下のようにしてdaxモジュールを利用することができます。

import { $ } from "dax";

await $`echo foobar`;

deno fmtでセミコロンの有無を制御できるように

今まで、Denoに搭載されたフォーマッタであるdeno fmtコマンドでは、ソースコードにおける行末のセミコロンの有無をカスタマイズすることができませんでした。

今回のリリースでは、deno.jsonfmt.options.semiColonsオプションがサポートされました。 このオプションにfalseを設定すると、deno fmtの実行時に行末のセミコロンが取り除かれます。

{
  "fmt": {
    "options": {
      "semiColons": false
    }
  }
}

また、--options-no-semicolonsオプションにより、CLI経由でセミコロンの有無を制御することも可能です。

このオプションを指定した場合も、フォーマット時に行末のセミコロンが取り除かれます。

$ deno fmt --options-no-semicolons main.ts

Deno.permissionsに同期バージョンのAPIが追加

DenoはDeno.permissions名前空間でquery()request()などのパーミッションを動的に制御するためのAPIを提供しています。

これらのAPIはすべて非同期に動作し、戻り値としてPromiseを返却します。

このリリースでは、パーミッションを同期的に制御したいケースに対応するため、Deno.permissions名前空間に以下の3つのメソッドが新しく追加されました。

  • querySync()
  • requestSync()
  • revokeSync()

挙動としては、各メソッドの非同期バージョン(名前にSyncがつかないメソッド)と同様ですが、戻り値としてPromiseではなく直接結果が返却されます。

const status = Deno.permissions.querySync({ name: "env", variable: "DENO_DIR" });
if (status.state === "granted") {
  const denoDir = Deno.env.get("DENO_DIR");
  console.info(denoDir);
}

Deno.env.hasの追加

新しいAPIとしてDeno.env.hasが実装されました。

引数で指定した環境変数が定義されていれば、trueが返却されます

console.log(Deno.env.has("DENO_DIR"));

このAPIの利用には--allow-envの指定が必要です。

Deno.testのサブステップAPIでテスト関数を直接渡せるように

Deno.testでは以下のように関数を直接渡してテストケースを定義することができます。

Deno.test(function sumReturnsSumOfNumbers() {
  assertEquals(sum(1, 2, 3), 6);
});

しかし、サブステップAPI(Deno.TestContext#step)にはこのようにして関数を渡すことができませんでした。

このリリースでは、サブステップAPIでも関数を直接渡すことができるように改善されています。

以下のように、step()の引数として直接テスト関数を渡すことができます。

Deno.test("sum", async (t) => {
  await t.step(function shouldReturnSumOfNumbers() {
    assertEquals(sum(1, 2, 5), 8);
  });
});

Deno.Command#spawnstdinオプションのデフォルト値が"inherit"に変更

Deno.Commandの生成時にstdinオプションが未指定の状態でspawnを実行した際は、 stdinオプションに"inherit"が指定された場合と同様の振る舞いをするように挙動が変更されています。

もし今までのバージョンと同じ振る舞いが必要な際は、stdinオプションに"null"を明示する必要があります。

const command = new Deno.Command(cmd, {
  args,
  stdin: "null",
});

Deno.writeFile()Deno.writeTextFile()ReadableStreamがサポート

Denoからファイルへ書き込みを行うためのAPIであるDeno.writeFile()Deno.writeTextFile()ReadableStreamを渡せるようになりました。

const stream = new ReadableStream({
  pull(controller) {
    controller.enqueue("foo\n");
    controller.enqueue("bar");
    controller.close();
  },
});
await Deno.writeTextFile("test.txt", stream);

console.info(await Deno.readTextFile("test.txt"));
// Output: foo
//         bar

Deno.FsFile#seekoffset引数でbigintがサポート

以下のように、Deno.FsFileseek()メソッドにbigintを渡せるようになりました。

const file = await Deno.open(filename);
try {
  await file.seek(3n, Deno.SeekMode.Start);
  const buf = new Uint8Array(100);
  await file.read(buf);
  console.info(new TextDecoder().decode(buf));
} finally {
  file.close();
}

Deno.Listenerref()unref()メソッドが安定化

Deno.listenrref()/unref()が安定化され、--unstableオプションなしで利用できるようになりました。

Deno.ListenerDeno.listen()などのAPIから返却されるオブジェクトです。

デフォルトでは、生存中のDeno.Listenerが存在する場合、Denoのプロセスの終了はブロックされます。

Deno.Listenerunref()メソッドを呼ぶと、該当のリスナがプロセスの終了をブロックしなくなります。

ref()メソッドはその逆で、unref()されたDeno.Listenerをデフォルトの状態へ戻します。(プロセスの終了がブロックされるようになります)

DENO_V8_FLAGS環境変数のサポート

今まで、Denoの内部で実行されるv8の挙動をカスタマイズしたい場合は、Denoの実行時に--v8-flagsオプションを指定する必要がありました。

このリリースでは、DENO_V8_FLAGS環境変数がサポートされています。

今後は、この環境変数経由でもv8の挙動をカスタマイズできます。

deno upgradeの改善

deno upgradeの実行後に、アップデート後のバージョンのリリースノートへのリンクが表示されるようになりました。

参考