Aleph.jsでDenoを使ったReact開発ができるだと！？

# はじめに

何気に今年始めての投稿になります。今回は前々から気になっていた[Deno](https://deno.land/)とそのReactフレームワークである[Aleph.js](https://alephjs.org/)を少し触って、その雰囲気を確かめてみよう！といった内容の記事です。特に内容はないですが、Denoを使ったReact開発環境構築がNext.jsの感覚で簡単にできてしまいました。

# Denoって？

一言でまとめると[Rust](https://www.rust-lang.org)製のJavaScript・TypeScriptランタイムです。Node.jsと違って以下のような特徴があります。

1. デフォルトではファイル・ネットワークへのアクセスが不可（明示的にEnableを指定する必要がある）
2. TypeScriptコンパイラを内包している（tsc等の導入が不要）

# Aleph.jsって？

Aleph.js（あれふ？読み方わかんないです。。。）はDenoのためのReactフレームワークです。[Next.js](https://nextjs.org/)に影響を受けてつくられたフレームワークとのことで、SSRやSSG等がサポートされています。

# とりあえず触ってみる

Aleph.jsの始め方は[Get Started](https://alephjs.org/docs/get-started)を見ればだいたいわかります。CLIツール周りもNext.jsとほとんど同じ感覚で使えそうです。現状のところ推奨されている開発環境は以下です。

- Deno v1.7以降
- [denoのvscode拡張](https://marketplace.visualstudio.com/items?itemName=denoland.vscode-deno)を使用

そして現時点（2021/02/20）ではv0.3.0のAlphaバージョンが最新のようなので、それをインストールします。

```bash
deno install -A -f -n aleph https://deno.land/x/aleph@v0.3.0-alpha.1/cli.ts
```

ちなみに、このバージョンより古いものをインストールするとコンパイル時にエラーを起こす可能性があります（私の方では古いドキュメントを参考にしてv2.6をインストールしたところ、初期のサンプルコードでコンパイルエラーが起こりました）。

これで`aleph`というCLIツールが使えるようになります。基本的にはNext.jsと似たような使い方です。

- プロジェクトの作成

```bash
aleph init hello
```

- developmentモードでの実行

```bash
aleph dev
```

- prodモードでの実行

```bash
aleph prod
```

- 静的サイト（SSG）のビルド

```bash
aleph build
```

# サンプルコードを見てみる

`aleph init`でプロジェクトを作成するとサンプルコードが実装された状態で以下のような構成のプロジェクトが作成されます。

```text
.
├── api
│   └── counter
│       ├── [action].ts
│       └── index.ts
├── app.tsx
├── components
│   └── logo.tsx
├── import_map.json
├── lib
│   └── useCounter.ts
├── pages
│   └── index.tsx
├── public
│   └── logo.svg
└── style
    └── index.css
```

基本的にはNext.jsと同じような内容になっていますが、Denoっぽい特徴をあげると`import_map.json`というものがあります。これはDenoのパッケージ管理ファイルとなっています。
Aleph.jsのデフォルトのサンプルコード（その他のサンプルコードについては[examples](https://github.com/alephjs/aleph.js/tree/master/examples)を参照）はカウンターアプリとなっていて、`+`と`-`で数を足したり減らしたりするような内容となっています。
カウンター機能の実装は`lib/useCounter.ts`の中で`useCallback`を使って実装しているようです。

```typescript
const increase = useCallback(() => {
  setCount(n => n + 1)
  fetch('/api/counter/increase').catch(e => console.error(e))
}, [])
const decrease = useCallback(() => {
  setCount(n => n - 1)
  fetch('/api/counter/decrease').catch(e => console.error(e))
}, [])
```

この中で`fetch('/api/counter/xxxx')`を実行している箇所があります。これは`api/counter/index.ts`と`api/counter/[action].ts`で定義した`handler`を実行させるために内部でAPIを叩いている部分となります。ディレクトリ構成がそのままAPIのパスにマッピングされるのは、Next.jsとほとんど同じですね。
APIの中では[globalThis](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/globalThis)を使ってカウンターの値を保存しています。useCallbackの中でもカウンターの値のインクリメント・デクリメントを行っているのは、APIとの同期を再レンダリングが走るとき(useEffect内部)でのみ行っているからですね。

```typescript
useEffect(() => {
  fetch('/api/counter').then(resp => resp.json().catch(() => ({})))
    .then(({ count }) => {
      if (typeof count === 'number' && !Number.isNaN(count)) {
        setCount(count)
      }
    })
    .catch(e => console.error(e))
    .finally(() => {
      setIsSyncing(false)
    })
}, [])
```

Next.js同様、Aleph.jsでもウェブページのレンダリングのためにWEBサーバーを立てることになります。なのでWEBサーバーを使って内部にAPIサーバーを立てることで、データのやり取りをAleph.js内で完結させることができるわけですね。まあ、個人的にはAPIサーバーは別で立てて実装したいと思う派なんですが。。。
あとは`pages/index.tsx`でページが実装されていて、ここもほとんどNext.jsと雰囲気は同じですね（唯一Deno独自っぽくなっているのが`useDeno`を使っているところ？）。これも`pages/blog/index.tsx`が`/blog`となるようにディレクトリがそのままパスにマッピングされる形となっているようです（詳しくは[Routing](https://alephjs.org/docs/basic-features/routing)を参照）。

# さいごに

とりあえず今回はAleph.jsで初期に構築されるサンプルコードを見て、Aleph.jsを使った実装の雰囲気を見てみるだけの内容となりました。
実装自体は特にまだできていないので、また時間があれば遊んでみたいと思います。