皆さんこんにちは。おっくんです。
去る 2022 年 2 月 17 日に Deno 1.19 がリリースされました。 今回も、リリースノートを参考に 変更事項の気になるところを紹介します。
Deno 1.19
Deno 1.19 での変更事項をDeno 1.19 リリースノートを元に確認します。
deno vendor が追加されました
deno vendor
コマンドが、本リリースで追加されました。
このコマンドは、ソースコードが参照しているモジュール群をローカルの vendor ディレクトリに展開します。
実際の例を元に紹介します。
次の sample.ts を用意します。
[sample.ts]
import { serve } from "https://deno.land/std@0.128.0/http/server.ts"; console.log("http://localhost:8000/"); serve((req) => new Response("Hello World\n"), { port: 8080 });
こちらを、deno run --allow-net=0.0.0.0:8080 sample.ts
で実行すると、次のようにコンソールに出力されます。
# deno run app.ts Download https://deno.land/std@0.128.0/http/server.ts Download https://deno.land/std@0.128.0/async/mod.ts Download https://deno.land/std@0.128.0/async/deadline.ts Download https://deno.land/std@0.128.0/async/debounce.ts Download https://deno.land/std@0.128.0/async/deferred.ts Download https://deno.land/std@0.128.0/async/delay.ts Download https://deno.land/std@0.128.0/async/mux_async_iterator.ts Download https://deno.land/std@0.128.0/async/pool.ts Download https://deno.land/std@0.128.0/async/tee.ts Check file:///usr/src/app/app.ts http://localhost:8000/
Download https://deno.land/~~
と記載されています。
この時のダウンロード先は、deno info
を実行することで確認できます。
$ deno info DENO_DIR location: "/deno-dir/" Remote modules cache: "/deno-dir/deps" Emitted modules cache: "/deno-dir/gen" Language server registries cache: "/deno-dir/registries" Origin storage: "/deno-dir/location_data"
Remote modules cache: "/deno-dir/deps"
とある通り、/deno-dir/deps
以下のディレクトリにダウンロードされて、キャッシュされていることがわかります。
確認します。
# 実行結果は一部省略 $ tree /deno-dir/deps /deno-dir/deps `-- https `-- deno.land |-- 36787f82612f5ba8672f136ec0b2ea965f132c9befbf1675e62363ae08caa974 |-- 36787f82612f5ba8672f136ec0b2ea965f132c9befbf1675e62363ae08caa974.metadata.json |-- 4c6be3d215f27a63ef23312109ee64fd8464c0f78fa8c95ca4636f77e9eb694b |-- d81b6a4c078ed0c3b11068d078a003e15fc11d4d0c52923a4e09e4e5bc6aa98e.metadata.json |-- e69a1acdd75c91705c4d0c85a7d92d5458b8db838db0266acaf0f715e99a5ff9 `-- e69a1acdd75c91705c4d0c85a7d92d5458b8db838db0266acaf0f715e99a5ff9.metadata.json
このようなキャッシュ以外のところでの、新しいモジュールの管理方法が、deno vendor
です。
deno vendor
を実行してみます。
$ deno vendor sample.ts Download https://deno.land/std@0.128.0/http/server.ts Download https://deno.land/std@0.128.0/async/mod.ts Download https://deno.land/std@0.128.0/async/deadline.ts Download https://deno.land/std@0.128.0/async/debounce.ts Download https://deno.land/std@0.128.0/async/deferred.ts Download https://deno.land/std@0.128.0/async/delay.ts Download https://deno.land/std@0.128.0/async/mux_async_iterator.ts Download https://deno.land/std@0.128.0/async/pool.ts Download https://deno.land/std@0.128.0/async/tee.ts Vendored 9 modules into vendor/ directory. To use vendored modules, specify the `--import-map` flag when invoking deno subcommands: deno run -A --import-map vendor/import_map.json sample.ts $ tree . |-- sample.ts |-- docker-compose.yml |-- dockerfile `-- vendor |-- deno.land | `-- std@0.128.0 | |-- async | | |-- deadline.ts | | |-- debounce.ts | | |-- deferred.ts | | |-- delay.ts | | |-- mod.ts | | |-- mux_async_iterator.ts | | |-- pool.ts | | `-- tee.ts | `-- http | `-- server.ts `-- import_map.json
現在のディレクトリに vendor ディレクトリが作成され、参照しているモジュール群が展開されました。
このローカルのモジュール群を参照するには、deno vendor
の実行結果に書いているように、
--import-map vendor/import_map.json
をつけて次のように実行します。
deno run --allow-net=0.0.0.0:8080 --import-map vendor/import_map.json sample.ts
deno vendor
の目的は、大きく二つあります。
1 つ目は、外部モジュールを本体のリポジトリの管理下に置くこと。このことで外部モジュールも本体と同じ git で管理できます。
2 つ目は、デバッグ時に外部モジュールへの一時的なデバッグコードの挿入が容易にできるようになることです。
個人的には、2 つ目の恩恵が大きいと感じます。
外部モジュール関連の確認の際に、一時的にデバッグコードを仕込みたいということがあります。
この時は、リポジトリを(ソースと関係ないものも含めて)まとめてクローンして、デバックコードを挿入。
クローンしたディレクトリを参照するように自身コードを直すというという流れになると思います。
deno vendor
を使うと、ソースだけを取得し、--import-map vendor/import_map.json
をつけて実行するだけで良くなります。
パーミッションの許可プロンプトが標準動作になりました。
Deno では、パーミッションの管理が厳格にされていますが、結果多くのコマンドラインフラグを要求する傾向にあります。 Deno 1.9 では--prompt を実行時に渡すことで、プロンプトで権限を与えるオプションが公開されていました。 Deno 1.19 からは、この動作が標準になりました。 先に出している sample.ts の動作で確認します。
[sample.ts の実行結果]
# プロンプトを表示 $ deno run sample.ts http://localhost:8000/ ⚠️ ️Deno requests net access to "0.0.0.0:8080". Run again with --allow-net to bypass this prompt. Allow? [y/n (y = yes allow, n = no deny)] y # プロンプトを表示しない場合には、例外発生 $ deno run --no-prompt sample.ts http://localhost:8000/ error: Uncaught (in promise) PermissionDenied: Requires net access to "0.0.0.0:8080", run again with the --allow-net flag const listener = Deno.listen({ ^ at Object.opSync (deno:core/01_core.js:168:12) at opListen (deno:ext/net/01_net.js:40:17) at Object.listen (deno:ext/net/01_net.js:299:17) at Server.listenAndServe (https://deno.land/std@0.128.0/http/server.ts:181:27) at serve (https://deno.land/std@0.128.0/http/server.ts:557:23) at file:///usr/src/app/sample.ts:4:1
ネイティブ Web ストリームとしてファイル、ネットワークソケット、標準入力が使えるようになりました
Deno.FsFile
と Deno.conn
に、ReadableStream
な readable
と WritableStream
なwritable
が追加されました。
このことで、Web ストリームを扱ういくつかの API と併せて使いやすくなったそうです。
サンプルとして、いくつかの使用例をリリースノートで示してものを参考に紹介します。
[file_001.ts]
const file = await Deno.create("./example.html"); const response = await fetch("https://example.com"); const body = await response.body; if (!body) Deno.exit(); body.pipeTo(file.writable);
(具体的な URL は記載できませんが、書き換えて試すとわかりやすいと思います。)
コチラを実行すると、fetch で取得した結果をファイルに書き出すことができます。
これは、Deno.create により作られた WritableStream に、Response.body が持つ ReadableStream をつないで読み取りから書き出しまで Web ストリームで完結させた形です。
[stream_002.ts]
const resp = await fetch("http://0.0.0.0:8080", { method: "POST", body: Deno.stdin.readable, }); console.log("Upload succeded?", resp.ok);
コチラは、標準入力から与えられたストリームを入力として、fetch の body プロパティに引き渡し、ストリーミングアップロードを実現したものです。
実行方法は、次のように紹介されています。
cat file.txt | deno run --allow-net=example.com stream_002.ts
[stream_003.ts]
import { serve } from "https://deno.land/std@0.128.0/http/server.ts"; serve( async (request) => { if (request.method === "POST") { // 受け取ったファイルのストリーム処理で書き込み const path = await Deno.makeTempFile(); console.log(`output: ${path}`); // 書き出し先 const file = await Deno.create(path); const body = await request.body; if (!body) return new Response("Not Save file"); await body.pipeTo(file.writable); return new Response(`Saved file to ${path}`); } else { // ディスクからページを読み込みストリームで配信 const path = "./example.html"; const file = await Deno.open(path); return new Response(file.readable, { headers: { "content-type": "text/html" }, }); } }, { port: 8080 } );
stream_003.ts は、WEB のリクエストからストリームを作成しストリームで書き込む処理と、ディスクからストリームで読み込んだファイルを、クライアントにストリームで返す処理が実装されています。
リリースノートに説明は無いのですが、 stream_003.ts をサーバーに、stream_002.st をクライアントとして動作し、 内容の受け渡しができます。 動作は以下の通りです。
[サーバー側コンソール]
$ deno run --allow-net=0.0.0.0:8080 stream_003.ts Check file:///usr/src/app/file/stream_003.ts # ここでクライアント側コンソールを実行 output: /tmp/5323ea3c ^C # コンソールを停止 $ cat /tmp/5323ea3c UPLOAD TEXT
[クライアント側コンソール]
$ cat upload.txt UPLOAD TEXT $ cat upload.txt | deno run --allow-net=0.0.0.0:8080 stream_002.ts Upload succeded? true
CompressionStream と DecompressionStream API が追加されました
先述の Web ストリームの対応と同じくして CompressionStream と DecompressionStream API が追加されました。 これらは、MDN に個別に解説があるので、ご覧ください。
それぞれ、ストリームの圧縮と解凍を行う API です。 .gz ファイルを解凍する例は次のように示されています。
[decomp.ts]
const input = await Deno.open("./comp.txt.tar.gz"); const output = await Deno.create("./decomp.txt"); await input.readable .pipeThrough(new DecompressionStream("gzip")) .pipeTo(output.writable);
実行すると次のようになります。
$ echo PLAIN FILE > plain.txt $ gzip plain.txt -c > comp.txt.gz $ deno run --allow-write --allow-read decomp.ts Check file:///usr/src/app/comp/decomp.ts $ cat decomp.txt PLAIN FILE
console.log が循環参照を表示するようになった
console.log がログの対象となったオブジェクトの循環参照についてより分かりやすく表示するようになりました。 Deno 1.18 と比較します。
// Deno 1.18 > const x = { a: {}, b: {}, foo: { deno: "land", bar: 1 } }; > x.a.x = x; > x.b.y = x; > console.log(x); { a: { x: [Circular] }, b: { y: [Circular] }, foo: { deno: "land", bar: 1 } } > x.b.x = x.a; > console.log(x.b.x); { x: { a: [Circular], b: { y: [Circular], x: [Circular] }, foo: { deno: "land", bar: 1 } } } // Deno 1.19 > const x = { a: {}, b: {}, foo: { deno: "land", bar: 1 } }; > x.a.x = x; > x.b.y = x; > console.log(x); <ref *1> { a: { x: [Circular *1] }, b: { y: [Circular *1] }, foo: { deno: "land", bar: 1 } } > x.b.x = x.a; > console.log(x.b.x); <ref *1> { x: <ref *2> { a: [Circular *1], b: { y: [Circular *2], x: [Circular *1] }, foo: { deno: "land", bar: 1 } } }
Deno 1.19 では、循環の対象になっているオブジェクト を<ref *1>
のように示すようになりました。
循環の対象が複数ある場合、より顕著に Deno 1.19 の表示の方がわかりやすくなります。
signal listener API が安定化
Deno 1.16 で登場した signal listener API が、安定化しました。 ただし、Windows では現在も使用できないそうですので、ご注意下さい。
リリースノートに記載のサンプルは次のようになっています。
const listener = () => { console.log("Got SIGTERM!"); }; // Starts listening for SIGTERM Deno.addSignalListener("SIGTERM", listener); // Stops listening for SIGTERM Deno.removeSignalListener("SIGTERM", listener);
Unix ソケットを使用して、HTTP 接続ができるようになりました
Deno では Unix ソケット介した TCP 接続をこれまで使用できませんでした。 Deno 1.19 から、HTTP も Unix ソケットで提供できるようになります。 使用には、--unstable の付与が実行時に必要になります。
リリースノートに記載のサンプルは次のようになっています。
import { serveListener } from "https://deno.land/std/http/server.ts"; const listener = Deno.listen({ transport: "unix", path: "/path/to/socket" }); serveListener(listener, (req) => { return new Response("Hello World"); });
HTTP の受け口として NginxのようなWebサーバを使うような構成を取っていた時、 これまでは WEBサーバーから アプリケーションが使用している ポートへの転送だけでした。 これからは Unix ソケットも使用してWEBサーバーと連携できるようになります。
unstable な API Deno.Conn.setNoDelay() と Deno.Conn.setKeepAlive() が追加されました。
TCP接続を行う Deno.Conn に2つのAPIが増えました。
- Deno.Conn.setNoDelay() : Nagle アルゴリズムの設定
- Deno.Conn.setKeepAlive() : キープアライブの設定
使用には、--unstable の付与が実行時に必要になります。
unstable な Deno.getUid APIが追加されました
Deno 1.19 では、deno プロセスを実行しているユーザーのuidを取得できるようになりました。 リリースノート記載のサンプルは次のようになっています。
const interfaces = Deno.getUid();
console.log(interfaces);
実行には、--unstable
に加え --allow-env
も必要になります。実行すると次のようになります。
$ whoami root $ id root uid=0(root) gid=0(root) groups=0(root) $ deno run --unstable --allow-env get_uid.ts 0
unstable な Deno.networkInterfaces APIが追加されました
Deno 1.19 では、実行環境のネットワークインターフェース取得できるようになりました。 リリースノート記載のサンプルは次のようになっています。
const interfaces = Deno.networkInterfaces();
console.log(interfaces);
Deno.getUid 同様に実行には、--unstable
に加え --allow-env
も必要になります。実行すると次のようになります。
$ deno run --unstable --allow-env get_network.ts Check file:///usr/src/app/network/get_network.ts [ { family: "IPv4", name: "lo", address: "127.0.0.1", netmask: "255.0.0.0", scopeid: null, cidr: "127.0.0.1/8", mac: "00:00:00:00:00:00" }, ... ]
--allow-env
を設定することで環境変数すべてへの参照を許可したくないので、--allow-env=hogehoge
のような設定ができないか確認しましたが、API ドキュメント には、詳細の記載がありませんでした。
改めてstable になった時に確認したいと思います。
V8 9.9 へ更新されました
Deno に同梱される V8 のバージョンが、9.9 にアップデートされました。 これにより、Intlオブジェクトに機能が追加されています。
MDNに、Intlについて詳細な解説があります。
ロケールの拡張機能
言語に対応したカレンダーが取得できるようになっています。
> const japanLocale = new Intl.Locale("ja-JP"); > japanLocale.calendars [ "gregory", "japanese" ]
識別子の列挙
V8 が対応する言語と、通貨のリストを取得できるようになりました。
> Intl.supportedValuesOf("calendar"); [ "buddhist", "chinese", "coptic", "dangi", "ethioaa", "ethiopic", "gregory", "hebrew", "indian", "islamic", "islamic-civil", "islamic-rgsa", "islamic-tbla", "islamic-umalqura", "iso8601", "japanese", "persian", "roc" ] > Intl.supportedValuesOf("currency"); [ "AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN", "BAM", "BBD", "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BRL", "BSD", "BTN", "BWP", "BYN", "BZD", "CAD", "CDF", "CHF", "CLP", "CNY", "COP", "CRC", "CUC", "CUP", "CVE", "CZK", "DJF", "DKK", "DOP", "DZD", "EGP", "ERN", "ETB", "EUR", "FJD", "FKP", "GBP", "GEL", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD", "HKD", "HNL", "HRK", "HTG", "HUF", "IDR", "ILS", "INR", "IQD", "IRR", "ISK", "JMD", "JOD", "JPY", "KES", "KGS", "KHR", "KMF", "KPW", "KRW", "KWD", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LYD", "MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRU", "MUR", "MVR", "MWK", "MXN", "MYR", "MZN", "NAD", "NGN", "NIO", ... 58 more items ]
その他
Deno.test
のサニタイザーエラーの記述が見やすくなりましたDeno.File
は、Deno.FsFile
に名前が変更されましたdeno compile
が、より確実に動作するようになりました- ファイルウォッチャーの再起動時に 画面のクリアを無効にするオプション
--no-clear-screen
が追加されました - deno coverage に --output フラグが追加されました
- LSP が改善しました
まとめ
今回のリリースでは、deno vendor が特に興味惹かれるものだったと感じます。 また、以前個人的にUnix ソケットで HTTP が使用できないのか確認して、当時できないことを確認していたこともあり、嬉しさがあるものでした。
ファイルアクセスもWebAPIとの共通の仕様でアクセスできるようになり、嬉しい点が多いです。 ストリーム処理について学んでみるきっかけができたと感じるので、近いうちに勉強してみたいと思いました。
明日は、 Deno 1.20のリリースノート追っかけ記事を公開予定です。
P.S.
採用情報
■募集職種
yumenosora.co.jp