皆様こんにちは、ゆっくり不動産でお部屋を眺めながら引っ越しを検討しています。おっくんです。
虎の穴ラボ Advent Calendar 2021 - Qiitaの18日目の記事です。
17日目は、H.HさんによるGithubActionsでLambdaのテストからデプロイまでを自動化した話でした。
こちらもぜひご覧ください。
今回は、Deno 環境で動作する Web アプリケーションフレームワーク Ultra を紹介します。
Ultra は、開発者が特に設定を行うことなく React のサーバーサイドレンダリングが動作するフレームワークです。 examples に用意されたものがあるので導入として触り、Web APIとの連携方法まで紹介します。
実行環境
Deno 1.16.3
examples から紹介
導入方法が紹介されているので、この通り実行してみます。
$ git clone https://github.com/exhibitionist-digital/ultra $ cd ultra/examples/react18 $ make dev mode=dev deno run --no-check --allow-net --allow-read --allow-env --allow-run --allow-write --import-map=importmap.json --unstable server.js Listening: http://localhost:3000
localhost:3000 にアクセスすると次のように表示されます。
非常に簡単です。
この React18 のサンプル以外にも、いくつか examples に含まれているので、ぜひ触ってみてください。
$ pwd /usr/src/app/ultra/examples/react18 $ cd .. $ ls boilerplate react18 threejs ultra-website web3
Ultra は、API サーバーの役割もできます。
Ultra を触っていただくと SSR をしてくれる SPA がかんたんに構築できるという点で、とても便利なのが伝わるかと思います。
examples で紹介されていない機能として、API サーバーアプリケーションも Ultra にまとめて実装することができます。
実は Ultra は、Deno のミドルウェアフレームワーク oak を使用して実装されています。
この oak のルーター機能を Ultra で使っているものがエクスポートされています。 こちらを拡張することで、独自のルーティングを追加できます。
実際に順を追いながらやってみます。
Ultra を自作ツールで初期設定
ultra の初期設定を行います。 毎度クローンするのが面倒なので、ultra の初期化 cli ツール ultra-init を作ったので使います。
この ultra-init を使用しての初期化、アプリケーション起動は、次の通りです。
$ deno run --allow-net --allow-write=. https://deno.land/x/ultra_init/cli.ts App name? # app 入力 $ cd app $ make dev mode=dev deno run --no-check --allow-net --allow-read --allow-env --allow-run --allow-write --import-map=importmap.json --unstable server.js Listening: http://localhost:3000
こちらのツールで使用するテンプレートについては、紹介しないのでultra-initのリポジトリをのぞいてみてください。
ディレクトリの構成は次のようになっています。
. `-- app |-- importmap.json |-- makefile |-- server.js `-- src |-- app.jsx `-- components |-- demo.jsx |-- links.jsx `-- repositry.jsx
Ultra に API を実装する
app/server.js は、次のようになっています。
[app/server.js]
import ultra from "https://deno.land/x/ultra@v0.6/mod.ts"; await ultra({ importmap: await Deno.readTextFile("importmap.json"), });
https://deno.land/x/ultra@v0.6/mod.ts の export として、router が有るのでこちらも import します。
[app/server.js(router を準備)]
import ultra, { router } from "https://deno.land/x/ultra@v0.6/mod.ts"; await ultra({ importmap: await Deno.readTextFile("importmap.json"), });
api の実装を app/api/module.ts に作成します。
[app/api/module.ts]
const addRoute = (router) => { router.get("/api/data", data); }; const data = async (context) => { // 外部APIへのアクセスやデータベースをすることを想定しますが、 // 一旦配列を返すだけにします。 const payload = [1, 2, 3, 4, 5]; context.response.body = JSON.stringify({ payload }); }; export { addRoute };
ここで作成した addRoute を使用して Ultra が提供してくれる router を拡張します。
[app/server.js(router を拡張)]
import ultra, { router } from "https://deno.land/x/ultra@v0.6/mod.ts"; import { addRoute } from "./api/module.ts"; addRoute(router); await ultra({ importmap: await Deno.readTextFile("importmap.json"), });
Ultra で Web API を使う
app/src/components/get_data.ts を作成し、用意した/api/data にアクセスし取得したデータを表示してみます。
[app/src/components/get_data.ts]
import React, { useEffect, useState } from "react"; const GetData = function () { const [data, setData] = useState([]); useEffect(() => { fetch("/api/data", { method: "GET" }) .then((res) => res.json()) .then((data) => { setData(data.payload); }); }, []); return ( <div class="flex justify-center m-3"> <div class="block"> <div class="flex justify-center m-3"> <h3 class="text-3xl">Get Data</h3> </div> <div class="flex justify-center m-3"> <div class="flex-1 m-1">{data.join(",")}</div> </div> </div> </div> ); }; export default GetData;
[app/src/components/links.jsx]
import React from "react"; import { Link } from "wouter"; const Links = function () { return ( <div class="flex justify-center m-3"> <div class="block"> <div class="flex justify-center m-3"> <div class="flex-1 m-1"> <span class="text-2xl md:hover:underline"> <Link href="/">Repositry</Link> </span> </div> <div class="flex-2 m-1"> <span class="text-2xl md:hover:underline"> <Link href="/demo">Demo</Link> </span> </div> <div class="flex-2 m-1"> {/* 追加した/data へのリンク */} <span class="text-2xl md:hover:underline"> <Link href="/data">Get Data</Link> </span> </div> </div> </div> </div> ); }; export default Links;
import React, { lazy, Suspense } from "react"; import { Helmet } from "helmet"; import { SWRConfig } from "swr"; import ultraCache from "ultra/cache"; import { Route } from "wouter"; const Repositry = lazy(() => import("./components/repositry.jsx")); const Links = lazy(() => import("./components/links.jsx")); const Demo = lazy(() => import("./components/demo.jsx")); // 作成した components/get_data.jsx の取得 const GetData = lazy(() => import("./components/get_data.jsx")); const Ultra = ({ cache }) => { return ( <SWRConfig value={{ provider: () => ultraCache(cache) }}> <Helmet> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta charset="UTF-8" /> <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet" ></link> <title>ULTRA - app</title> <link rel="icon" type="image/svg+xml" href="https://ultrajs.dev/logo.svg" /> </Helmet> <main> <div class="flex justify-center m-3"> <h1 class="text-4xl">app</h1> </div> <div class="flex justify-center m-3"> <img src="https://camo.githubusercontent.com/ac900236c1cc4ca5ed749e8bf519206ddb3dd1949a4158d0e5158af474bea011/68747470733a2f2f647765622e6c696e6b2f697066732f6261666b7265696168366c79716c746a7a6d716167676e3369616e673673697037746e626f74767879716567367a6772656d3677716e696567666d" class="inset-0" /> </div> </main> <Suspense fallback={null}> <Links /> <div class="flex justify-center m-3 border border-gray"> <Route path="/"> <Repositry /> </Route> <Route path="/demo"> <Demo /> </Route> <Route path="/data"> {/* 追加した/data に対応した部分 */} <GetData /> </Route> </div> </Suspense> </SWRConfig> ); }; export default Ultra;
これまでのものを作成できたら、リロードすると Get Data
のリンクがあるので開きます。
すると、/api/data
にリクエストを行い、返却された [1,2,3,4,5]
を表示できています。
ここまでで、Ultra が使用している oak に API を追加。API のレスポンス結果を表示できました。
まとめ
今回は、Deno の Web アプリケーションフレームワーク Ultra を紹介しました。
「Deno で API サーバーは作ってみたけど・・・」、といった際の次に「フロントエンドも Deno で」といった際に取れるプランとしてオススメです。
最近 Reactを使うフレームワークとして、Remix v1 が公開されました。
この投稿で、Remix を Deno Deploy でサポートすることを計画されていることが書かれています。 フロントエンド向け実行環境としての Deno も面白いので、Deno のサードパーティモジュール群も是非眺めてみてください。
Node.js 向けライブラリの移植や、インスパイアモジュールもいろいろ発見できると思います。
また、Slack も新たな SDK を Deno をターゲットとした TypeScript で構築することを発表しました。 ますます Deno の盛り上がりを感じるようになっています。 リリースノートも併せ、引き続き Deno を追いかけます。
明日は、nsd さんより、「 『Team Geek ―Googleのギークたちはいかにしてチームを作るのか』の感想 」です。
P.S.
採用情報
■募集職種
yumenosora.co.jp
カジュアル面談も随時開催中です
■お申し込みはこちら!
news.toranoana.jp
■ToraLab.fmスタートしました!
メンバーによるPodcastを配信中!
是非スキマ時間に聞いて頂けると嬉しいです。
anchor.fm
■Twitterもフォローしてくださいね!
ツイッターでも随時情報発信をしています
twitter.com