Deno v1.31がリリースされました。
この記事では主な変更点などについて解説します。
package.json
サポート
Denoでpackage.json
がサポートされました。
具体的には、以下のような機能などが実装されています。
package.json
の自動探索dependencies
/devDependencies
の定義内容によるbare specifierの解決deno task
によるscripts
の実行
package.json
の自動探索
deno.json
などのファイルと同様に、Denoがpackage.json
も自動で探索してくれるようになりました。
もしpackage.json
が見つかった場合、必要に応じてdependencies
やdevDependencies
で記述された依存パッケージを自動でダウンロードし、デフォルトでnode_modules
ディレクトリに保存してくれます。 (従来通り、package.json
が存在しない状態でnpm:
経由でnpmパッケージをimport
した際は、--node-modules-dir
を指定しない限り、node_modules
は作成されません)
もし、package.json
の自動探索を無効化したい場合は、以下のいずれかの手段で無効化できます (以下の機能は、それぞれ次のリリースであるv1.31.1で追加された機能のためご注意!)
--no-config
または--no-npm
オプションを指定する。DENO_NO_PACKAGE_JSON
環境変数に1
を指定する
dependencies
/devDependencies
によるbare specifierの解決
Denoがpackage.json
のdependencies
やdevDependencies
で定義された依存関係を元に、Import Mapsライクにbare specifierを解決してくれるようになりました。
例えば、以下のような内容のpackage.json
が存在したとします。
{
"dependencies": {
"chalk": "^5.2.0",
"koa": "2"
}
}
この場合、アプリケーションでは以下のようにbare specifierを記述することがでます。
import chalk from "chalk"; // => `npm:chalk@^5.2.0`
import Koa from "koa"; // => `npm:koa@2`
const app = new Koa();
app.use((ctx) => {
ctx.body = "Hello world";
});
app.listen(3000, () => {
console.log(chalk.blue.bold("Listening on port 3000"));
});
もしImport Maps (deno.json
のimports
プロパティなど)とpackage.json
の両方が存在する場合は、Import Mapsが優先されます。
そのような場合、DenoはまずImport Mapsを元にbare specifierの解決を試み、それがうまくいかなければpackage.json
による解決へfallbackします。
deno task
によるscripts
の実行がサポート
package.json
のscripts
で定義されたスクリプトのdeno task
コマンドによる実行がサポートされました。
dependencies
やdevDependencies
で宣言されているパッケージであれば、それらのパッケージで提供されるコマンドも実行することができます。
具体的には、以下はdeno task
でcowsay
パッケージを実行する例です。
{
"devDependencies": {
"cowsay": "^1.5.0"
},
"scripts": {
"hello": "cowsay Hello"
}
}
以下のように実行できます
$ deno task hello
このようにnpmパッケージに含まれるコマンドを実行する際は、内部的には以下のようなコマンドが実行されます。
$ deno run -A npm:cowsay@^1.5.0 hello
もしプロジェクト内にdeno.json
とpackage.json
の両方が存在する場合は、deno.json
が優先されます。
そのような場合、Denoはまずdeno.json
のtasks
に対象のタスクが定義されていないかを確認し、もし存在しなければ、package.json
のscripts
からタスクの探索を試みます。
deno_std/node
のDeno本体への組み込み
今まで、DenoにおけるNode.js互換機能は、deno_std/nodeで実装されたポリフィルを利用することで実現されていました。
その関係で、Denoの初回実行時にdeno_std/nodeのダウンロードが必要であったり、ポリフィルの実装にDenoの内部APIやOpなどの仕組みが使いづらいというような課題がありました。
これらの課題を解決するため、Deno本体にポリフィル(deno_std/node
)が組み込まれました。
Node.jsのポリフィルはDenoのビルド時にあらかじめ作成されるV8のスナップショットに含まれており、Denoからnpmパッケージを利用する際の起動の高速化などが期待されます。
この変更を受けて、今までTypeScriptで実装されていた一部の組み込みパッケージ(node:punycode
やnode:crypto
など)の実装などがRustへポートされています。
また、今までTypeScriptのみでは実装が難しかったnode:v8
パッケージの一部の機能も実装が追加されています。
import { getHeapStatistics } from "node:v8";
console.log(getHeapStatistics());
Node.js互換性に関する安定化
Node-APIの安定化
Node-APIが安定化されました。
今後はNode-APIを--unstable
なしで利用できます。(ただし、Node-APIの利用には--allow-ffi
の指定が必要です)
PrismaなどのパッケージがNode-APIに依存しているため、そういったパッケージがより使いやすくなりそうです。
npm:
に依存したリモートモジュールに関する安定化
ローカルモジュールからのnpm:
の利用はすでにDeno v1.28で安定化されたものの、npm:
を含むリモートモジュールを利用する際は依然として--unstable
が必要な状況でした。
今回のリリースから、こういったnpm:
を含むリモートモジュールも--unstable
なしで利用できるようになりました。
deno bench
でJSONレポーターがサポート
--json
オプションを指定することで、ベンチマーク結果をJSON形式で出力することができます。
$ deno bench --json main_bench.ts
以下のように結果が出力されます。
{
"runtime": "<ランタイム情報 (Denoバージョンなど)>",
"cpu": "<CPU名>",
"benches": [
{
"origin": "file:///home/uki00a/ghq/github
.com/uki00a/deno-sample/main_bench.ts",
"group": null,
"name": "sum",
"baseline": false,
"results": [
{
"ok": {
"n": 5972,
"min": 4.7421,
"max": 24.2738,
"avg": 8.406597823174797,
"p75": 11.036,
"p99": 15.3162,
"p995": 17.3743,
"p999": 22.9964
}
}
]
}
]
}
deno bundle
コマンドの非推奨化
今後、deno bundle
コマンドを利用する際は、以下のような警告メッセージが表示されます。
Warning "deno bundle" is deprecated and will be removed in the future.
Use alternative bundlers like "deno_emit", "esbuild" or "rollup" instead.
こちらのメッセージにもあるとおり、今後はdeno_emitやesbuildなどに移行するとよさそうです。
deno fmt
コマンドのオプションの簡略化
CLIオプションによってdeno fmt
の挙動を変更したい場合、今までは、--options-
から始まるオプションを指定する必要がありました。
$ deno fmt --options-no-semicolons --options-single-quote main.js
今回のリリースからoptions-
というプレフィックスを省略できるようになり、より簡潔にオプションを指定できるように改善されています。
$ deno fmt --no-semicolons --single-quote main.js
unstable APIの安定化
Deno.Command
Deno v1.28で追加されたDeno.Command
が安定化され、--unstable
なしで利用できるようになりました。
この安定化に合わせて、Deno.CommandOptions.args
がstring[]
からreadonly string[]
型に変更されています。
(補足) Deno.run
の非推奨化について
元々は今回のDeno v1.31で予定されていたようですが、Deno.Command
の安定化とDeno.run
の非推奨化を同時に行うと移行猶予が短くなってしまうということもあり、Deno.run
の非推奨化は次のv1.32移行に持ち越されそうです。
Deno.osUptime
Deno.osUptime
が安定化されました。
今後は--unstable
オプションを指定せずに利用できます。
パーミッションプロンプトの利便性の向上
Denoは--allow-*
オプションによって権限が与えられていない処理を実行する場合、デフォルトでプロンプトを表示して、ユーザーに対して権限の付与を求めます。
例えば、以下はDeno v1.30におけるプロンプトの表示内容です。
⚠️ ┌ Deno requests read access to "foo.txt".
├ Requested by `Deno.readTextFile()` API
├ Run again with --allow-read to bypass this prompt.
└ Allow? [y/n] (y = yes, allow; n = no, deny) >
Deno v1.31では、このプロンプトに今までのy
とn
に加えて、新しくA
という選択肢が追加されています。
┌ ⚠️ Deno requests read access to "foo.txt".
├ Requested by `Deno.readTextFile()` API
├ Run again with --allow-read to bypass this prompt.
└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions) >
このA
を選択すると、該当のカテゴリの全リソースに対する権限が与えられます。(例えば、上記の場合、ファイルシステムの全ファイルへの読み込み権限が与えられます)
今までは、パーミッションプロンプトからはアクセスしたいリソースごとに一つずつ権限を与える必要がありましたが、これにより利便性が向上しています。
Deno APIに関する新機能・改善
Deno.resolveDns
にsignal
オプションが追加
AbortSignal
を使用して問い合わせをキャンセルできるようになりました。
const ac = new AbortController();
// ...
const records = await Deno.resolveDns("deno.land", "A", {
signal: ac.signal,
});
for (const x of records) {
console.log(x);
}
Deno.build.os
の型定義の改善
このプロパティは元々は以下のように型が定義されており、FreeBSDなどのOSで実行した場合、型エラーが起きてしまう問題がありました。
"darwin" | "linux" | "windows"
この問題を解消するために、v1.31で以下のように型定義が改善されました
"darwin" | "linux" | "windows" | "freebsd" | "netbsd" | "aix" | "solaris" | "illumos"
Deno.errors.WouldBlock
の追加
Deno.errors.WouldBlock
が追加されています。
これに合わせて、EWOULDBLOCK
エラーが起きたときにプロセスがパニックする問題も修正されています。(そのような場面でこのDeno.errors.WouldBlock
がthrow
されます)
FFI
Deno.UnsafePointer
/Deno.UnsafePointerView
の新機能
Deno.UnsafePointer
に以下のstaticメソッドが追加されています
メソッド | 説明 |
---|---|
create(value: number | bigint): Deno.PointerValue | 数値をDeno.PointerValue へ変換します。 |
equals(a: Deno.PointerValue, b: Deno.PointerValue): boolean | 2つのポインタが同じアドレスを参照していればtrue を返します。 |
offset(value: NonNullable<Deno.PointerValue>, offset: number): Deno.PointerValue | ポインタから指定されたオフセットだけずらした位置のアドレスを指すポインタを取得します。 |
value(value: Deno.Pointer): number | bigint | Deno.PointerValue を数値に変換します。 |
また、Deno.UnsafePointerView.getPointer
が追加されており、現在の地点から指定されたオフセットだけずらした位置のポインタをDeno.PointerValue
型として取得することができます。
Deno.UnsafeCallback
のref
/unref
に関する改善
unref
メソッドなどによって参照カウントが0になった状態のDeno.UnsafeCallback
をref
メソッドによって再度参照カウントを増加させた際に、Denoのイベントループが意図せずして停止してしまうことのある問題が修正されています。
また、あらかじめref
された状態のコールバックを作成するために、Deno.UnsafeCallback
にthreadSafe
というstaticメソッドが追加されています。
その他のバグ修正など
Deno.serve()
で起動したHTTPサーバがHEADリクエストを受信した際に、レスポンスのサイズによっては間違ったContent-Length
が返却されてしまう問題が修正されています。GPUAdapter.features
がundefined
になってしまう問題が修正されています。GPUDevice.createSampler
を呼ぶとエラーが発生する問題が修正されています。console.table
で整数のみが含まれる列のみが右寄せで表示されるように改善されています。WebSocket
クライアントからPongが余分に送信される問題が修正されています。