Deno v1.22がリリースされました。
この記事では、主な変更点についてまとめていきます。
リモートモジュールの型チェックがデフォルトで無効化
deno runやdeno testなどの各コマンドでリモートモジュールの型チェックがデフォルトで無効化されました。
今後はローカルのTypeScriptファイルのみが型チェックされます。
もしリモートモジュールの型チェックも必要な際は--check=allオプションまたはdeno check --remoteを使用します。
また、次のv1.23のリリースでは、deno runやdeno cacheではデフォルトで一切型チェックが行われなくなる予定です。 (deno checkコマンドや--checkオプションなどで明示的に型チェックする必要があります)
例えば、CIでdeno cacheコマンドを実行して型チェックを行っている場合などは、今のうちにdeno checkコマンドに移行しておくとよいと思います。
# mod.tsの型チェックを行う
$ deno check mod.ts
# deno run実行時に型チェックも行う
$ deno run --check main.ts
設定ファイルの読み込みの無効化
Denoはエントリポイントが存在するディレクトリまたはその上位のいずれかのディレクトリにdeno.json(c)というファイルが存在する場合、それを自動で読み込みます。
このリリースでは、新しく--no-configオプションがサポートされました。
このオプションを指定すると、deno.json(c)の自動探索を無効化できます。
$ deno run --no-config main.ts
(破壊的変更) Worker内でデフォルトでDeno APIが有効化
今までは、Worker内でDeno.readFileなどのAPIを使用したい場合は、denoオプションによって明示的に有効化する必要がありました。
new Worker(new URL('./worker.js', import.meta.url).href, {
  deno: { namespace: true }, // Deno APIの使用を有効化
  type: "module"
});
今後は上記のようにオプションを指定しなくても、Worker内で常にDenoのAPIを参照できます。
new Worker(new URL('./worker.js', import.meta.url).href, { type: "module" });
また、この変更の影響により、WorkerOptions.denoやWorkerOptions.deno.namespaceが型定義から削除されています。
(破壊的変更) Deno.emit()の削除
Deno.emit()という、プログラムからTypeScriptコードをバンドルまたはトランスパイルすることができるAPIがありました。
このリリースでは、このDeno.emit()が削除されています。
代わりにdenoland/deno_emitという同様の役割をこなすモジュールが公開されています。
import { bundle } from "https://deno.land/x/emit@0.0.2/mod.ts";
const { code } = await bundle("https://deno.land/std@0.140.0/examples/chat/server.ts");
await Deno.writeTextFile("bundle.js", code);
合わせて、Deno.applySourceMap()やDeno.formatDiagnostics()も同様に削除されています。
サブプロセスAPIのアップデート
Deno v1.21でDeno.spawnChild()やDeno.spawn()などの新しいサブプロセスAPIが追加されました。
これらのAPIでAbortSignalがサポートされました。
AbortControllerによって中断が指示されると、起動された子プロセスへSIGTERMが送信されます。
const controller = new AbortController();
const child = Deno.spawnChild(Deno.execPath(), {
  args: [
    "eval",
    "setTimeout(() => console.log('foobar'), 10000)",
  ],
  signal: controller.signal,
});
queueMicrotask(() => controller.abort());
const status = await child.status;
console.assert(!status.success);
また、ChildStatusオブジェクトのsignalプロパティが数値から文字列に変更されています (Child#kill()の引数が文字列にも関わらず、signalプロパティが数値になっており、一貫性が取れていなかったため)
const child = Deno.spawnChild(Deno.execPath(), { args });
// ...
const status = await child.status;
status.signal; // => "SIGTERM" (v1.21までは数値が設定されていました)
ちなみに、これらのサブプロセスAPIはv1.23にて安定化予定とのことです。
Deno.resolveDns()の改善
Deno.resolveDns()で下記レコードの問い合わせがサポートされています。
- NS
- CAA
- SOA
- NAPTR
deno lspでリントがデフォルトで有効化
特に設定を行わなくとも、今後はリントがデフォルトで実行されます。
もしこの挙動を無効化したい場合は、vscode-denoの場合は.vscode/settings.jsonでdeno.lintオプションにfalseを設定することで無効化可能です。
deno testでテストレポートの出力が改善
例えば、次のようなテストファイルがあったとします。
Deno.test("output", () => {
  console.log(123);
  console.log("foobar");
});
Deno.test("dangling promise", async () => {
  const promise = Promise.reject(new Error("error"));
});
Deno.test("uncaught error", () => {
  throw new Error("hey");
});
v1.22では次のように出力が行われます。
running 3 tests from ./test.js
output ...
------- output -------
123
foobar
----- output end -----
output ... ok (6ms)
dangling promise ...
Uncaught error from ./test.js FAILED
 ERRORS
./test.js (uncaught error)
error: (in promise) Error: error
  const promise = Promise.reject(new Error("error"));
                                 ^
    at file:///home/uki00a/ghq/github.com/uki00a/deno-sample/test.js:7:34
This error was not caught from a test and caused the test runner to
 fail on the referenced module.
It most likely originated from a dangling promise, event/timeout ha
ndler or top-level code.
 FAILURES
./test.js (uncaught error)
それに対し、v1.21では次のように出力されます。
running 3 tests from ./test.js
output ...
------- output -------
123
foobar
----- output end -----
ok (10ms)
dangling promise ...
test result: FAILED. 1 passed; 0 failed; 0 ignored; 0 measured; 0 f
iltered out (74ms)
error: Uncaught (in promise) Error: error
  const promise = Promise.reject(new Error("error"));
                                 ^
    at file:///home/uki00a/ghq/github.com/uki00a/deno-sample/test.js:7:34
    at testStepSanitizer (deno:runtime/js/40_testing.js:449:13)
    at asyncOpSanitizer (deno:runtime/js/40_testing.js:149:15)
    at resourceSanitizer (deno:runtime/js/40_testing.js:375:13)
    at Object.exitSanitizer [as fn] (deno:runtime/js/40_testing.js:
432:15)
    at runTest (deno:runtime/js/40_testing.js:799:18)
    at Object.runTests (deno:runtime/js/40_testing.js:1105:28)
このように、テストが失敗した箇所やUncaught errorの表示などが改善されています。
Response.json()がサポート
Response.jsonのサポートが追加されました。
このAPIを使うことで、application/json形式のレスポンスを簡易的に作れます。
const res = Response.json({ name: "foo" });
res.status; // => 200
res.headers.get("content-type"); // => "application/json"
await res.json(); // => { name: "foo" }
また、第2引数でヘッダなどをカスタマイズできます。
Response.json({ id: 1 }, { headers: { "x-foo": "foo" } });
このAPIは主に、Deno Deployなどのサーバサイドランタイムでの利用が想定されているようです。
performance APIの改善
performance.timeOriginが追加されました。
このプロパティにはDenoのランタイムやWorkerが起動された時刻が設定されます。
また、performance.toJSONも実装されています。
navigator.userAgentの追加
navigator.userAgentが実装されています。
このプロパティには、fetch()などで設定されるものと同様のユーザーエージェントが設定されます。
navigator.userAgent; // => "Deno/1.22.0"
その他の修正
- HTTPサーバ(Deno.seveHTTP)がAccept-Encoding: deflate, gzipのリクエストを受信された際に、レスポンスが圧縮されない問題が修正されました。
- HTTPサーバ(Deno.serveHTTP)でReadableStreamの圧縮がサポートされました。
- TextEncoderで大きな文字列をエンコードする際のパフォーマンスが向上しました。