「JavaScriptとHTML、2ファイル90行のDenoで作るシンプルなBBS」
Node.jsと比べて、Denoで気に入っているところ。
1. モジュール管理がブラウザでも使えるESモジュール互換(URLでimportできる)
2. 安全(ファイルアクセス、ネットアクセスは基本禁止、--promptで都度チェックもOK)
3. ストレージを圧迫する npm install、node_modules が不要
4. テスト方法が標準である(deno test)
5. Denoくんがかわいい
逆に、Node.jsと比べてDenoの不便なところ?
- 非対応モジュールがまだ多い(→移植を進めたり作ったり貢献できる!)
「困難は分割せよ」の如し、一見複雑なプログラムもザクザクモジュールに分割して、それぞれのモジュールがしっかり動いていれば大丈夫。 ESモジュールは、scriptタグがだらだらと並ぶ悪しき習慣と、Node.jsの非標準のモジュール分割方法からの脱却しましょう。
例として、フィボナッチ数列を求めるwebアプリを作ってみます。(index.html)
<!DOCTYPE html><html><head> <script type="module"> import { fib } from "./fib.js"; in_n.onchange = () => { div_result.textContent = fib(in_n.value); }; </script> </head><body> <h1>TDDでフィボナッチ!</h1> <input id=in_n> <div id=div_result> </div> </body></html>
入力ボックスに数をいれると、結果が表示される想定です(タブを押してフォーカスを外す)
import している、フィボナッチ数を計算する関数 fib を fib.js として実装すればいいわけです。
実装を始める前に、Deno.testを使って、テストコードから書いてみましょう。テスト駆動開発です。(fib.test.js)
import { fib } from "./fib.js"; import * as t from "https://deno.land/std/testing/asserts.ts"; Deno.test("fib(0)", () => { t.assertEquals(fib(0), 0); }); Deno.test("fib(1)", () => { t.assertEquals(fib(1), 1); }); Deno.test("fib(2)", () => { t.assertEquals(fib(2), 1); }); Deno.test("fib(5)", () => { t.assertEquals(fib(5), 5); }); Deno.test("fib(10)", () => { t.assertEquals(fib(10), 55); });
fib(0)は0を返すかチェック(assert)するなど、動いてほしいことを書きます。 前2つの数を足すのがフィボナッチ数、5の時5、10の時55になります。
まずは、失敗する fib を実装しましょう。(fib.js)
const fib = (n) => { return n; }; export { fib };
古いJavaScriptでは、functionと長い単語がたくさんでてきますが、=> を使ってスッキリシンプルにいきましょう。
では、テストしてみます。
deno test
結果は
running 5 tests test fib ... ok (3ms) test fib(1) ... ok (1ms) test fib(2) ... FAILED (3ms) test fib(5) ... ok (2ms) test fib(10) ... FAILED (1ms)
引数と結果がたまたま一致する3つは成功しましたが、他2つはだめですね。
ちゃんと動くように実装しましょう。
const fib = (n) => { if (n < 2) { return n; } else { return fib(n - 2) + fib(n - 1); } }; export { fib };
もう一度、deno test すると、全部合格することが分かります。やった!
フィボナッチ計算モジュールができたので、webアプリから使ってみましょう。
Denoをインストールした環境で、次のコマンドでサーバー起動します。(liveserver)
deno run --allow-net --allow-read https://js.sabae.cc/liveserver.js
数を入れて、タブを押せば、結果が表示されますね。
再帰を使ったフィボナッチ数の計算は、引数が大きいと指数関数的に処理時間がかかるので、ひとまず40を超えたらエラーにします。
const fib = (n) => { if (n > 40) { throw new Error("too big"); } if (n < 2) { return n; } else { return fib(n - 2) + fib(n - 1); } }; export { fib };
例外発生を確認するには t.assertThrows を使って、下記のように書きます(fib.test.js)
Deno.test("fib(100)", () => { t.assertThrows(() => fib(41)); });
deno test を使うことで、フィボナッチがテストコードでチェックしている範囲でちゃんと動くことを確認できるわけです。 安心ですね!
もし、引数がマイナスだったら?引数に 'abc' が渡ってきたら?想定する自体に対してどう動いてほしいかをテストコード fib.test.js に追記し、fib.jsの実装を変更していきます。
国連ベクトルタイルを使った新しい地図ライブラリ「mapthree-es」で使っているデータ構造「pbf」、テストを後回しにしていたので対応しました。 実際のテストコード pbf.test.js、compile.test.js を見たり動かしたりしてすると理解が深まります。
このコードを動かすために、Node.js用のコード resolve-protobuf-schema をforkして、resolve-protobuf-schema-deno としてDeno移植。
その移植のために、Node.js用のコード protocol-buffers-schema を protocol-buffers-schema-es としてESモジュール、Deno移植。
GitHub Pagesを設定して、CDN的に使っています。
例えば、こちらESモジュールにも対応させベクトルタイルが依存するライブラリ point-geometry、npm install すると node_modules は 496項目、90Mbyte もの容量を使います。モジュール Point.js 自体はたった 9KBなのに!
チーム開発においても重要なモジュール分割。 サーバーで動かすコード、クライアントで動かすコード、それぞれ担当したところがちゃんと動くようにテストコードと合わせた開発が安心ですね。
サクサクと気軽にモジュールが作りたい方にオススメ、Denoで楽しいwebアプリ開発!
jigインターンやOSSで実践しましょう!
links
- JavaScriptとHTML、2ファイル90行のDenoで作るシンプルなBBS
- オンライン開催】jig.jp勉強会&会社説明会 - 次回開催5/21
- jigインターン 2021年夏のjigインターン募集中