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

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

実験的なパッケージマネージャが実装 (jsr:URL)

⚠️この機能は実験的機能のようなので、今後、大きな変更が入る可能性があります。

⚠️また、パッケージレジストリがまだ公開されていないため、この機能はまだ利用できない状態のようです。

Deno本体に実験的なパッケージマネージャーが実装されています。

具体的には、以下のようにjsr:形式のURLを記述することで、Denoがパッケージレジストリと連携してsemverの解決などを行いつつ、パッケージのインストールなどを自動で行ってくれるようです。

import { foo } from "jsr:@foo/some_pkg@1/mod.ts";

例えば、この場合、@foo/some_pkgパッケージに関するsemverの解決を行うために、まずhttps://${DENO_REGISTRY_URL}/@foo/some_pkg/meta.jsonの問い合わせを行い、その内容を元にどのバージョンをインストールすべきか判断されるようです。

従来のhttps:npm:形式のパッケージと同様に、npm installなどのコマンドの実行は不要で、スクリプトの実行時にDenoが必要に応じてパッケージをインストールしてくれます。

また、パッケージのインストール元レジストリはDENO_REGISTRY_URL環境変数で変更可能なようです。

ここからは推測になりますが、この機能は、元々、導入される予定であったdeno:URLに相当する機能だと思われます。

Deno本体がレジストリと連携してsemver解決を行うことで、依存関係の重複問題などを解消しようというのがこの機能の狙いだと思われます。


deno jupyter

Deno本体にJupyter Kernelが実装されました。

以下のコマンドを実行すると、Deno Kernelがインストールされているかどうかを確認できます。

$ deno jupyter --unstable
ℹ️ Deno kernel is not yet installed, run `deno jupyter --unstable --install` to set it up

もしインストールされていなければ、以下のコマンドでインストールできます。

$ deno jupyter --unstable --install
[InstallKernelSpec] Installed kernelspec deno in /path/to/jupyter/kernels/deno
✅ Deno kernelspec installed successfully.

インストールが完了すると、Deno Kernelを利用できます。

$ jupyter console --kernel deno

また、MIMEタイプがキーに設定されたオブジェクトを返す関数をSymbol.for("Jupyter.display")プロパティに設定することで、出力内容をカスタマイズできます。

In [1]: { [Symbol.for("Jupyter.display")]: () => ({ "text/plain": "Hello Deno!", "text/html": "<b>Hello Deno!</b>" }) }
Out[1]: Hello Deno!

deno test

TAPレポーター

deno testコマンドにTAPレポーターが実装されました。--reporter=tapオプションを指定することで有効化できます。

$ deno test --allow-read --reporter=tap | deno run --allow-read npm:tap-nyan@1.1.0 
 10  -_-_-_-_-__,------,
 0   -_-_-_-_-__|  /\_/\ 
 0   -_-_-_-_-_~|_( ^ .^) 
     -_-_-_-_-_ ""  "" 
  Pass!

Deno.test.only()/Deno.test.ignore()

Deno.test.only()Deno.test.ignore()が実装されました。

それぞれ、Deno.test()only: trueまたはignore: trueを指定した際と同様の振る舞いをします。

Deno.test.only("add", () => {
  assertEquals(add(1, 2), 3);
});
// これは以下と同様です
Deno.test({
  name: "add",
  fn: () => {
    assertEquals(add(1, 2), 3);
  },
  only: true,
});


Deno.test.ignore("sub", () => {
  assertEquals(sub(5, 2), 3);
});
// これは以下と同様です
Deno.test({
  name: "sub",
  fn: () => {
    assertEquals(sub(5, 3), 3);
  },
  ignore: true,
});

フィルタリングに関する挙動の改善

--filterによる絞り込みによって実行がスキップされたテストファイルがログに出力されないように挙動が改善されています。

v1.37.0:

$ deno test -A --filter="$fresh-testing-library/components" 
running 1 test from ./components.test.tsx
$fresh-testing-library/components ...
  provides a thin wrapper to `@testing-library/preact` ... ok (52ms)
$fresh-testing-library/components ... ok (100ms)

ok | 1 passed (1 step) | 0 failed | 9 filtered out (1s)-

v1.36.4:

$ deno test -A --filter="$fresh-testing-library/components"
running 0 tests from ./async-route-components.test.tsx
running 1 test from ./components.test.tsx
$fresh-testing-library/components ...
  provides a thin wrapper to `@testing-library/preact` ... ok (57ms)
$fresh-testing-library/components ... ok (108ms)
running 0 tests from ./doc.test.ts
running 0 tests from ./internal/fresh/mod.test.ts
running 0 tests from ./permissions.test.ts
running 0 tests from ./server.test.ts

ok | 1 passed (1 step) | 0 failed | 9 filtered out (1s)

また、--filteronly: trueを併用した際の挙動が変更されています。

通常、only: trueが指定されたテストケースが実行された場合、Denoはテスト全体を強制的に失敗として扱います。

Deno v1.37ではこの挙動が一部変更され、--filterオプションによるフィルタリングの結果、only: trueが指定されたテストケースの実行がスキップされた場合は、通常通りテストの実行を成功として扱います。

例えば、以下のようなテストコードがあったとします。

Deno.test({
  name: "add",
  fn: () => {
    assertEquals(add(1, 2), 3);
  },
  only: true,
});

Deno.test("sub", () => {
  assertEquals(sub(5, 1), 4);
});

このテストを以下のコマンドで実行すると、v1.37では成功しますが、v1.36.4ではエラーが発生します。(error: Test failed because the "only" option was used)

$ deno test --filter=sub test.ts
running 1 test from ./test.ts
sub ... ok (0ms)

ok | 1 passed | 0 failed | 1 filtered out (33ms)

そのため、意図せずしてonly: trueが設定されたテストケースがコミットされないよう、注意が必要かもしれません。

サニタイザーのパフォーマンス改善

サニタイザーとは、deno testコマンドがリソースリークなどを検出するための仕組みです。

このサニタイザーの実装を最適化することで、deno testコマンドのパフォーマンスがかなり改善されたようです。(場合によっては、以前までの10倍程度まで高速化が見込まれるようです)

また、サニタイザーが出力する情報量の増加や信頼性の向上なども行われています。

--coverageの改善

deno test --coverageによるカバレッジ計測時に、Denoの内部モジュールに関する網羅率も計測されてしまう問題が修正されています。

deno lsp

入力補完に関する改善

npmパッケージの補完がサポートされました。import宣言でnpm:を記述する際に、パッケージ名やバージョンなどが提案されます。

また、自動インポートに関する保管候補にファイル名(パス)が表示されるように挙動が改善されています。

deno.jsonの検出時にvscode-denoを自動で有効化

今まで、vscode-denoを有効化するためには、.vscode/settings.json"deno.enable": trueを指定する必要がありました。

Deno v1.37では、deno.json(c)が存在すれば、自動でvscode-denoが有効化されるように挙動が変更されています。

この挙動を無効化したい場合は、"deno.enable": falseを明示する必要があります。

disablePathsオプション

disablePathsオプションが追加されました。

プロジェクト内の特定のディレクトリに対してのみdeno lspを無効化したいようなケースで活用できます。

{
  // vscode-denoでの設定例
  "deno.disablePaths": ["./frontend"]
}

その他の改善

  • ファイルをリネームした際に、関連するファイルのimportの自動的なアップデートがサポートされました。
  • 自動importなどの実行時に、deno.json(c)fmt.singleQuoteなどのフォーマットに関する設定が適用されない問題が修正されています。
  • vscodeのテストエクスプローラーにテストケースを表示する際に、deno.jsonexclude/test.exclude/test.includeの設定が適用されるようになりました。

deno lint

deno lint --rulesで全てのルールが表示されるように挙動が変更されました。(v1.36.4まではrecommendedタグのルールのみが表示されていました)

また、各ルールのタグも表示されるように出力が改善されています。

v1.37.0:

$ deno lint --rules | grep fresh
 - fresh-handler-export [fresh]
   help: https://lint.deno.land/#fresh-handler-export
 - fresh-server-event-handlers [fresh]
   help: https://lint.deno.land/#fresh-server-event-handlers

v1.36.4:

$ deno lint --rules | grep fresh
$ echo $?
1

$ deno lint --rules | grep prefer-as-const
 - prefer-as-const
   help: https://lint.deno.land/#prefer-as-const

Node.js互換性

このリリースでも、様々な改善が実施されています。

具体的には、v1.37で以下のパッケージの動作がテストされているようです。

主な変更点:

  • node:http2: http2.connect()ClientHttp2Sessionが実装されました。
    • ストリーミングやTrailerなどのヘッダーのハンドリングなど、基本的な操作は機能するようです。
    • ただし、ref()/unref()などは未実装のようです。
  • node:crypto: createCipheriv()createDecipheriv()aes-128-gcm及びaes-256-gcmがサポートされました。
  • node:child_process: envオプションにundefinedが設定されたキーがあると、プロセスがクラッシュする問題が修正されています。
  • node:net: wsなどのパッケージをより効率に扱えるよう、ソケットからの読み込みが最適化されています

ロックファイル v3

ロックファイルの新しいフォーマット(v3)が導入されています。

おそらく、jsr:URLの導入などに向けた対応と推測されます。

また、再現性の向上のため、HTTPリダイレクトが発生した場合、リダイレクト元とリダイレクト先のURLの組み合わせがロックファイルで管理されるようになりました。

TypeScript v5.2

Deno本体のTypeScriptがv5.2へアップデートされています。

TypeScriptファイル限定ではあるものの、await usingusingがサポートされています。

class Disposable {
  [Symbol.dispose]() {
    console.info("Disposable: disposed!");
  }
}

{
  using disposable = new Disposable();
}
// => Disposable: disposed!

ただし、以下の機能については、まだ動作しないようです。(v8でのサポート待ちの状況のようです)

  • JavaScriptファイルにおけるusing/await using
  • Decorator Metadata

CLI

Import Attributesが実装

Import Attributesが実装されました。

import config from "./deno.json" with { type: "json" };

console.info(config);

前身であるImport Assertionsについては、今後、サポートが廃止される予定のようです。

--allow-runの挙動が改善

--allow-run=<プログラム名>のように、許可をしたいプログラム名を非絶対パス形式で指定した際の挙動が変更されています。

例えば、--allow-run=denoのように指定して かつ deno/usr/local/bin/denoに存在した場合、v1.36とv1.37ではそれぞれ以下のような振る舞いをします。

バージョンコード挙動
v1.36new Deno.Command("/usr/local/bin/deno")PermissoinError
v1.37new Deno.Command("/usr/local/bin/deno")問題なく動きます

Deno.Server#shutdown

Deno.Server#shutdownが実装されました。(利用する際は、--unstableの指定が必要です。)

従来までのsignalオプションを使用した方法と異なり、このAPIを使用することでサーバーをgracefulに停止できます。

このAPIを呼んだ後は、サーバは一切のコネクションを受け付けず、実行途中のリクエストは処理の完了まで待機されます。

参考