Deno v1.38がリリースされました。
この記事では主な変更点などについて解説します。
deno doc
deno doc --lint
deno doc
コマンドで--lint
オプションがサポートされました。
$ deno doc --lint mod.ts
Missing JS documentation comment.
at file:///home/uki00a/ghq/github.com/uki00a/some-project/mod.ts:12:3
このオプションを指定すると、DenoはAPIドキュメントを出力する前に、各APIを検査します。そして以下のようなAPIが検出された場合、APIドキュメントを出力せずにエラーを表示します。
export
されているAPIにJSDocコメントが書かれていない場合 (Missing JS documentation comment.
)export
されているAPIの戻り値の型定義が省略されている場合 (Missing return type.
)export
されている型のプロパティがexport
されていない型を参照している場合 (Type 'foo' references type 'Bar' which is not exported from a root module.
)- このエラーが発生した場合、その
export
されていない型に@internal
を指定することでエラーを抑止できます
- このエラーが発生した場合、その
deno doc --html
deno doc
でAPIドキュメントのHTML形式での出力がサポートされました。 --html
を指定すると、docs
ディレクトリにHTMLが出力されます。
$ deno doc --html --name=fresh-testing-library mod.ts
Written 261 files to "./docs/"
docs/index.html
を開くことで作成されたAPIドキュメントを閲覧できます。
# ファイルサーバーを起動します
$ deno run --allow-read --allow-net https://deno.land/std@0.205.0/http/file_server.ts ./docs
# ブラウザを開きます
$ xdg-open http://localhost:4507
APIドキュメントの保存先ディレクトリを変更したい場合は、--output
オプションを指定します。
$ deno doc --html --output=api-docs --name=fresh-testing-library mod.ts
公開APIから参照されている非公開APIの出力がサポート
例えば、以下のようなファイルがあったとします。
interface BaseOptions {
port: number;
}
export interface ServerOptions extends BaseOptions {
signal: AbortSignal;
}
非公開APIであるBaseOptions
は公開APIであるServerOptions
から参照されています。この場合、非公開APIであるBaseOptions
の情報も出力されます。(v1.37までは出力されませんでした)
$ deno doc mod.ts
Defined in file:///home/uki00a/ghq/github.com/uki00a/some-project/mod.ts:1:1
private interface BaseOptions
**** port: number
Defined in file:///home/uki00a/ghq/github.com/uki00a/some-project/mod.ts:5:1
interface ServerOptions extends BaseOptions
signal: AbortSignal
複数エントリポイントの指定がサポート
例えば、v1.37まではdeno doc
コマンドに複数のエントリポイントを指定すると、以下のようなエラーが発生します。
$ deno doc server.ts expect.ts
error: Node expect.ts was not found!
v1.38ではこの挙動が改善され、複数のエントリポイントを引数として指定できるようになりました。例えば、以下のケースだと、server.ts
とexpect.ts
それぞれのAPIドキュメントが出力されます。
$ deno doc server.ts expect.ts
この変更による影響として、フィルタリングを行いたい際は、今後は明示的に--filter
オプションを指定する必要があります。
$ deno doc --filter=createHandlerContext server.ts expect.ts
HMRがサポート (--unstable-hmr
)
Denoに--unstable-hmr
というオプションが追加されました。
基本的には--watch
オプションと同様の振る舞いをしますが、ファイルが変更された際に、可能な際はプロセス全体を再起動せずに、変更されたファイルのみに対してその場でパッチを当ててくれます。
$ deno run --unstable-hmr=config.json --no-clear-screen mod.ts
ただし、--unstable-hmr
に指定されたファイルが変更された場合など、状況によっては--watch
と同様にプロセス全体が再起動されることもあるようです。
また、ファイルの変更が発生した際にDenoはhmr
イベント(CustomEvent)を発火するため、状態の更新など必要に応じて独自の処理を実装することも可能です。
function onHMR(path: string) {
// ...
}
addEventListener("hmr", (e) => {
onHMR(e.detail.path);
});
unstable APIの詳細な制御がサポート (--unstable-*
オプション)
Denoにはいくつかのunstable APIが存在します。(例: Deno.openKv
, Deno.dlopen
など)
こういったAPIを利用するためには、--unstable
オプションを指定する必要がありました。しかし、--unstable
オプションはユーザーが直接利用しないすべてのunstable APIを有効化します。
より細かく有効化したいAPIを制御するために、--unstable-ffi
/--unstable-kv
/--unstable-cron
など、各カテゴリごとにunstable APIを有効化するためのオプションが実装されました。
例えば、--unstable-kv
を指定した際は、unstable APIのうちDeno KV関連のAPIのみが有効化されます。
$ deno run --unstable-kv main.js
現時点では以下のオプションが提供されています。
--unstable-broadcast-channe
--unstable-ffi
--unstable-fs
--unstable-http
--unstable-kv
--unstable-net
--unstable-worker-options
--unstable-cron
(後述)--unstable-bare-node-builtins
(後述)--unstable-byonm
(後述)
deno.json
unstable
フィールドが追加
--unstable-*
オプションの実装に関連して、deno.json
でも有効化したいunstable APIを細かく管理できるように改善されました。
{
"unstable": ["kv", "cron"]
}
compilerOptions.jsx
でprecompile
がサポート
compilerOptions.jsx
でDeno独自の設定としてprecompile
がサポートされました。
precompile
の導入の目的として、ソースコード中のJSXテンプレートに含まれるHTMLノードをトランスパイル時にあらかじめ文字列へ変換しておくことで、オブジェクトの割り当てを減らし、SSR時のパフォーマンスの向上を狙う意図があるようです。
基本的にはPreact/Freshでの使用を想定したオプションであると思われますが、サポートを入れることでそれ以外のフレームワークでも利用は可能なようです。
Preactでは現在、このprecompile
向けのサポートが進んでいるようで、近いうちに利用できるようになるかもしれません。
feat: support precompiled JSX transform (preactjs/preact#4177)
feat: add support for precompiled JSX (preactjs/preact-render-to-string#322)
また、以下のリポジトリではPreact+precompile
オプションの使用例が公開されています。
.env
のサポート (--env
オプション)
deno run
やdeno test
などのコマンドで--env
オプションが実装されました。このオプションを指定すると、コードを実行する前にDenoが.env
から環境変数を読み込んでくれます。
$ deno run --env main.js
--allow-read
を指定せずに.env
の読み込みが行えることが利点のようです。
もし.env
以外から環境変数を読みたい場合は、--env
オプションにパスを指定する必要があります。
$ deno run --env=.env.development main.js
deno repl
でJSXがサポート
deno repl
でJSXがサポートされました。
$ deno repl
> /** @jsxImportSource https://esm.sh/preact@10.18.1 */
undefined
> const vnode = <div>foobar</div>;
┌ ⚠️ Deno requests net access to "esm.sh".
✅ Granted net access to "esm.sh".
undefined
Deno API
Deno.cron
(unstable)
新しいAPIとしてDeno.cronが実装されています。
このAPIを利用する際はdeno.json
のunstable
オプションや--unstable-cron
オプションなどで有効化できます。
{
"unstable": ["cron"]
}
このAPIを利用することで、Cron式に指定された内容に基づいてハンドラーを定期的に実行することができます。
Deno.cron(
"sample", // ジョブ名
"*/1 * * * *", // cron式
async () => { // ハンドラー
await doSomething();
},
);
Deno CLIの実装においては、Cronに関する状態はメモリ上にのみ保持されディスクには永続化されないようなので、少し注意が必要かもしれません。
リトライについて
もしハンドラーの実行に失敗した場合、最大で5回まで自動的にリトライされます。リトライ間隔はデフォルトで100ms → 1s → 5s → 30s → 1mのようです。(ext/cron/local.rs#L32)
この挙動はbackoffSchedule
オプションによりカスタマイズが可能で、例えば、以下のケースだと1s → 2s → 4sの間隔で最大3回までリトライが行われます。
Deno.cron(
"sample", // ジョブ名
"*/1 * * * *", // cron式
async () => { // ハンドラー
await doSomething();
},
{
backoffSchedule: [1000, 2000, 4000],
},
);
ジョブの中断
Deno.cron
にはsignal
オプションを指定することができます。指定されたAbortSignal
が中断状態に変わると、Denoは対象のジョブの登録を解除します。
const ac = new AbortController();
// ...
await Deno.cron(
"sample",
"*/1 * * * *",
async () => {
await doSomething();
},
{
signal: ac.signal,
},
);
また、Deno.cron
は戻り値としてPromise
を返却しますが、このPromise
はAbortSignal
が中断されるとresolve
されます。
Deno.serve
意図を明確にするために、Deno.Server
がDeno.HttpServerへリネームされました。Deno.Server
は非推奨化されており、今後、削除される予定です。
using
のサポート
以下の各オブジェクトでSymbol.dispose
/Symbol.asyncDispose
が実装されています。
Symbol.dispose
Deno.FsFile
Deno.FsWatcher
Deno.ChildProcess
Deno.Kv
Deno.Listener
Deno.Conn
Symbol.asyncDispose
Deno.HttpServer
使用例:
{
using kv = await Deno.openKv(":memory:");
console.info(await kv.get(["users", 1]));
}
{
using f = await Deno.open("deno.json");
console.info(await f.stat());
}
Deno KV
リモートバックエンドでもexpireIn
オプションがサポートされました。
Node.js互換性
npm
などで作成されたnode_modules
のサポート (BYONM)
npm
などで作成されたnode_modules
ディレクトリからのnpmパッケージの読み込み(BYONM)がサポートされました。
例えば、以下のようにnpm
でkoa
パッケージがインストールされていたとします。
$ npm i koa
npm
によってインストールされたkoa
パッケージをnpm:
なしで読み込むJavaScriptファイルを用意します。
// index.js
import Koa from "koa";
const app = new Koa();
app.use(async (ctx) => {
ctx.body = "Hello Deno!";
});
app.listen(3000);
この状態で--unstable-byonm
オプションを指定するか または deno.json
でunstable: ["byonm"]
を設定すると、npm
によって作成されたnode_modules
ディレクトリからkoa
パッケージが読みこまれます。
$ deno run --unstable-byonm --allow-net --allow-read --allow-env index.js
将来的には、package.json
が存在する際は--unstable-byonm
の挙動をデフォルト化することも検討されているようです。
node:
なしでのNode.js組み込みパッケージの読み込み (--unstable-bare-node-builtins
)
Node.jsの組み込みパッケージのnode:
なしでの読み込みがサポートされました。(基本的には、node:
を付けて読み込むことが推奨されます)
import { EventEmitter } from "events";
const emitter = new EventEmitter();
emitter.once("foo", console.info);
emitter.emit("foo", 123);
この機能は以下のいずれかの方法で有効化できます。
- BYONMを有効化する
--unstable-bare-node-builtins
を指定するdeno.json
で"unstable": ["bare-node-builtins"]
を設定する
その他の改善
EventSource
が実装されましたWebSocket
over HTTP/2が実装されました- Deno本体のV8がv12へアップデートされました (
Array.fromAsync
/Promise.withResolvers
が利用できるように) Object.groupBy
やMap.groupBy
の型定義が追加されましたdeno test
:--junit-path
オプションで指定されたディレクトリが存在しない場合でも動作するように改善されました。deno lsp
:deno.json
がない場合は、フォーマット時にtypescript.preferences.quoteStyle
が参照されるように改善されました。