2021年のDenoの変更点やできごとのまとめ
Deno Advent Calendar 18日目の記事です。
この記事では2021年にDenoに関して起きた変更やできごとなどについてまとめます。
Denoランタイムに関する変更点
--no-check=remote
のサポート
--no-check
オプションでremote
を指定すると、リモートモジュール(http:
またはhttps:
で始まるモジュール)の型チェックを無効化できるようになりました。
$ deno run --no-check=remote mod.ts
Import assertionsのサポート
Deno v1.17でImport assertionsが実装されました。
現在はjsonファイルのみがサポートされています。
import modules from "./modules.json" assert { type: "json" };
Object.keys(modules);
Import mapsの安定化
Deno v1.8にてImport mapsが安定化されました。
またDeno v1.10にてリモートのImport mapsファイルもサポートされました。
$ deno run --import-map=https://deno.land/x/aleph@v0.3.0-beta.19/import_map.json main.ts
ネイティブHTTPサーバ
Deno本体にHTTPサーバが組み込まれました。
RequestやResponseなどのオブジェクトが利用されており、極力Web APIに沿うようにデザインされています。
const listener = Deno.listen({ port: 3000 });
(async () => {
for await (const conn of listener) {
(async () => {
const httpConn = Deno.serveHttp(conn);
for await (const { request, respondWith } of httpConn) {
const response = new Response("Hello world!");
respondWith(response);
}
})();
}
})();
このHTTPサーバはRustで実装されており、元々標準ライブラリに存在していたHTTPサーバ(std/http)と比較して大幅なパフォーマンス向上が見込まれます。
また、Deno.upgradeWebSocket
というAPIも提供されており、Deno.serveHttp
と併用することでWebSocketサーバを立てることもできます。
Node.js互換モード
v1.15でNode.js互換モードが実装されました
Denoの実行時に--compat
を指定することで、Node.jsの組み込みモジュール(events, fsなど)の読み込みやCommonJS形式のモジュールの実行などが有効化されます。
$ deno run --compat --unstable main.mjs
Node.jsとの互換性についてはまだ100%ではないものの、現時点でESLintやExpressなどのパッケージがある程度動くようです。
React 17のJSXトランスフォームのサポート
React 17の新しいJSXトランスフォームがDenoでサポートされました。
.jsx
または.tsx
ファイル中で@jsxImportSource
を使うことで有効化されます。
/** @jsxImportSource https://esm.sh/preact@10.5.15 */
export function Hello(props) {
return (
<div>Hello, {props.name}</div>
)
}
また、--config
オプションで指定する設定ファイルで有効化することも可能です。
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "https://esm.sh/react@17.0.2"
}
}
--allow-env
と--allow-run
でリスト指定がサポート
--allow-write
や--allow-read
などのオプションでは、以下のように権限をコンマ区切りでリスト指定することができます。
$ deno run --allow-write=tmp,dist main.ts
しかし、--allow-run
や--allow-env
ではこのリスト指定はサポートされていませんでした。
Deno v1.9で--allow-env
と--allow-run
のリスト指定がサポートされ、より厳しく権限を設定できるようになりました。
$ deno test --allow-run=redis-server,redis-cli --allow-net ./tests
Deno.permissions
の安定化
DenoのパーミッションAPI(Deno.permissions
)を使用すると、プログラムから動的にパーミッションの問い合わせや付与などを行うことができます。
このパーミッションAPIも安定化されたため、今後は--unstable
を指定せずに利用できます。
// --allow-runが指定されているか問い合わせる
await permissions.query({ name: "run" });
// --allow-readの付与を要求する
await Deno.permissions.request({ name: "read", path: "." })
シグナルAPI
v1.16で新しいシグナルAPIが実装されました
const signalListener = () => {
// ...
};
Deno.addSignalListener("SIGTERM", signalListener);
Deno.removeSignalListener("SIGTERM", signalListener);
元々、Deno.signal()
という異なるAPIが存在していたのですが、誤った使い方をされてしまいがちであることなどから、新しいAPIが導入されました。
この変更に合わせて、既存のDeno.signal()
は削除されています。
--prompt
オプション
--prompt
オプションはDeno v1.9で実装された機能です。
デフォルトでは許可されていない処理を実行しようとすると、Denoはプロセスを停止させます。
例えば、--allow-read
が与えられていない状況で下記コードを実行すると、エラーが発生します。
console.log(Deno.cwd());
--prompt
オプションを与えてDenoを実行すると、権限が与えられていない処理に遭遇した際に、Denoはプロンプトを表示して必要な権限の許可をユーザに対して求めます。
もしユーザが権限の付与を許可した場合、Denoは自身に対象の権限を付与した上で処理を続行します。
これにより、例えばスクリプトなどの実行時に段階的に権限を与えることができるようになりました。
プライベートモジュールのサポート
プライベートなモジュールのダウンロードなどをサポートするために、DENO_AUTH_TOKENS
という環境変数が導入されました。
この環境変数に{token}@{hostname[:port]}
形式でトークンを指定することで、該当のホストからモジュールをダウンロードする際に、Authorization
ヘッダに指定されたBearerトークンが自動で設定されます。
トークンはセミコロン区切りで複数指定することができます。
また、Basic認証もサポートされています。
$ DENO_AUTH_TOKENS=user:password@127.0.0.1:3000 deno run mod.ts
プラグインシステムの廃止
元々、Denoにはプラグインシステムが存在しました。
これはユーザがRustを使用してDenoを拡張する仕組みで、Deno.openPlugin
というAPIを使うことで、任意のプラグインを読み込むことができました。
Deno v1.13でDeno.openPlugin
が廃止され、代わりにFFIが導入されました。
const dylib = Deno.dlopen("./add.so", {
add: {
parameters: ["i32", "i32"],
result: "i32",
},
});
console.assert(dylib.symbols.add(1, 2) === 3);
Deno.dlopen
はまだ安定化されておらず、利用には--unstable
が必要です。
パフォーマンス向上
Deno v1.9でserde_v8というRustクレートが導入されました。
これにより、Deno内部でのop呼びだしのオーバーヘッドが大幅に削減されました。
その他にも、様々なAPIでパフォーマンス向上が図られています(大きなものとしては、URL
のパフォーマンスが3倍にまで向上しています)
Web標準との互換性について
DenoにはWPTという、各種ブラウザなどでWeb標準への準拠度を確認するためのテストスイートが導入されています。
これにより全体的にWeb標準との互換性が向上しています。
また、MDN Web Docsの「ブラウザーの互換性」欄にDenoの情報が掲載されるようになりました。
また、下記のように様々なAPIが実装されています。
globalThis.location
globalThis.location
が実装されました。
Denoを起動する際に--location
オプションで指定されたオリジンが設定されます。
また、これの実装合わせて、fetch()
で相対URLの指定がサポートされました。
Worker
大きな変更点として、Worker
を生成する際にパーミッションを指定できるようになりました。
const worker = new Worker(new URL("./worker.ts", import.meta.url).href, {
type: "module",
deno: {
namespace: true,
permissions: {
read: ["."],
write: false,
},
},
});
また、Worker
に関連して下記のAPIも実装されました。
fetch()
URIスキームとして、下記がサポートされました。
blob:
data:
file:
このうち、file:
はDeno独自の拡張で、利用する際は--allow-read
が必要です。
const res = await fetch("file:///home/uki00a/.vimrc");
console.log(await res.text());
また、ReadableStream
を利用したリクエストボディのストリーミングや、AbortController
によるリクエストのキャンセルなどもサポートされています。
Web Storage API
DenoでlocalStorage
やsessionStorage
などが実装されました。
WebSocketStream
まだ利用には--unstable
が必要ですが、WebSocketStreamが実装されました。
const stream = new WebSocketStream("ws://localhost:3000");
const { readable, writable } = await stream.connection;
const writer = writable.getWriter();
await writer.write("Hello world!");
setTimeout(() => stream.close(), 5000);
for await (const message of readable) {
console.log(message);
}
URLPattern
URLPatternが実装されました。
簡易的なAPIサーバなどを実装する際に便利かもしれません。
const pattern = new URLPattern({ pathname: "/users/:id" });
pattern.exec("https://example.com/users/1").pathname.groups; // {id: '1'}
WebGPU API
まだunstableですがWebGPU APIが実装されました。
下記リポジトリに実際の利用例などについて掲載されています。
コンパイラAPI
元々、DenoからTypeScriptコンパイラを利用するために、Deno.transpileOnly
, Deno.bundle
, 及びDeno.compile
の3種類のAPIが提供されていました。
これらのAPIがDeno.emit
という単一のAPIに統合されました。
const result = await Deno.emit("/mod.ts", {
bundle: "module",
sources: {
"/mod.ts": `import { add } from "./add.ts";
console.log(add(1, 2));`,
"/add.ts": `export const add = (a: number, b: number) => a + b;`,
},
});
非推奨化されたAPI
Deno名前空間に実装されていた以下のAPIが非推奨化されています。
Deno.Buffer
Deno.readAll
Deno.readAllSync
Deno.writeAll
Deno.writeAllSync
Deno.iter
Deno.iterSync
Deno.copy
これらのAPIはdeno_std/io/utilなどに移動しているため、今後はそちらに移行するとよいでしょう。
deno test
の変更点
deno test
はDenoに搭載されたテストランナです。
--job
によるテストケースの並行実行
Deno v1.10で--job
オプションがサポートされ、テストケースの並行実行がサポートされました。
$ deno test --jobs 2
--doc
によるJSDocコメントやMarkdownファイル内のコードブロックの型チェックがサポート
--doc
オプションによるJSDocコメント(v1.10)やMarkdownファイル(v1.13)内のコードブロックの型チェックがサポートされました。
$ deno test --doc --no-run --import-map=import_map.test.json
簡単な例として、以下のようなファイルがあったとします。
/**
* ```ts
* import { add } from "./add.ts";
* add(1, "2"); // NG
* ```
*/
export function add(a: number, b: number): number {
return a + b;
}
このファイルに対してdeno test --doc
を実行すると、JSDocコメント内のコードで関数に与える引数の型が間違っているため、型エラーが報告されます。
$ deno test --doc add.ts
--shuffle
によるテストケースの実行順序のランダム化
Deno v1.12でサポートされました。
これによりテストケースの実行順序をランダムにできるため、不安定なテストケースが生まれることの防止につながるかもしれません。
$ deno test --shuffle -A
テストケースごとのパーミッションの制御
Deno.test
でテストケースごとに細かくパーミッションを制御できるようになりました。
Deno v1.10で追加され、Deno v1.16で安定化されました。
Deno.test({
name: "This should fail",
permissions: {
net: false, // --allow-netを無効化
},
fn: async () => {
const _ = await fetch("https://example.com"); // --allow-netが無効化されているため、失敗します
},
});
サブテストAPI
Deno v1.15で追加された機能で、テストケースのグループ化ができます。
まだ--unstable
が必要ですが、おそらく来年にリリースされるであろうv1.18にて安定化される予定です。
Deno.test("nested test case", async (t) => {
const success = await t.step("step 1", async (t) => {
const success = await t.step("step 1-1", () => {
throw new Error("Failed!");
});
if (!success) throw new Error("Failed!");
await t.step("step 1-2", () => {});
});
if (success) throw new Error("Failed!");
});
--watch
オプションのサポート
Deno v1.10でdeno test
で--watch
オプションがサポートされました。
これにより、ファイルを変更するたびにテストを自動で再実行することができます。
$ deno test --watch -A
テストカバレッジ機能の強化
元々、Denoでのカバレッジの収集とレポートの生成はdeno test --coverage
という単一のコマンドで実現されていました。
Deno v1.8で使い方が以下のように変更されました。
- カバレッジを収集する際は
deno test --coverage
を使う - レポートを生成する際は、
deno coverage
を使う
さらに、deno coverage
に--lcov
オプションを指定することで、lcov形式のレポートが生成できるようになりました。
deno fmt
の変更点
deno fmt
はDenoに組み込まれたコードフォーマッタです。
Markdownサポート
Deno v1.7でMarkdownファイルのフォーマットがサポートされました。
$ deno fmt README.md
--ext
のサポート
Deno v1.7のMarkdownサポートに合わせて追加されました。
deno fmt -
で標準入力経由でフォーマット対象のコードを渡す際に指定することが想定されています。
$ cat mod.js | deno fmt --ext=js -
$ cat README.md | deno fmt --ext=md -
JSONサポート
Deno v1.8でJSONファイルのフォーマットがサポートされました。
$ deno fmt modules-lock.json
設定ファイルによる挙動のカスタマイズ (v1.14)
Deno v1.14で設定ファイル(--config
)によってdeno fmt
の挙動をカスタマイズできるようになりました。
インデント幅やタブの使用有無などを設定できます。
$ deno fmt --config deno.jsonc
詳しい設定内容については、下記の記事で詳しくまとまっているためそちらを参照ください。
deno lint
の変更点
deno lint
はDeno本体に組み込まれたリンタです。
まず大きな変更点として--unstable
オプションが不要になりました。 (v1.10)
また、deno fmt
同様に設定ファイルによる挙動のカスタマイズがサポートされています。 (v1.14)
$ deno fmt --config deno.jsonc
詳しい設定内容については下記の記事を参照ください。
また、--watch
オプションのサポートも追加されており、ファイルの変更時にリンタを自動で再実行することができます。(v1.15)
deno compile
の変更点
deno compile
はJavaScriptやTypeScriptコードをバンドルし、スタンドアロンな実行可能ファイルを生成するコマンドです。
安定化
Deno v1.10でdeno compile
コマンドが安定化されました。
そのため、今後はdeno compile
を--unstable
オプションを指定せずに利用できます。
--target
オプションによるクロスコンパイル
Deno v1.7で--target
オプションによるクロスコンパイルがサポートされました。
例えば、LinuxやMacなどのOS上でWindows向けのバイナリを生成できます。
$ deno compile --target x86_64-pc-windows-msvc main.ts
パーミッションなどのサポート
Deno v1.7でパーミッション(--allow-read
や--allow-net
など)や証明書(--cert
)などをバイナリに組み込めるようになりました。
$ deno compile --allow-read main.ts
deno lsp
の変更点
deno lsp
コマンドはDenoの本体に組み込まれたLanguage Serverです。
大きな変更点としてDeno v1.7.5で安定化が行われました。
そのため、今後は--unstable
オプションの指定は不要です。
その他にも下記の機能などが追加されています。
- import節の入力補完がサポート
- Test code lens (エディタやIDEから直接特定のテストケースを実行できる)
- Refactoring code actions (コードの関数抽出などができる)
deno repl
の変更点
deno repl
コマンドを実行すると、REPLを起動できます。
REPLに対する大きな変更点として、TypeScriptコードの実行やNode.js互換モード(--compat
)がサポートされています。(ただし、入力されたTypeScriptコードの型チェックはサポートされていません)
その他にもimport
やexport
の評価などもサポートされ、コードを貼り付けて利用する際の利便性が向上しています。
deno uninstall
コマンド
Deno v1.15で実装された新しいコマンドです。
deno install
によってインストールされたコマンドをアンインストールできます
$ deno uninstall udd
deno_stdの変更点
deno_std/http
Deno v1.9でネイティブHTTPサーバ(Deno.serveHttp
)が実装されたのに合わせて、http/server.tsもそれをベースに再実装されました。
import { serve } from "https://deno.land/std@0.118.0/http/server.ts";
await serve((request) => {
return new Response("Hello", { status: 200 });
}, { port: 8000 });
この変更に合わせて、既存のTypeScriptベースのHTTPサーバはhttp/server_legacy.tsに移動していましたが、deno_std v0.118.0で削除されました。
deno_std/ws
deno_std/ws
はTypeScriptベースのWebSocketサーバの実装を提供するモジュールです。
Deno本体でDeno.upgradeWebSocket
が実装されたため、deno_std v0.118.0で削除されました。
deno_std/collections
deno_std v0.103.0で追加された新しいモジュールです。
コレクション操作に関する様々な関数が提供されています。
Kotlinの標準ライブラリに影響を受けているようです。
import { groupBy } from "https://deno.land/std@0.117.0/collections/group_by.ts";
const users = [{ name: "foo", group: "admin" }, { name: "bar", group: "normal" }];
const usersByGroup = groupBy(users, (it) => it.group);
console.log(usersByGroup["admin"]);
deno_std/crypto
deno_std v0.104.0で追加された新しいモジュールです。
背景
元々、deno_std/hash
というモジュールがありました。
このdeno_std/hash
のAPIはNode.jsのcryptoモジュールに影響を受けていると思われます。
しかし、Deno本体でWeb Crypto APIの実装が進んできたこともあり、それをベースにしてdeno_std/crypto
が追加されました。
deno_std/crypto
はWeb Crypto APIをベースにしつつ、Web Crypto APIでは提供されていないアルゴリズムなどを提供することを目的としています。
deno_std/encoding/toml
deno_std/encoding/toml
はDenoで実装されたTOMLパーサです。
大きな変更として、内部のパーサが1から書き直され、TOML仕様への準拠度が向上しています。
Deno Deploy
Deno公式によりDeno Deployが公開されました。
Cloduflare Workersなどのように、CDNのエッジ上でTypeScriptやJavaScriptなどを実行することができます。
これに合わせて、FreshやSiftなどのDeno Deployで動作するフレームワークが公開されました。
また、OakなどのフレームワークでもDeno Deployのサポートが追加されています。
Denoが法人化
Deno Deployの発表に合わせてDenoの法人化が発表されました。
Deno本体やDeno Deployの開発などを中心に活動しています。
その他にも、TC39へのジョインなど様々な活動が行われています。
Deno公式のDockerイメージ
元々、DenoにはAndy Hayden氏を中心にメンテナンスされていたDockerイメージがありました。
このDockerイメージがDeno公式でメンテナンスされるようになりました。
Slackの新プラットフォーム
Slackの次世代開発プラットフォームが発表されました。
このプラットフォームでは、CLIやSDKなどでDenoが採用されています。
dnt
Denoで書いたモジュールをNode.jsから利用できるようにするツールが公開されました
12月03日のkt3kさんの記事で解説されているため、詳しくはそちらを参照ください
lint.deno.landがDeno Deployに移行
deno lintの公式サイトであるlint.deno.landがDeno Deployへ移行されました。
それに合わせて、内部実装もdext.ts+Tailwind CSSからFresh+Twindへ移行されています。
doc.deno.landがリニューアル
DenoのAPIドキュメンテーションサイトであるdoc.deno.landがリニューアルされました。
合わせて、内部実装もVercel+Next.jsからDeno Deploy+Oak+NanoJSX+Twindに移行されています。
SkypackのDenoサポートが強化
Skypackはnpmパッケージを配信するCDNです。
このSkypackでDenoのサポートの強化が行われています。
具体的には、Node.jsの組み込みモジュールの読み込みをdeno_std/nodeへの読み込みに自動で置き換えてくれる機能が追加されています。
これにより、Node.jsの組み込みモジュールに依存したnpmパッケージがDenoから使いやすくなりました
他にも、SkypackはURLにクエリパラメータとしてdts
を指定することでレスポンスにX-TypeScript-Types
ヘッダを付与してくれるため、Denoとの相性がよいです。
https://cdn.skypack.dev/react@17.0.1?dts
Flat Data
Flat Dataという、HTTPエンドポイントまたはSQLクエリからデータを取得し、GitHubリポジトリに格納するためのGitHubアクションが公開されました。(GitHub製)
Denoを使用したJavaScript/TypeScriptファイルの実行がサポートされており、ダウンロードされたデータを変換することができます。
また、GitHubリポジトリに格納されたデータを可視化するために、Flat Viewerというツールも提供されています。
denodrivers
Denoでは様々なデータベースクライアントライブラリが開発されています。
元々、これらのライブラリは有志によって開発されていました。
これらのライブラリを一箇所で開発・管理することを目的として、denodriversというOrganizationができました。
Discordチャンネルもあるため、開発の動向などについては、こちらを見てみるとよいかもしれません。
おわりに
今年一年でDenoには様々な機能の追加やできごとなどがありました。
特にDeno Deployの発表やSlackでのDenoの採用などは、今後のDenoの使用率などにも影響してくるのではないかと感じています。
Denoの今後の動きについては、JSConf JPのkt3kさんの発表で解説されているため、興味のある方は見てみてはいかがでしょうか。
参考
- https://deno.com/blog/v1.7
- https://deno.com/blog/v1.8
- https://deno.com/blog/v1.9
- https://deno.com/blog/v1.10
- https://deno.com/blog/v1.11
- https://deno.com/blog/v1.12
- https://deno.com/blog/v1.13
- https://deno.com/blog/v1.14
- https://deno.com/blog/v1.15
- https://deno.com/blog/v1.16
- https://deno.com/blog/v1.17
- https://deno.com/blog/deno-on-mdn.html
- https://deno.com/blog/the-deno-company/
Discussion