Fresh - DenoのWebフレームワークを触ってみた特徴と所感
https://gyazo.com/4ffa4b154678acf8e7fdad3878bb7c90
林家花園
#Deno #Fresh
前回の記事で使ってみたFreshについての特徴と所感をまとめてみようと思います。もし前回の記事を読んだことがない場合は、先に読むことをお勧めします。Denoを初めて触ろうと考えている人やFreshを使ってみたい人に参考になればと思います。
Fresh は Preact 依存のフレームワーク
Freshは内部実装でPreactが使われています。そのため、後ほど紹介するパッケージ管理システムの中にデフォルトで組み込まれているPreactを外すことはできません。前回はRSSフィードを作るだけだったので、特にPreactやJSXを使うシーンというのは無かったのですが、Preactを外してしまうとFreshサーバの内部実装でエラーになってしまいました。そういう意味では、今回はよりシンプルなHttpフレームワークを使うだけでも良かったのかもしれません。
ゼロコンフィグでTypeScriptが使える
私は普段から専らTypeScriptを使っていますが、Denoは何の設定をせずともTypeScriptを使うことができます。つまり、Node.jsでTypeScriptを書く際には必須となるtsconfig.jsonが必要ありません。この辺りの仕組みとしては、まずDenoを使うときに必須となるdeno-cliにTypeScriptが内包されています。そのため、下記のコマンドでどのバージョンが使われているのかを知ることができます。
code:console
deno --version
# deno 1.24.3 (release, aarch64-apple-darwin)
# v8 10.4.132.20
# typescript 4.7.4
tsconfig.jsonをカスタマイズすることもできます。カスタマイズする場合は、deno.jsonまたはdeno.jsoncというファイルを作成します。ただし、カスタマイズできるのはcompilerOptionsのセクションのみに限定され、そのほかは無視されるようです(Denoには無関係の機能や不完全な動きをするものが含まれるため)。Freshの新規プロジェクトにはdeno.jsonが含まれるため、そのままcompilerOptionsセクションを作成すれば良いですね。ちなみに、デフォルト値については公式ページにまとまっているため、目を通しておくと良いかもしれません。デフォルトでstrict: trueなのは最高ですね。
ビルドステップがない
昨今のNode開発環境ではほぼ確実に必要となるWebpackやesbuildなどのビルドツールも不要です。僕自身はビルドツールの設定に拘ったり全ての設定の意味を調べて必要なものを吟味することが好きなんですが、サクッとアプリを作りたいときにはそれが時間泥棒になってしまう場合があるので、何も設定が必要ないのはプロダクト作成に時間とエネルギーを割くことができて良いですね。
Freshで作成したアプリをDeno DeployにデプロイするようにGitHub連携しておくと、mainブランチをプッシュした直後にアプリケーションがデプロイされReady状態になります。よくみてみると、Deno Deployのプロジェクトページにビルドの画面はありません。これがゼロビルドステップの力か〜と感動しました。
Next.js風のファイルシステムルーティング
FreshはNext.jsと同じようなファイルシステムをベースとしてルーティングを採用しています(Fresh公式でもそのように謳っています)。例えばroutes/hoge.tsxを作成したら、/hogeにアクセスできるようになります。Next.jsであればpages/配下ですが、Freshではroutes/配下であれば、APIリクエストをハンドリングしたり(一般的にはrouters/api/配下に定義しますが任意です)、JSXを返してHTMLのページをレンダリングするすることができます。公式ドキュメントの表がわかりやすいので参考にしてみると良いでしょう。
import map を使ったパッケージ管理システム
Denoではimport時に直接URLを書いてしまう方法の他、パッケージ管理を行う手法としてdeps.tsを使う方法とimport mapを使う方法の二種類があるようですが、Freshの新規プロジェクトではデフォルトでimport mapを使った方法が採用されています。これはプロジェクト内にimport_map.jsonファイルを置いて依存を解決する仕組みです。
code:import_map.json
{
"imports": {
"$fresh/": "https://deno.land/x/fresh@1.0.2/",
"preact": "https://esm.sh/preact@10.10.0",
"preact/": "https://esm.sh/preact@10.10.0/",
"preact-render-to-string": "https://esm.sh/preact-render-to-string@5.2.1?external=preact",
"rss-parser": "https://esm.sh/rss-parser@3.12.0"
}
}
インポートしたいESモジュールのURLに対して、任意の名前をキーとしたJsonを定義します。このようなファイルをプロジェクトルートに配置したのち、deno.jsonにファイルパスを明記してあげると、このファイルを使って依存を解決してくれます(実行コマンドの引数に--import-map ./import_map.jsonと指定する方法もあります)。
code:deno.json
{
...
"importMap": "./import_map.json"
}
実際のコードでは以下のようにインポートして使います。
code:main.ts
import { HandlerContext, Handlers } from "$fresh/server.ts"; // https://deno.land/x/fresh@1.0.2/
import Parser from "rss-parser"; // https://esm.sh/rss-parser@3.12.0
DenoはNodeとの互換性がないため、現状はNode用に作成されたnpmのパッケージをそのまま使うことはできません(3ヶ月以内には80%〜90%のnpmパッケージを簡単に使えるようにする計画がブログで公表されました)。そこで、npmパッケージを使いたい場合は以下の順番で試してみると良いです。
1. https://deno.land/x にホスティングされていないか調べる
deno.land/x はDeno用モジュールのホスティングサービスです。lodashやdayjsなどの人気なパッケージはすでに公開されているようです。今回使ってみたFresh自身もここにホスティングされています。import_map.jsonのURLにhttps://deno.land/x/{パッケージ名}@{バージョン}と書いて使います。
2. ESM形式で、Deno用にビルドされたパッケージを配布してくれるCDNを使う
前回のRSSフィードを作成するときは、rss-parserというnpmパッケージを使うために https://esm.sh というCDNを利用しました。ブラウザでhttps://esm.sh/{パッケージ名}にアクセスすると、https://esm.sh/{パッケージ名}@{バージョン}にリダイレクトされるので、それをURLとしてimport_map.jsonに書いてあげましょう。実は、DenoにはNode互換のパッケージが存在しており、Node専用のモジュールをNode互換のモジュール呼び出しに置き換えることにより使える場合があり、その仕組みを使ってDeno用モジュールを配布できるCDNのうちの一つがesm.shです。
ちなみに、依存パッケージの更新管理はdependabotやrenovateがよく使われますが、Denoではuddというツールがよく使われているようです。しかし、現状はesm.shのURL形式を完全にサポートできていないため、今回は使いませんでした。今後のアップデートが待たれるところです。
クライアントサイドJSを動かすための仕組み
Freshはインタラクティブなページを実装するための仕組みとしてアイランドアーキテクチャを採用しています。基本的に全てのコンポーネントはサーバサイドでレンダリングされますが、islands/配下に定義したコンポーネントだけはクライアントサイドで埋め込まれレンダリングされる仕組みです。動的なコンポーネントだけはファイルシステムで孤立・分離させることでクライアントサイドJSの量を最小限に抑えられますし、影響がそのコンポーネントに閉じるように工夫されています。
まとめ
一部の内容はFreshというよりDenoの良いところを語ってしまいましたが、Freshは軽量で薄いフレームワークのため、初めてDenoを触ってみたい方には最適なフレームワークのうちの一つではないかと思いました。次はislands/をゴリゴリ使ったアプリやPreactをガッツリ使うもの、ある程度大きめのページも作ってみたいです。
Freshに関してより詳細な情報を知りたい方は、https://fresh.deno.dev/docs/concepts を眺めてみてください。Freshの考え方が簡潔にまとまっています。
https://i.gyazo.com/51454271bc5520c96d424a29a19498c4.png https://twitter.com/share?url=https%3A%2F%2Fscrapbox.io%2Fwada-blog%2FFresh_-_Deno%25E3%2581%25AEWeb%25E3%2583%2595%25E3%2583%25AC%25E3%2583%25BC%25E3%2583%25A0%25E3%2583%25AF%25E3%2583%25BC%25E3%2582%25AF%25E3%2582%2592%25E8%25A7%25A6%25E3%2581%25A3%25E3%2581%25A6%25E3%2581%25BF%25E3%2581%259F%25E7%2589%25B9%25E5%25BE%25B4%25E3%2581%25A8%25E6%2589%2580%25E6%2584%259F&text=Fresh+-+Deno%E3%81%AEWeb%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF%E3%82%92%E8%A7%A6%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%9F%E7%89%B9%E5%BE%B4%E3%81%A8%E6%89%80%E6%84%9F < Twitter でシェア
参考
Fresh - Deno の 次世代 Web フレームワーク
Effective Deno
Deno v1.15で導入されたNode.js互換モードについて
宣伝
株式会社モニクルでは、はたらく世代・子育て世代が抱えるお金や資産運用に関する不安や悩みを解決するお手伝いをさせていただき、現在から老後に至るまでの資金計画や最適なポートフォリオの提案を行っております。
会社の紹介スライドはこちら → https://speakerdeck.com/monicle/about