脱Node.jsからのDenoしてる話
Node.jsのパッケージ周りのしんどさやPureJSとの乖離のつらさ(例えば昔はfetchがなかったとか)を感じ、個人ではDenoに切り替えていきたいと常々考えていました。実際CLIやバックエンド等はすんなり移行できたものの、最後の障壁となっていたのが現在利用している、tsc
等Node.jsで動くツールでした。これを使えないと脱することはできません。
しかしそれも過去の話。最近のDenoはnpmパッケージを正式に使えるようになり、後は tsc
等のNode.jsで動くツールをインストールできれば自分の使い方ならば十分脱Node.jsできるはずです。最近タイミングよく新しいPCを入手したので、ここ数ヶ月はNode.jsを入れない状態で個人開発を行ってみました。
初めに書いておくとフレームワークなどをあまり使わない自分の使い方だと実務向きではないとは思います。ただ、脱Node.jsの話はちらほらあるものの実際に何をしてどんなふうに使っているかの具体的な話があまりないので、何を使っているのか、どう使っているのかをざっくりとまとめていきたいと思います。
主な開発環境
- 開発ツール
- 基本的にはDenoがデフォルトで提供するツールを使う。
- フォーマッターやテストなど。
- VSCode + vscode_deno
- 基本的にはDenoがデフォルトで提供するツールを使う。
- フロントエンド
-
tsc
とtsconfig.json
を用いたシンプルなビルド- Minifyやビルド系のツールは個人規模なのでほぼ使わない。
- どうしても使うときだけ入れて使ったりするので今回は触れない。
- WebComponents+PureJSによるWebアプリの開発
- React等のフレームワーク未使用。
- 実務ではフレームワーク必須なのでここに関しても触れられない。
-
- バックエンド
- Denoの標準ライブラリによるサーバー実装
- Denoが提供する静的なWebサーバー
- 自作フレームワーク
- Deno Deployを用いたDenoのバックエンドの簡易デプロイ
- Denoの提供する機能を使っていれば特に何もすることなくローカルで動いていたものを動かすことができる。
あまり実務には向いていないものの tsc
をインストールできるなら他のNode.jsのツールもインストールできるでしょう。そういう場合の参考にもなると思うので以下では自分がよく使っているツールや何をよく使っているかを紹介していきます。
Deno本体
Deno標準ツール
Denoはデフォルトでリントやフォーマッター、テスト等を提供しています。正直基本的なツール類は設定を deno.json
にまとめられることもあり、これを使えば良いと思います。
公式が提供するツールは色々あるので、deno --help
で出てきたサブコマンドを見てみます。
SUBCOMMANDS:
bench
Run benchmarks
bundle
Bundle module and dependencies into single file
cache
Cache the dependencies
check
Type-check the dependencies
compile
UNSTABLE: Compile the script into a self contained executable
completions
Generate shell completions
coverage
Print coverage reports
doc
Show documentation for a module
eval
Eval script
fmt
Format source files
help
Print this message or the help of the given subcommand(s)
info
Show info about cache or info related to source file
init
Initialize a new project
install
Install script as an executable
lint
Lint source files
lsp
Start the language server
repl
Read Eval Print Loop
run
Run a JavaScript or TypeScript program
task
Run a task defined in the configuration file
test
Run tests
types
Print runtime TypeScript declarations
uninstall
Uninstall a script previously installed with deno install
upgrade
Upgrade deno executable to given version
vendor
Vendor remote modules into a local directory
いくつか紹介します。
bundle
bundleは単純にDenoが実行できる単一のJSを出力します。
処理内容にもよりますがブラウザで読めたりもするので、単純にファイルを結合したい時などに使っています。
fmt
フォーマッターです。
デフォルトでフォーマッターが入っているのが非常にありがたいです。設定項目は少ないもののいくつかカスタマイズ可能で、その内容は deno.json
に記述します。
例えば個人で使う場合は以下の設定を行っています。
{
"fmt": {
"files": {
"include": ["src/"]
},
"options": {
"useTabs": true,
"indentWidth": 4,
"lineWidth": 160,
"singleQuote": true
}
}
}
lint
lintも大体fmtと同じように設定できます。
{
"lint": {
"files": {
"include": ["src/"]
},
"rules": {
"tags": ["recommended"],
"include": [],
"exclude": ["require-await"]
}
}
}
task
Denoをちょっと知っている人ならばちょっとハードルの高さを感じるのが権限周りではないでしょうか?
例えば今以下のようなプログラムがあったとします。
fetch('https://deno.land/').then((response) => {
return response.text();
}).then((result) => {
Deno.writeTextFile('download.html', result);
});
Denoはセキュリティのためにファイル読み書きやネット接続、環境変数の参照などが制限され、deno run download.ts
みたいな感じでファイルをダウンロードして保存するプログラムなどは動かせません。
この場合は deno run --allow-write --allow-net download.ts
のように --allow-なんとか
というオプションを付ける必要があります。
正確にはこれを普通に実行すると以下のようになります。
$ deno run download.ts
⚠️ ┌ Deno requests net access to "deno.land".
├ Requested by `fetch()` API
├ Run again with --allow-net to bypass this prompt.
└ Allow? [y/n] (y = yes, allow; n = no, deny) >
このようにこの権限使おうとしてるがどうする?っと聞かれるので y
を押せば権限を許可して実行できます。このように別にフラグ指定はなくても動きますが、毎回許可する?許可する?っと聞かれるのでうざったいでしょう。
かと言ってファイルごとにフラグをいちいち覚えてつけて実行は死ぬほど面倒くさいです。
その問題を解決してくれるのがタスクランナーです。Node.jsにある npm-scripts
と同じ機能です。
具体的には deno.json
に以下のように記述します。
{
"tasks": {
"download": "deno run --allow-write --allow-net download.ts"
}
}
この状態で deno task download
と実行すれば、権限を覚えたりつける必要なく実行する事が可能になります。これがないと本当にしんどかった!!
また余談ですが例えばテストでファイルを読み込む場合等は権限が必要になるので、この後紹介する deno test
を使うと上手く動かない場合もあります。
そのため、deno task tests
というタスクを使って権限を設定したテストを走らせるというようなこともやったりしています。
権限周りで面倒だと思っていた方はこれでハードルが一気に下がったかと思います。
test
deno test tests/
などと指定することでフォルダ内 なんとか.test.ts
等のファイルのテストを実行してくれます。詳しくは以下を見てください。
assert等も提供されていて上記ページにあるような形でテストを書くことができます。
TypeScriptのインストール
Denoは色々できますがフロントの開発でもTypeScriptを使うなら tsc
は外せません。
Node.jsなら typescript
をインストールすれば tsc
コマンドも使えるようになりますが、Denoでは実行するコマンドは1つ1つインストールする必要があります。(Denoの思想的に実行も読み込みもファイル単位できっちりやる必要がある。)
では実際に typescript に含まれる2つのコマンドをインストールしてみます。
deno install --force --allow-all npm:typescript/tsc
deno install --force --allow-all npm:typescript/tsserver
Denoはインストール時に権限を指定すると、以降コマンド実行時にその権限が付与された状態で使えるようになります。
逆に言うと --allow-net
等を指定しない場合ダウンロードやファイル読み書きが発生した時点で許可するか聞かれるので注意しましょう。
自分は完全に tsc
を信頼することにして --allow-all
の権限を与えてインストールしています。
これで無事いつも使っている tsc
がNode.js無しで動くようになりました。
VSCodeとの連携
これに関してはほぼ一択で、公式が提供している拡張機能をインストールします。
後はプロジェクトの設定で有効化します。
VSCodeのワークスペースを開いて deno enable
などで調べれば有効化フラグは出てきますし、ファイルを直接開いて以下のように有効化することも可能です。
{
"deno.enable": true
}
またここで deno.enablePaths
という設定でDenoを有効化するフォルダを配列で指定できます。指定したフォルダ内ではDeno前提の補完となり、他ではブラウザ向けの補完になったりします。
ローカルの静的Webサーバー
以下のページにあるように公式から提供されているサーバーがあります。
最近HTTPSかlocalhostのWebサーバー上でないと動かないフロント技術も増えてきたので、そういう場合にはこういったものを使えばさくっと開発できるでしょう。
バックエンド
実装の話になってしまうのでさらっと流しますが、以下のページにあるように serve
などを使ってサーバーを立てたりすることができます。
サーバーからリクエストを貰って、それを返すのが基本なのでこれをいい感じに隠蔽化したりするフレームワークを使うことになると思います。
Denoが公式に提供するDeno Deployではこの機能をいい感じに上書きしてURL等を指定している部分をガン無視してデプロイを行い、外部と通信できるようにしてくれます。変なことをしなければ素直に実装するだけでデプロイが成功するはずです。
またこういう場合ルーターを導入するかと思いますが、JSに URLPattern という機能があり、これを使うとURLをいい感じに解釈して利用することができます。
const pattern = new URLPattern({
pathname: '/api/:user/*'
});
console.log(pattern.exec('https://localhost/test'));
console.log(pattern.exec('https://localhost/api/me/info'));
実行結果は以下です。
null
{
inputs: [ "https://localhost/api/me/info" ],
protocol: { input: "https", groups: { "0": "https" } },
username: { input: "", groups: { "0": "" } },
password: { input: "", groups: { "0": "" } },
hostname: { input: "localhost", groups: { "0": "localhost" } },
port: { input: "", groups: { "0": "" } },
pathname: { input: "/api/me/info", groups: { "0": "info", user: "me" } },
search: { input: "", groups: { "0": "" } },
hash: { input: "", groups: { "0": "" } }
}
この結果を見ればルーティングも余裕で実装できるのがわかると思います。
Deno Deploy
Deno DeployはDenoで動くプログラムを超簡単にデプロイして動かすことのできるEdge Workerです。
GitHubのリポジトリか直にコードを入力することで動かせます。
またGitHubのリポジトリと連携した場合、リポジトリ内のファイルを読み込むことが可能です。ファイルの書き込みができるストレージがないため、例えば読み込みのみの個人サイトなどであれば十分利用可能かもしれませんが、サービスとなってくると厳しいものがあります。外部DBとの連携に関しては資料があるのでそれを参考にすれば色々できると思います。
ちなみに、ファイル読み書きに関しては一部のAPI(Promiseを利用しないやつ)を呼んだだけでエラーとなります。
SQLiteも読み込みなら動くのでは?っと思うかもしれませんが例えばサードパーティーの https://deno.land/x/sqlite はDeno Deployでは使用不可能です。(Deno Deployで禁止されているAPIを使い、作者もこれに関して合わせる気がないため。)
ただしこれには回避策もあり、ファイルを読み込んだ後エラーとなるAPIを再現した処理に置き換えることで回避するライブラリがあります。
こういうライブラリを使えば禁止APIを回避して読み取りも可能になるので、データ更新が発生しないならば単体でSQLiteを使うことも可能です。
まとめ
Denoを使っていて思うのは、やはりPureJSで使える機能がそのまま使えるのと、デフォルトでよく使うツールが含まれているので悩む必要がない点が非常に嬉しいポイントです。
DenoはDenoが提供するAPIを使わなければブラウでもDenoでも動くコードが書けるのが魅力です。JSの最新知識をフルに使えるのでバックエンドとフロントエンドでやり方を変えなくて済むのがすごくストレスフリーだと感じています。
個人的にはシンプルというかあまり実務で使われているようなツールやフレームワークを使わないで開発しているためあまり参考にはならないかもしれませんが、今現在の脱Node.jsしたDenoの開発環境周りの具体例をまとめてみました。個人的には非常に快適です。
他の脱Node.jsした具体例があれば参考になるので増えてくれると嬉しいなと思います。
Discussion