Deno入門[CLIコマンド、モジュール、環境変数、Webフレームワーク]

この記事は筆者の[ソロ Advent Calendar 2022](https://qiita.com/advent-calendar/2022/panda) 15日目の記事です。

Denoの公式ドキュメントの内容を実際に動かしてみてDenoに入門してみたのでその備忘録の続きです。

[Deno入門[インストール、環境構築、ファイル実行、標準ライブラリ]](https://qiita.com/JY8752/items/9cd6c05394bf955bdd75)
[Deno入門[CLIコマンド、モジュール、環境変数、Webフレームワーク]](https://qiita.com/JY8752/items/a00866917626a8719ebb) <- 今ここ
[Deno入門[npmモジュールの使用]](https://qiita.com/JY8752/items/d177e176a7544b693a34)
[Deno入門[prisma + oakで作るAPI]](https://qiita.com/JY8752/items/198762a69d463ac90fab)
[Deno入門[テスト編]](https://qiita.com/JY8752/items/e7e52aae6a0a3eb69572)

# CLI
Denoはコマンドラインツールのためdenoコマンドでいろいろ操作できます。

```
//help
deno help

//依存関係などを含め一つのファイルにバンドルする
deno bundle <source> <output>

//フォーマット
deno fmt

//リント
deno lint

//テスト
deno test
```

watchオプションでファイルの変更を検知しそのたびにコマンドを実行することもできるのでフォーマットやテストをwatchオプションで実行したりみたいに使えば便利そう。

goもそうだけど標準でフォーマッターついてるのいいな。JavaとかKotlinも標準であればいいのに。

# 設定ファイル
Denoはnodeのようにpackage.jsonのようなファイルを必要としないが、deno.jsonという設定ファイルを配置することができる。基本的には配置不要で開発ができるようになっているが一度公式ドキュメントの[設定ファイル例](https://deno.land/manual@v1.28.2/getting_started/configuration_file)に目を通しておくといつか役に立つかもしれない。

## deno task
npm runのようにあらかじめ登録しておいたコマンドを実行するのにDenoでは設定ファイルにタスクを登録して実行することができる。

```json:deno.json
{
  "tasks": {
    "hello": "deno run --allow-read reading_file.ts hello.txt"
  }
}
```

```
% deno task hello       
Task hello deno run --allow-read reading_file.ts hello.txt
Hello!!
Deno!!
```

# モジュール
Denoでのモジュールの使用はECMAScriptのimport/exportを使用する。importはローカルインポート以外にもURLでのリモートインポートも可能。

```ts:reading_files.ts
import { copy } from "https://deno.land/std@0.166.0/streams/conversion.ts";
const filenames = Deno.args;
for (const filename of filenames) {
  const file = await Deno.open(filename);
  await copy(file, Deno.stdout);
  file.close();
}
```

この時、同じライブラリが複数のファイルでインポートされているとバージョン違いのライブラリをインポートしてしまうことなども考えられるので、deps.tsファイルをルートディレクトリに配置し外部ライブラリをインポートおよび再エクスポートすることで解決することができる。

```ts:deps.ts
export { copy } from "https://deno.land/std@0.166.0/streams/conversion.ts";
```

```ts:reading_files.ts
import { copy } from "./deps.ts"
const filenames = Deno.args;
for (const filename of filenames) {
  const file = await Deno.open(filename);
  await copy(file, Deno.stdout);
  file.close();
}
```

## Lockファイルについて
外部モジュールをインポートしている場合、ローカルで動作していても外部モジュールが更新され挙動が変わってしまうということがあると思います。そのようなことがないようにモジュールのバージョンを固定するのにDenoではlockファイルを使用することができる。

lockファイルの作成
```
deno cache --lock=lock.json --lock-write ./deps.ts  
```

lockファイルを使用してキャッシュをリロードする
```
deno cache --reload --lock=lock.json ./deps.ts
```

作成したlockファイルはgitで管理するのをお忘れなく。

# 環境変数の扱い
Denoで環境変数を扱う場合はDeno.envを使用することで環境変数の設定、参照をすることができます。

```ts:env.ts
Deno.env.set("FIREBASE_API_KEY", "examplekey123");
Deno.env.set("FIREBASE_AUTH_DOMAIN", "firebasedomain.com");

console.log(Deno.env.get("FIREBASE_API_KEY")); // examplekey123
console.log(Deno.env.get("FIREBASE_AUTH_DOMAIN")); // firebasedomain.com
```

また、標準ライブラリからconfig関数をimportし.envファイルを参照することもできる。

```txt:.env
TEST=test
```

```diff_typescript:env.ts
+ import { config } from "https://deno.land/std@0.166.0/dotenv/mod.ts";

Deno.env.set("FIREBASE_API_KEY", "examplekey123");
Deno.env.set("FIREBASE_AUTH_DOMAIN", "firebasedomain.com");

console.log(Deno.env.get("FIREBASE_API_KEY")); // examplekey123
console.log(Deno.env.get("FIREBASE_AUTH_DOMAIN")); // firebasedomain.com

+ const configData = await config();
+ console.log(configData["TEST"])
```

```
% deno run --allow-env --allow-read env.ts
examplekey123
firebasedomain.com
test
```

# Webフレームワーク
Deno製のフレームワークはすでに多くありReactのようなwebフレームワークやExpressのようなサーバーフレームワークもある。名前だけ紹介します

- Fresh Denoで最も人気のあるWebフレームワークらしい。実際Fresh関連の記事をけっこう見かけた
- Aleph Freshの次に人気のあるWebフレームワーク。
- Ultra こちらもWebフレームワーク。
- Lume こちらは静的サイトジェネレーター。
- Oak こちらはExpressのようなWebアプリケーションフレームワークらしい。TypeScriptでサーバーとなるとNestJSがよく聞くけどどうなのだろう。個人的には使ってみたい。

# まとめ
- Denoの基本的なCLIコマンドとtask登録したコマンド実行について紹介しました
- Denoのモジュールや環境変数の扱いについて紹介しました
- DenoのWebフレームワークについて紹介しました

Denoの基本的な扱いについてはこれで大体試すことができました。次回は最近対応したNPMモジュールの扱いについて触っていきたいと思います！