はじめに
何気に今年始めての投稿になります。今回は前々から気になっていたDenoとそのReactフレームワークであるAleph.jsを少し触って、その雰囲気を確かめてみよう!といった内容の記事です。特に内容はないですが、Denoを使ったReact開発環境構築がNext.jsの感覚で簡単にできてしまいました。
Denoって?
一言でまとめるとRust製のJavaScript・TypeScriptランタイムです。Node.jsと違って以下のような特徴があります。
- デフォルトではファイル・ネットワークへのアクセスが不可(明示的にEnableを指定する必要がある)
- TypeScriptコンパイラを内包している(tsc等の導入が不要)
Aleph.jsって?
Aleph.js(あれふ?読み方わかんないです。。。)はDenoのためのReactフレームワークです。Next.jsに影響を受けてつくられたフレームワークとのことで、SSRやSSG等がサポートされています。
とりあえず触ってみる
Aleph.jsの始め方はGet Startedを見ればだいたいわかります。CLIツール周りもNext.jsとほとんど同じ感覚で使えそうです。現状のところ推奨されている開発環境は以下です。
- Deno v1.7以降
- denoのvscode拡張を使用
そして現時点(2021/02/20)ではv0.3.0のAlphaバージョンが最新のようなので、それをインストールします。
deno install -A -f -n aleph https://deno.land/x/aleph@v0.3.0-alpha.1/cli.ts
ちなみに、このバージョンより古いものをインストールするとコンパイル時にエラーを起こす可能性があります(私の方では古いドキュメントを参考にしてv2.6をインストールしたところ、初期のサンプルコードでコンパイルエラーが起こりました)。
これでaleph
というCLIツールが使えるようになります。基本的にはNext.jsと似たような使い方です。
- プロジェクトの作成
aleph init hello
- developmentモードでの実行
aleph dev
- prodモードでの実行
aleph prod
- 静的サイト(SSG)のビルド
aleph build
サンプルコードを見てみる
aleph init
でプロジェクトを作成するとサンプルコードが実装された状態で以下のような構成のプロジェクトが作成されます。
.
├── 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を参照)はカウンターアプリとなっていて、+
と-
で数を足したり減らしたりするような内容となっています。
カウンター機能の実装はlib/useCounter.ts
の中でuseCallback
を使って実装しているようです。
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を使ってカウンターの値を保存しています。useCallbackの中でもカウンターの値のインクリメント・デクリメントを行っているのは、APIとの同期を再レンダリングが走るとき(useEffect内部)でのみ行っているからですね。
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を参照)。
さいごに
とりあえず今回はAleph.jsで初期に構築されるサンプルコードを見て、Aleph.jsを使った実装の雰囲気を見てみるだけの内容となりました。
実装自体は特にまだできていないので、また時間があれば遊んでみたいと思います。