Deno の組み込み機能、ソースコードの変更を検知してオートリロードする "File Watcher" の紹介
Copyright (c) 2018-2020 the Deno authors. MIT License.
この記事は Deno Advent Calendar 2020 13日目の記事です。
12日目は -> (あとで埋める)
14日目は -> (あとで埋める)
Deno は組み込みでいろいろ便利機能が入っている
以前の記事 でも簡単に紹介したのですが、Deno には組み込みで以下のような機能が入っています。
- テストランナー(
Deno.test
という組み込み関数を使って定義されたコードをテストする) - ベンチマーク測定
- バンドラ(依存関係を解決して、単一の
.js
ファイルを出力する) - ドキュメンテーション(ファイルを解釈して、JSDoc を抽出して表示。この出力をベースに、サードパーティのライブラリであってもこのようなドキュメントサイトが生成される)
- REPL
- フォーマッタ (
prettier
のようなもの) - リンター(
ESLint
のようなもの)
今回はこれらの機能(の一部)に対して付与できるオプションである --watch
を紹介します。
--watch
の紹介
--watch
を付けることで、ファイルの内容が更新されたときに自動で再読み込みしてくれるようになります。Node.js でいうところの nodemon のような機能です。
現時点(Node v1.6.0)では以下のコマンドが --watch
に対応しています。
- run
- bundle
- fmt
run --watch
のデモ
例として run --watch
してみた場合にどうなるのか見てみましょう。
まず実行するスクリプトを用意します。自動更新があって嬉しいケースで試してみるのが良いと思うので、APIサーバーの開発という想定でいきます。
import { Application } from "https://deno.land/x/oak/mod.ts";
const app = new Application();
app.use((ctx) => {
ctx.response.body = "Hello World!";
});
console.log("server is ready!");
await app.listen({ port: 7777 });
(https://github.com/oakserver/oak#application-middleware-and-context より[1])
7777番ポートで待ち受けて、あらゆるリクエストに対して Hello World!
を返すだけのシンプルなサーバーです。このファイルを用意したら、以下のようにすることで --watch
オプション付きでサーバーを起動させることができます。
$ deno run --watch --unstable --allow-net my-server.ts
起動後、curl
などで7777番ポートに対してリクエストを送ると、Hello World!
が返ってくることが確認できます。
ここでサーバープログラムを書き換えてみましょう。
import { Application } from "https://deno.land/x/oak/mod.ts";
const app = new Application();
app.use((ctx) => {
- ctx.response.body = "Hello World!";
+ ctx.response.body = "Hello Deno!";
});
console.log("server is ready!");
await app.listen({ port: 7777 });
このように書き換えて保存してみると、立ち上げているサーバープロセスがファイル変更を検知して、自動で再起動されます。
再起動後に curl
でもう一度7777番ポートを叩いてみると、今後は Hello Deno!
に変わっていることが確認できます。
以上の流れをGIFアニメーションにしてみました。
--watch
を使うとどうなるか
bundle, fmt と一緒に bundle --watch
とすると、ファイルの変更があるたびにバンドルを再実行し、常に最新の .js
ファイルを出力します。
同様に fmt --watch
では、ファイルの変更があるたびにフォーマッタを実行します。常にコードがフォーマットされた状態で保たれます。(VSCode などのエディタがこの機能をもっていることが多いと思いますが……)
fmt --watch --check
とすることもできます。こうすると、ファイルの変更があるたびに、フォーマットされたキレイなコードになっているかどうかを チェック します。チェックするだけなので、汚いコードの場合にも警告が出るのみです。
--watch
をつけたときの監視対象ファイルはどのように決定されるか
Deno は Node.js と違って、プロジェクトのルートディレクトリ、といった概念は存在しません。package.json
が無いので、package.json
があるディレクトリがルートディレクトリで、それ以下にある TypeScript / JavaScript のファイルを Watcher の監視対象にする……みたいな扱いができない、ということです。
ではどうやって監視対象ファイルを決めているかというと、ファイル間の依存関係を解決した結果のうち、ローカルにあるファイルをすべて監視対象としています。
例えば、deno run --watch --unstable main.ts
というように起動させたとします。そして、main.ts
にある import
から順に依存関係を見ていった結果が、以下のようになったとします。
main.ts
├── a.ts
├── src/b.ts
│ ├── https://example.com/c.ts
│ └── src/foo/d.ts
└── https://example.com/e.ts
└── https://example.com/f.js
この依存関係のうち、ローカルにあるものは
- main.ts
- a.ts
- src/b.ts
- src/foo/d.ts
の4ファイルです。したがって、これらのファイルを監視対象とします。
ファイルが新規作成された場合は、その新規作成ファイルに到達するような依存関係が追加されれば、監視対象に加えられます。例えば、src/new.ts
を作ったすると、作った段階では Watcher の監視対象には加わっていません。
a.ts
に import { someFunction } from "./src/new.ts";
を追加して保存したとします。このタイミングで、src/new.ts
に到達する依存関係ができあがったので、監視対象に加わります。
おわり
Deno の組み込み便利機能の1つである Watcher を紹介しました。
まだ --unstable
フラグが必要だったり、対応しているコマンドが少ない(例えば deno lint --watch
はまだ出来ない)といった問題はありますが、それでも Deno をインストールするだけですぐに Watcher が使えるというのは強力だと思うので、ぜひ使ってみてください。
Watcher に関して、こういう機能が欲しい、この挙動が気に食わない、などありましたらぜひご連絡ください!(できる限り実装します)
-
MIT License https://github.com/oakserver/oak/blob/main/LICENSE ↩︎
Discussion