Deno標準モジュールを、前編と後編の2回に分けて解説します。本記事は後編です
モジュール解説
前編に続き、以下ではDeno標準モジュールの中の各モジュールについて解説していきます。
11. FS
FSではファイル操作用のユーティリティが実装されています。具体的には以下のような機能が提供されています。
- copy:ファイルもしくはディレクトリをコピーする
- detect:ファイルの内容を受け取ってファイルの改行形式を判定する
- emptyDir:ディレクトリを空にする
(ディレクトリ自体は消されない) - ensureDir:ディレクトリがなければ作成する
- ensureFile:ファイルがなければ作成する
- ensureLink:ハードリンクがなければ作成する
- ensureSymlink:シンボリックリンクがなければ作成する
- format:ファイルの改行形式を整形する
- expandGlob:グロブを展開する
- expandGlobSync:グロブを同期的に展開する
- move:ファイルもしくはディレクトリを移動する
- moveSync:ファイルもしくはディレクトリを同期的に移動する
- walk:ディレクトリのすべてのエントリーを返すAsyncIterableを返す
- walkSync:ディレクトリのすべてのエントリーを返すIterableを返す
ここでは例として、ensureDir
とwalk
の使い方を見てみましょう。
import { ensureDir } from "https://deno.land/[email protected]/fs/mod.ts";
await ensureDir("./bar"); // ディレクトリがなければ作成する、すでにある場合は何もしない
import { walk } from "https://deno.land/[email protected]/fs/walk.ts";
import { assert } from "https://deno.land/[email protected]/testing/asserts.ts";
// カレントディレクトリ以下のすべてのファイル・ディレクトリについて繰り返し処理する
for await (const entry of walk(".")) {
console.log(entry.path);
assert(entry.isFile);
}
exists
とexistsSync
について
FSモジュールにはexists
とexistsSync
という現在は非推奨化された2つのユーティリティが存在します。これらの関数は、あるファイルまたはディレクトリが存在するかどうかを判定します。
この機能は一見問題なさそうに見えますが、TOCTOU
if (existsSync("data.txt")) {
// ファイルがあると前提してdata.txtを読む
const text = await Deno.readTextFile("data.txt");
}
上記のコードは一見問題なさそうですが、実は問題があります。existsSync("data.
のチェックがtrueになったとしても、Deno.
の実行時にファイルが存在するとは限らないからです。existsSyncの呼び出しと、Deno.
try {
const text = await Deno.readTextFile("data.txt");
} catch (e) {
if (e instanceof Deno.errors.NotFound) {
// ファイルが無かった場合の処理
}
}
12. HTTP
HTTPでは、HTTPのサーバー・serve
APIです。serve
は以下のように使って、HTTPサーバを起動できます。
import { serve } from "https://deno.land/[email protected]/http/server.ts";
serve((_req) => new Response("Hello, world"));
serve
はいろいろなオプションを持っています。例えばportを変更したい場合はportオプションを指定します。
import { serve } from "https://deno.land/[email protected]/http/server.ts";
serve((_req) => new Response("Hello, world"), { port: 3000 });
HTTPでもう一つ重要な機能はfile_
$ deno run --allow-read --allow-net https://deno.land/[email protected]/http/file_server.ts Listening on http://localhost:4507/
以上の他に、以下のようなユーティリティが実装されています。
- CookieMap:クッキーをMap的なインタフェースで扱うためのクラス
- SecureCookieMap:署名付きクッキーをMap的なインターフェスで扱うためのクラス。署名の生成・
検証が自動的に行われる - HttpError:HTTPのエラーステータスを表現するクラス
- accepts:RequestオブジェクトからAcceptヘッダーを読み出して、受け付けているメディアタイプを優先度順に並べた配列を返す
- acceptsEncodings:RequestオブジェクトからAccept-Encodingヘッダーを読み出して、受け付けているエンコーディングを優先度順に並べた配列を返す
- acceptsLanguages:RequestオブジェクトからAccept-Languageヘッダーを読み出して、受け付けている表示言語を優先度順に並べた配列を返す
- deleteCookie:Headersオブジェクトに与えられたキーのcookieを消すためのSet-Cookieヘッダーを書き込む
- getCookie:Headersオブジェクトからクライアントから送られてきたクッキーをオブジェクト形式で抜き出して返す
- getSetCookie:Headersオブジェクトからサーバーから送られてきたクッキーを抜き出してCookie型の配列として返す
- isClientErrorStatus:与えられたステータスコードがクライアント由来エラー
(4XX系) であるか判定する - isErrorStatus:与えられたステータスコードがエラー
(4XXまたは5XX) であるか判定する - isInformationalStatus:与えられたステータスコードがインフォメーショナル
(1XX系) であるか判定する - isRedirectStatus:与えられたステータスコードがリダイレクト
(3XX系) であるか判定する - isServerErrorStatus:与えられたステータスコードがサーバー由来エラー
(5XX系) であるか判定する - mergeHeaders:複数のHeadersオブジェクトをマージする
- serveListener:与えられたDeno.
Listenerオブジェクトを使ってHTTPサーバーを起動する - serveTls:TLS上のHTTP
(https://) サーバーを起動する - setCookie:Headersにクライアント向きのクッキーをセットする
HTTPモジュールでは、あえてWebフレームワーク的な機能は取り込まないという方針があります。そのため、上記のユーティリティ群は、特定のWebプログラミングパターンを支援するものというよりは、どのフレームワークでも内部的に利用可能な、プリミティブなものに限定して提供されています。
より効率的にWebサーバーを記述したい場合は、より本格的な3rdパーティ製のフレームワークを参照することをお勧めします。Denoでよく使われる3rdパーティ製のWebフレームワークには以下のようなものが有名です。
OakとHonoはいわゆるexpress的なレイヤーを担うフレームワークです。REST APIサーバーを作りたい場合や、従来型のテンプレートエンジン
FreshやAlephはいわゆるNext.
13. Log
Logではログ出力関連のユーティリティが実装されています。現状以下の5レベルのロギングをサポートしてます。
- debug:デバッグレベル
- info:参考レベル
- warning:警告レベル
- error:エラーレベル
- critical:致命的レベル
以下のように使用します。
import * as log from "https://deno.land/[email protected]/log/mod.ts";
log.debug("デバッグ");
log.info("参考");
log.warning("警告");
log.error("エラー");
log.critical("致命的エラー");
logの向き先をファイルとコンソール両方にしたい場合は以下のようにして、File handlerを追加することで実現できます。
import * as log from "https://deno.land/[email protected]/log/mod.ts";
await log.setup({
handlers: {
console: new log.handlers.ConsoleHandler("DEBUG"),
file: new log.handlers.FileHandler("WARNING", { filename: "./log.txt" }),
},
loggers: {
default: {
level: "DEBUG",
handlers: ["console", "file"],
},
},
});
log.debug("デバッグ");
log.info("参考");
log.warning("警告");
log.error("エラー");
log.critical("致命的エラー");
// WARNING以上のエラーは、ターミナルとファイルの両方に書き出されます。
より詳細な使い方については公式ドキュメントを参考にしてください。
14. Media Types
Media Typesでは、メディアタイプ
- contentType:メディアタイプ文字列、もしくはファイル拡張子を引数にとって対応するメディアタイプ文字列を返す
- extension:メディアタイプ文字列を受け取って、そのメディアタイプのファイルの最も代表的な拡張子を返す
- extensionsByType:メディアタイプ文字列を受け取って、そのメディアタイプのファイルの代表的な拡張子すべての配列を返す
- formatMediaType:メディアタイプ文字列を整形する
- getCharset:メディアタイプ文字列から適切な文字セットを返す
- parseMediaType:メディアタイプ文字列をパースする
- typeByExtension:ファイル拡張子を受け取って対応するメディアタイプを返す
例として、contentType
関数の使い方を紹介します。
import { contentType } from "https://deno.land/[email protected]/media_types/content_type.ts";
contentType(".json"); // `application/json; charset=UTF-8`
contentType("text/html"); // `text/html; charset=UTF-8`
contentType("text/html; charset=UTF-8"); // `text/html; charset=UTF-8`
contentType("txt"); // `text/plain; charset=UTF-8`
contentType("foo"); // undefined
contentType("file.json"); // undefined
15. Node
NodeモジュールではNode.
この標準モジュールのNode以下のAPIはnpm:
でnpmモジュールをインポートした際のNodeのAPIのshimとしても動いており、このモジュールの開発が進むことでnpm:
でインストールするnpmモジュールの互換性が上がっていくという関係性になっています。
例として、Node.
import * as http from "https://deno.land/[email protected]/node/http.ts";
const server = http.createServer((req, res) => {
res.write("Hello");
res.end();
});
server.listen(async () => {
const resp = await fetch(`http://localhost:${server.address().port}`);
console.log(await resp.text()); // => Hello
server.close();
});
詳細は公式ドキュメントを参照してください。
16. Path
Pathではファイルパス操作関連の各種ヘルパーが実装されています。具体的には以下のような機能が提供されています。
- basename:ファイルパスのファイル名部分を取り出す
- dirname:ファイルパスのディレクトリ名部分を取り出す
- extname:ファイルパスの拡張子部分を取り出す
- format:パースされたパスオブジェクトをパス文字列にする
- fromFileUrl ファイルを表すURLオブジェクト
file:///で始まるもの
をパス文字列に変換する - isAbsolute:ファイルパスが絶対パスかどうか判定する
- join:パスを結合する
- normalize:ファイルパスを正規化する
(重複したパス区切り文字の削除など) - parse:ファイルパスをパースしてパスオブジェクトにする
- posix:POSIX準拠のパス操作機能を提供する名前空間
(WindowsでPOSIXのパス操作をしたい場合に使う) - relative:与えらたファイルパスから、別の与えられたファイルパスを参照する相対パス表記を返す
- resolve:与えらた複数のファイルパスを合成した絶対パスを返す
- toFileUrl:ファイルパスをファイルURLに変換する
- toNamespacedPath:Windows上で与えらたファイルパスを名前空間付きパスに変換する
- win32:Windows用のパス操作機能を提供する名前空間
(Linux/ MacでWindows用のパス操作をしたい場合に使う)
ここでは例として、basename
、dirname
、join
の使い方を見てみましょう。
import {
basename,
dirname,
join,
} from "https://deno.land/[email protected]/path/mod.ts";
basename("/path/to/my-file.txt"); // => my-file.txt
dirname("/path/to/my-file.txt"); // => /path/to
join("foo", "bar", "baz"); // => foo/bar/baz or foo\bar\baz
PathモジュールはNode.
17. Permissions
PermissionsではDenoのPermission機能を使うためのヘルパーが提供されています。以下のAPIが提供されています。
- grant:複数のパーミッションを一気に要求する
- grantOrThrow:複数のパーミッションを一気に要求し、それらが満たされない場合は例外を投げる
例としてgrantOrThrowの使い方を見てみましょう。
import { grantOrThrow } from "https://deno.land/[email protected]/permissions/mod.ts";
await grantOrThrow({ name: "env" }, { name: "net" });
// 後続処理ではenvとnetパーミッションがあることを想定できる
このように、Denoはデフォルトではプログラムの途中で必要なパーミッションをその都度ユーザーに聞くように挙動しますが、上記のように書くことで、プログラムの開始時にまとめてパーミッションを要求できます。
18. Semver
SemverではSemantic Versioning
- compare:2つのバージョンを比較した結果を返す
- compareBuild:2つのバージョンをビルド番号まで比較した結果を返す
- difference:2つのバージョンの差を表すリリースタイプ
("major"、"minor"等) を返す - eq:2つのバージョンが等しい時にtrueを返す
- gt:2つのバージョンの左が大きい時にtrueを返す
- gte:2つのバージョンの左が大きいか等しい時にtrueを返す
- gtr:バージョンが、バージョンレンジよりも大きい時にtrueを返す
- increment:バージョンをリリースタイプ
("major"、"minor"等) でインクリメント (プラス1) する - intersect:2つのバージョンレンジに交わりがあるかどうかを判定する
- lt:2つのバージョンの左が小さい場合にtrueを返す
- lte:2つのバージョンの左が小さいか等しい場合にtrueを返す
- ltr:バージョンがバージョンレンジより小さい場合にtrueを返す
- major:バージョンのメジャーバージョン部分を返す
- maxSatisfying:バージョンの配列とバージョンレンジを受け取って配列の中からバージョンレンジを満たすもののうち最大のものを返す
- minor:バージョンのマイナーバージョン部分を返す
- minSatisfying:バージョンの配列とバージョンレンジを受け取って配列の中からバージョンレンジを満たすもののうち最小のものを返す
- minVersion:バージョンレンジの中の最小バージョンを返す
- neq:2つのバージョンが等しくない時にtrueを返す
- outside:バージョンがバージョンレンジに含まれない時にtrueを返す
- parse:バージョン文字列を受け取ってパージョンオブジェクトを返す
- patch:バージョンのパッチバージョン部分を返す
- prerelease:バージョンのプレリリース部分
(番号の後ろのalpha. 1やbeta. 2などの部分) を返す - rcompare:2つのバージョンを比較した結果を返す
(compareの逆) - rsort:バージョンの配列をソートする
(ソート順はsortの逆) - satisfies:バージョンがバージョンレンジの中に含まれる時にtrueを返す
- sort:バージョンの配列をソートする
- valid:バージョン文字列がSemverのルールに沿っているかどうかを判定する
- validRange:バージョン文字列が
(npm互換の) バージョンレンジのルールに沿っているかを判定する
例として、compare
とsatisfies
を使う例を見てみましょう。
import { compare } from "https://deno.land/[email protected]/semver/mod.ts";
compare("1.2.3", "1.1.5"); // => 1
compare("1.2.3", "1.3.0"); // => -1
compare("1.2.3-alpha", "1.2.3-beta"); // => -1
compare("1.2.3", "1.2.3"); // => 0
import { satisfies } from "https://deno.land/[email protected]/semver/mod.ts";
satisfies("1.3.0", ">=1.2.3"); // => true
satisfies("1.3.0", "~1.2.3"); // => false
satisfies("1.2.5", "~1.2.3"); // => true
satisfies("1.3.0", "^1.2.3"); // => true
Semverモジュールはnpmモジュールのsemver
を元にデザインされています。したがってバージョンレンジ表現などの非標準部分も含めて同npmモジュールに準拠したデザインになっています
19. Signal
Signalでは、OS Signalのハンドリングについてのヘルパーが実装されています。現在は複数のsignalをまとめてAsyncIterable化出来るsignal
ヘルパーだけが実装されています。
import { signal } from "https://deno.land/[email protected]/signal/mod.ts";
setTimeout(() => {}, Infinity);
const sig = signal("SIGKILL", "SIGINT");
for await (const _ of sig) {
// SIGKILLかSIGINTを受け取るとここが走る
if (...) {
// シグナル監視を止めたい場合はdispose(リソースを開放)する
sig.dispose();
}
}
Deno本体にはDeno.
というイベントハンドラー型のAPIが実装されています。AsyncIterable型の記法でシグナル監視を記述したい場合はこちらのヘルパーを使ってみましょう。
20. Streams
StreamsではWeb Stream API関連のヘルパーが実装されています。I/
- ByteSliceStream:バイトストリーム
( ReadableStream<Uint8Array>
)から指定の開始位置から終了位置までを切り取るTransformStream - DelimiterStream:バイトストリーム
( ReadableStream<Uint8Array>
)を指定の区切り文字で区切ったチャンクに切り分けるTransformStream - LimitedBytesTransformStream:バイトストリーム
( ReadableStream<Uint8Array>
)から指定の先頭バイトを切り取るTransformStream - LimitedTransformStream:任意型のストリームから指定の先頭チャンク数を抜き出すTransformStream
- TextDelimiterStream:テキストのストリーム
( ReadableStream<string>
)を指定の区切り文字で区切ったチャンクに切り分けるTransformStream - TextLineStream:テキストのストリームを改行文字で区切ったチャンクに切り分けるストリーム
- earlyZipReadableStream:複数のReadableStreamを入力として受け取り、各ストリームから1チャンクづつ取り出したストリームを作る。1つの入力データが終わったタイミングで全体の読み取りを終了する
- mergeReadableStream:複数のReadableStreamの入力をマージする。チャンクの順番は考慮されない。すべての入力データが終わるまで読み取りを続ける
- readableStreamFromIterable:IterableもしくはAsyncIterableを受け取って、その出力をチャンクとするようなReadableStreamを返す
- readableStreamFromReader:Readerインターフェース
(Go言語由来の旧I/ Oインターフェス) を受け取って、ReadableStreamに変換する - toTransformStream:ReadableStreamを引数として受け取るようなGenerator関数をTransformStreamに変換する
- writableStreamFromWriter:Writerインターフェース
(Go言語由来の旧I/ Oインターフェス) を受け取って、WritableStreamに変換する - zipReadableStream:複数のReadableStreamを入力として受け取り、各ストリームから1チャンクづつ取り出したストリームを作る。すべての入力データの読み取りが終了するまでデータを読み続ける
ここでは例として、ByteSliceStream
とtoTransformStream
の使い方を紹介します。
import { ByteSliceStream } from "https://deno.land/[email protected]/streams/byte_slice_stream.ts";
const response = await fetch("https://example.com");
const rangedStream = response.body!
.pipeThrough(new ByteSliceStream(1000, 5000));
// rangedStreamは1001バイト目移行5000バイト目までのストリームになる
import { toTransformStream } from "https://deno.land/[email protected]/streams/to_transform_stream.ts";
const readable = new ReadableStream({
start(controller) {
controller.enqueue(0);
controller.enqueue(1);
controller.enqueue(2);
controller.close();
},
})
.pipeThrough(toTransformStream(async function* (src) {
for await (const chunk of src) {
yield chunk * 100;
}
}));
for await (const chunk of readable) {
console.log(chunk);
}
// output: 0, 100, 200
toTransformStream
を使うと、Generator関数を使ってTransformStreamを自然に書くことができます。Node.
21. Testing
Testingではアサーション関数を始めとする、テストを書く際に便利な各種ヘルパー機能が提供されています。
アサーション系は以下が提供されています。
- assert:対象がtrue
(より正確にはtruthy) であることをアサートする - assertAlmostEquals:2つの数が一定の誤差を許して、ほぼ等しいことをアサートする
- assertArrayIncludes:配列が要素を含むことをアサートする
- assertEquals:2つの値が等しいことをアサートする
(deep equalアルゴリズムで判定) - assertExists:値がnullish
(nullかundefined) ではないことをアサートする - assertFalse:値がfalse
(より正確にはfalsy) であることをアサートする - assertInstanceOf:値があるクラスのインスタンスであることをアサートする
- assertIsError:値がErrorオブジェクトであることをアサートする
- assertMatch:文字列が正規表現にマッチすることをアサートする
- assertNotEquals:2つの値が等しくないことをアサートする
(deep equalアルゴリズムで判定) - assertNotInstanceOf:値があるクラスのインスタンスでないことをアサートする
- assertNotMatch:文字列が正規表現にマッチしないことをアサートする
- assertNotStrictEquals:2つの値が厳密比較で一致しないことをアサートする
- assertObjectMatch:値が別のオブジェクトの部分になっていることをアサートする
(部分であることの判定はオブジェクト構造に対して再帰的に判定される) - assertRejects:非同期関数がリジェクトされることをアサートする
(リジェクトされた値はassertRejectsの返り値になる) - assertStrictEquals:2つの値が厳密に等しいことをアサートする
- assertStringIncludes:文字列が別の文字列に含まれることをアサートする
- assertThrows:関数が例外を投げることをアサートする
(投げられた例外はassertThrowsの返り値になる) - equal:2つの値の比較結果を真偽値で返す
- fail:テストを失敗させる
例としてassertEquals
、assertThrows
を使う例を紹介します。
import {
assertEquals,
assertThrows,
} from "https://deno.land/[email protected]/testing/asserts.ts";
Deno.test("値の等しさをチェックする", () => {
assertEquals("world", "world");
assertEquals({ hello: "world" }, { hello: "world" });
});
Deno.test("URL のパースエラーをチェックする", () => {
assertThrows(() => {
new URL("invalid url");
});
});
BDDスタイルテスト
TestingモジュールではJestやMochaなどのBDD
import {
assertEquals,
assertThrows,
} from "https://deno.land/[email protected]/testing/asserts.ts";
import { describe, it } from "https://deno.land/[email protected]/testing/bdd.ts";
import { User } from "https://deno.land/[email protected]/testing/bdd_examples/user.ts";
describe("User", () => {
it("users initially empty", () => {
assertEquals(User.users.size, 0);
});
it("constructor", () => {
const user = new User("Alice");
assertEquals(user.name, "Alice");
});
describe("age", () => {
it("getAge", function () {
const user = new User("Bob");
assertThrows(() => user.getAge(), Error, "Age unknown");
user.age = 18;
assertEquals(user.getAge(), 18);
});
it("setAge", function () {
const user = new User("Charlie");
user.setAge(18);
assertEquals(user.getAge(), 18);
});
});
});
このファイルをtest.
などの名前で保存して、deno test
コマンドで実行できます。
$ deno test test.ts Check file:///path/to/test.ts running 1 test from ./test.ts User ... users initially empty ... ok (6ms) constructor ... ok (5ms) age ... getAge ... ok (4ms) setAge ... ok (5ms) age ... ok (16ms) User ... ok (37ms) ok | 1 passed (5 steps) | 0 failed (73ms)
it
で指定した仕様が、テストケースとして認識されていることが確認できます。他にafterEach
、beforeEach
などの各種フック関数なども提供されています。MochaやJestに親しみのあるユーザは、デフォルトのDeno.
よりもこちらのほうが手に馴染むかもしれません。
モック
Testingモジュールではモックテストを支援するためのユーティリティ群も提供されています。モックテストの例として、spy
とstub
を使う例を紹介します。
spy
を使う例は以下のようになります。
import {
assertSpyCall,
assertSpyCalls,
spy,
} from "https://deno.land/[email protected]/testing/mock.ts";
import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts";
Deno.test("how spy works", () => {
const func = spy();
// スパイが呼ばれていないことの確認
assertSpyCalls(func, 0);
assertEquals(func(), undefined);
// スパイが空の引数リストで呼ばれた事の確認
assertSpyCall(func, 0, { args: [] });
assertSpyCalls(func, 1);
assertEquals(func("x"), undefined);
// スパイが"x"という引数で呼ばれたことの確認
assertSpyCall(func, 1, { args: ["x"] });
assertSpyCalls(func, 2);
});
また、stub
を使う例は以下のようになります。
import {
returnsNext,
stub,
} from "https://deno.land/[email protected]/testing/mock.ts";
import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts";
Deno.test("how stub works", () => {
// Math.randomをスタブで置き換える
// この設定でMath.randomは最初に0.1を、次に0.2を、次に0.3を返すようになる
const mathStub = stub(Math, "random", returnsNext([0.1, 0.2, 0.3]));
try {
assertEquals(Math.random(), 0.1);
assertEquals(Math.random(), 0.2);
assertEquals(Math.random(), 0.3);
} finally {
// もともとのMath.randomに戻すためには.restore()を呼びます
mathStub.restore();
}
});
上記のようにstub
を使うと、特定のオブジェクトの挙動を任意の挙動に置き換えることができます。
スナップショットテスト
Testingモジュールではスナップショットテストの仕組みも提供しています。スナップショットテストを使うことで、たとえば、コマンドラインツールの出力であったり、何らかの言語の変換結果であったりといった、単純にassertEquals
でアサーションするには手間がかかりすぎる対象をテストしたい際にスナップショットテストが有効になります。
スナップショットテストをする簡単な例を以下に紹介します。
import { assertSnapshot } from "https://deno.land/[email protected]/testing/snapshot.ts";
Deno.test("出力をスナップショットと比較する", async (t) => {
const output = generateSomething();
await assertSnapshot(t, output);
});
上記のようにassertSnapshot
を呼び出すことで、自動的にテストコンテキストt
)output
が等しいかを比較してアサーションします。なお、スナップショットを更新したい場合は、テストコマンドの最後に-- --update
という引数を与えることで、スナップショットを更新できます。
22. UUID
UUIDではバージョン1、4、5のUUIDを生成する機能が提供されています。
import { v1, v4, v5 } from "https://deno.land/[email protected]/uuid/mod.ts";
v1.generate(); // UUID v1準拠の文字列が生成されます
v4.generate(); // UUID v4準拠の文字列が生成されます
v5.generate(); // UUID v5準拠の文字列が生成されます
なお、UUID v4については、Web標準APIである、crypto.
という関数を使って生成することもできます。
23. Wasi
WasiモジュールではWASIwasi_
モジュール
import Context from "https://deno.land/[email protected]/wasi/snapshot_preview1.ts";
const context = new Context({
args: Deno.args,
env: Deno.env.toObject(),
});
const binary = await Deno.readFile("path/to/wasm");
const module = await WebAssembly.compile(binary);
const instance = new WebAssembly.Instance(module, {
"wasi_snapshot_preview1": context.exports,
});
context.start(instance);
WASIに依存したwasmバイナリの生成方法についてはWASIの公式サイトなどを参考にしてみてください。
Deno標準モジュールの今後の展望
最後にDeno標準モジュールで今後検討されているプランなどについて紹介します。
I/Oインターフェースの移行作業
Denoは当初I/
移行作業はかなり進捗しており、大部分がWeb Streamsで扱えるようになってはいるものの、一部のAPIがまだ旧Reader/
旧インターフェースでしか提供されていない機能を使う場合は、StreamsモジュールのreadableStreamFromReader
やreaderFromIterable
などを使ってインターフェースを相互に変換して使う必要があります。
直近のプライオリティ
現在の標準モジュールのなかで最も開発の優先度が高いのはNodeモジュールstd/
)std/
はDeno本体のnpm互換性を提供するための基礎部分になっており、std/
の開発が進むことで、Denoから使えるnpmモジュールが増えていくという関係性になっています。
std/
の中でも特に、net、http、tls周りの細かい互換性実装が現在は優先的に進められています。
今後追加の可能性があるモジュール
現状でもかなり分量が多い標準モジュールですが、まだまだカバー範囲が十分ではありません。
よく挙がる提案の一つとして、数学関連の処理が弱いという点があります。現状、たとえば、あるデータの平均や標準偏差を計算するような統計的な処理が標準モジュールからは提供されていません。何度かこのような機能の提案があったものの、そのような機能群をどう位置付けて開発するかという点で合意が形成できなかったために、見送りとなっています。今後のコミュニティからの提案次第で、数学関連のモジュールが追加される可能性が十分にあると言えます。
また、通信プロトコルのカバー範囲も拡張の余地があると言えるでしょう。インターネットと親和性の高いgRPCやMQTTのようなプロトコルは今後追加されるかもしれません。
まとめ
前編と後編の2回に分けて、Denoの標準モジュールについて解説しました。