皆さんこんにちは。おっくんです。
去る 2023 年 8 月 3 日に Deno 1.36 がリリースされました。 今回も、リリースノートを参考に 変更事項の気になるところを紹介します。
Deno 1.36
Deno 1.36 での変更事項をDeno 1.36 リリースノートを元に確認します。
柔軟なセキュリティオプションの追加
Deno は、デフォルトでオプトイン形式のセキュリティを提供しています。
--allow-net
など、--allow-*
によって、リソースアクセスを許可します。
Deno 1.36 から、--deny-*
を提供するようになります。
リリースノートには次のような使用例が示されています。
# ネットワークのリソースを許可するが、`api.evil.com` を除外する $ deno run --allow-net --deny-net=api.evil.com mod.ts # ファイルの書き込みと読み取りを許可するが、/etc 以下は双方とも除外する $ deno run --allow-read --deny-read=/etc --allow-write --deny-write=/etc mod.ts # 許可対象が除外された場合は、除外する方が優先される。 $ deno run --allow-read=foo.txt --deny-read=foo.txt mod.ts
今後もパーミッションシステムの拡充に努める事が記載されており、その一環として「構成ファイルdeno.json(c)にアクセス許可を定義する」issue が議論されています。
--allow-*
で複数の定義を与えることはできましたが、ケース次第では記述が多くなるケースが存在していたと思います。
--deny-*
の登場により、そういった方はかなり楽ができるのではないでしょうか。
テストとベンチマーク
JUnit レポーター形式のサポート
テストのレポーターとして、JUnit XML 形式の出力ができるようになります。 JUnit XML 形式をサポートすることで、数多くのサービスに、ネイティブ対応できるようになります。
実際に動かすと次のようになります。
# これまでの動作 $ deno test running 1 test from ./main_test.ts addTest ... ok (7ms) ok | 1 passed | 0 failed (44ms) # JUnit 形式を指定 $ deno test --reporter=junit <?xml version="1.0" encoding="UTF-8"?> <testsuites name="deno test" tests="1" failures="0" errors="0" time="0.046"> <testsuite name="hoge/main_test.ts" tests="1" disabled="0" errors="0" failures="0"> <testcase name="addTest" time="0.008" filename="/hoge/main_test.ts" line="4" col="6"> </testcase> </testsuite> </testsuites> # JUnit 形式でファイルへ書き出し $ deno test --junit-path=test_report.xml running 1 test from ./main_test.ts addTest ... ok (7ms) ok | 1 passed | 0 failed (45ms) $ cat .\test_report.xml <?xml version="1.0" encoding="UTF-8"?> <testsuites name="deno test" tests="1" failures="0" errors="0" time="0.045"> <testsuite name='hoge/main_test.ts" tests="1" disabled="0" errors="0" failures="0"> <testcase name="addTest" time="0.007" filename="/hoge/main_test.ts" line="4" col="6"> </testcase> </testsuite> </testsuites>
dot レポーターの追加
テストの進行状況を dot 形式で出力するレポーター―が追加されました。
動作させると次のようになります。
$ deno test --reporter=dot ...............................................!........ ok | 56 passed | 0 failed (339ms) # 以下、パス出来なかったテストの詳細
node:test ポリフィルの追加
Node 18 で導入され、Node 20 で stable になったテストランナー のポリフィルが追加されました。 このことで、Node 20 に組み込みのテストAPIを使用できるようになります。
リリースノートに示されたテストコードを参照し、動作確認します。
$ cat test.mjs import assert from "node:assert"; import test from "node:test"; test("synchronous passing test", (t) => { assert.strictEqual(1, 1); }); test("asynchronous passing test", async (t) => { assert.strictEqual(1, 1); }); # Node の場合 $ node -v v20.7.0 $ node --test test.mjs ✔ synchronous passing test (1.0344ms) ✔ asynchronous passing test (0.1101ms) ℹ tests 2 ℹ suites 0 ℹ pass 2 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 59.7531 # Deno の場合 $ deno -V deno 1.36.4 $ deno test .\test.mjs running 2 tests from ./test.mjs synchronous passing test ... ok (8ms) asynchronous passing test ... ok (6ms) ok | 2 passed | 0 failed (46ms)
詳細な表示はランタイムによりますが、それぞれとも実行できました。
deno bench の改善
deno bench の精度とベンチマーク粒度が改善されました。
ベンチマーク精度
deno bench の実行前に、空の関数を実行するウォームアップがされるようになりました。 このことで JIT bias という不適切な最適化が回避されるようになりました。
詳細はプルリクエストに記載があるので興味があれば読んでみるのが良いと思います。
https://github.com/denoland/deno/pull/19844
ベンチマーク粒度
Deno.BenchContext.start
と Deno.BenchContext.end
のふたつのメソッドが追加されました。
この二つの関数の間で記述されたものだけをベンチマーク対象にできる機能です。
動作を確認します。
ベンチマークを行うコードは次の通りです。 [bench.ts]
Deno.bench("bench 1", () => { let tmp = ""; for (let i = 0; i < 10000000; i++) { tmp += "a"; } for (let i = 0; i < 10000000; i++) { tmp += "b"; } for (let i = 0; i < 10000000; i++) { tmp += "c"; } }); Deno.bench("bench 2", (b) => { let tmp = ""; for (let i = 0; i < 10000000; i++) { tmp += "a"; } b.start(); for (let i = 0; i < 10000000; i++) { tmp += "b"; } b.end(); for (let i = 0; i < 10000000; i++) { tmp += "c"; } });
bench 2 のみ、 2つ目の処理だけを Deno.BenchContext.start
と Deno.BenchContext.end
で囲みました。
全体の処理からすれば 1/3 だけがベンチマーク対象になっているのでそのような結果を予想します。
$ deno bench .\bench.ts cpu: Intel(R) Core(TM) i5-9400F CPU @ 2.90GHz runtime: deno 1.36.4 (x86_64-pc-windows-msvc) file:///hoge/bench.ts benchmark time (avg) iter/s (min … max) p75 p99 p995 --------------------------------------------------------------- ----------------------------- bench 1 4.31 s/iter 0.2 (3.99 s … 4.72 s) 4.51 s 4.72 s 4.72 s bench 2 1.4 s/iter 0.7 (1.25 s … 1.79 s) 1.41 s 1.79 s 1.79 s
同じ処理をされつつも、対象箇所が絞られた bench 2 の方が結果3倍程度結果が良くなっており、対象箇所が絞られていることがわかります。
Node.js 互換性の向上
bin に登録されていない npm パッケージのスクリプトを実行できるようになりました。
process.dlopen が使用できるようになりました。
process.dlopen APIを使用して、Node.js のネイティブアドオンを読み込みできるようになりました。
AsyncLocalStorage
node:async_hooks
に用意されているAsyncLocalStorageの実装が最適化され Deno 1.35.3 対比で、3.5倍高速になったそうです。
node:os が完全にポリフィルされました
Node.js ビルトインモジュールの node:os
が完全にポリフィルされました。
Deno 1.35 と動作比較を行うと次のようになります。
$ cat os.ts import { getPriority,userInfo } from "node:os"; console.log(getPriority()); console.log(userInfo()); $ deno -V deno 1.36.0 $ deno run --allow-sys --allow-env os.ts error: Uncaught Error: Not implemented: See https://github.com/denoland/deno_std/issues/1436 at notImplemented (ext:deno_node/_utils.ts:9:11) at getPriority (node:os:88:5) at file:///usr/src/app/1.36/os.ts:3:13 $ deno -V deno 1.36.0 $ deno run --allow-sys --allow-env os.ts 0 { uid: 0, gid: 0, homedir: "/root", shell: null, username: "root" }
各種更新/品質向上
deno compile --no-terminal の追加
deno compile で作成されたバイナリをWindowsで実行すると、ターミナルが開く動作をしていまいた。 こちらを抑制するオプションが追加になりました。
Deno.createHttpClient.allowHost の追加
unstable な機能として Deno.createHttpClient が allowHost をサポートするようになりました。 こちらを設定することで、fetch を使用したリクエストの際に Host ヘッダーを設定できるようになります。
WebSocket APIで、HTTP(S) のURLが使えるようになった
WebSocket で提供される Web API について、http: と https: のふたつのスキームを受け入れるようになりました。 Deno はそれぞれを ws: とwss: の何れかのプロトコルであると自動的に調整し、動作します。
その他
- 失敗したモジュールのダウンロードが再試行されるようになった
- Deno.Command API 実行時、存在しないバイナリを実行しようとした際に、意味あるエラーを返すようになった
- LSP の修正と改善
まとめ
このリリースはリリースノートで、Deno 1.36: More flexible security and expanded testing APIs
と銘打たれている通り、
セキュリティとテストの拡張のリリースでした。
そのほか目立つのは、Node.js 互換性の向上が目立っていました。
すでに Deno 1.38まで がリリースされています。またこちらも追いかけていきます。
採用情報
虎の穴では一緒に働く仲間を募集中です!
この記事を読んで、興味を持っていただけた方はぜひ弊社の採用情報をご覧下さい。
カジュアル面談やエンジニア向けイベントも随時開催中です。ぜひチェックしてみてください♪
yumenosora.co.jp