🍋

Freshハンズオン 中級編

2024/03/02に公開

Freshハンズオンのための記事です。
こちらは中級編となっております。
基本的にJSフレームワークの利用経験がある人向けにざっくりとしか説明していないため、不明点は気軽に聞いて下さい。

準備

下記の基本ツールがインストールされていることを確認してください。

  • VSCode
  • Deno
  • Deno for VSCode

また、Deno Deployに事前にサインアップしてください。

そして、今回のKV書き込み確認用に、Kiviをインストールします。

https://kivi-kv-editor.studio.site/

※まだ安定した拡張機能とは言い難いので、まともに動かなかった場合はworkaroundの項を参照してください。

Web掛け軸を作ろう

とにかくクソデカな文字を画面に表示するだけです。

まずはinit

deno run -A -r https://fresh.deno.dev kakejiku

今度は下記の設定で生成します。

  • Styling library: y
    • twind(2)
  • VSCode: y

※ここでtailwindcssがrecommendedであるにもかかわらず選択しない理由は、GitHub Actionsが必須となりハンズオンには少し回り道になってしまうためです。twindは一部utility classが使用できないことに留意する必要があります。

でっかい文字を表示しよう

index.tsxを下記のように置き換えます。

export default function Home() {
  return (
    <div>
      <link
        href="https://fonts.googleapis.com/css2?family=Yuji+Syuku&display=swap"
        rel="stylesheet"
      >
      </link>
      <style>
        {`h1 {font-family: 'Yuji Syuku', sans-serif;}`}
      </style>
      <h1 class="text-9xl flex justify-center items-center h-screen">
        臥薪嘗胆
      </h1>
    </div>
  );
}

※標語は好きに変えてください

deno task start でプレビューしてください。

デプロイ

deployctlをインストールし deployctl deploy を実行します。
main.tsが自動でエントリポイントと判別されます。アップロードが実行され、URLが発行されます。

標語を変更できるようにする

標語をハードコードせずにDBにストアして、自由に変更できるようにしましょう。
まずHome関数にasyncを追加します。

export default async function Home() {

その次の行にこの2行を追記します。

const db = await Deno.openKv()
const word = await db.get<string>(["word"])

するとブラウザ上でこのように怒られてしまいます。

Deno KVの有効化

これはまだDeno KVがunstableな機能だからで、これを通すにはdeno.jsonに下記を追加します。

  "unstable": [
    "kv"
  ],

また、VSCode上のエラーを消すためにmain.tsに下記の行を追加する必要がありました。

/// <reference lib="deno.unstable"/>

取得した値の埋め込み

では早速、取得した標語を埋め込んでみましょう。

  <h1 class="text-9xl flex justify-center items-center h-screen">
    {word.value}
  </h1>

まだDBには何も値を入れていないのでブラウザは真っ白になります。
Kiviで値を追加してみます。

Kiviタブを選択してこの画面になるか確認してください。

正しく表示されている場合、keyにword, Valueに好きな標語を入れてCreateを押下します。

標語は表示されましたか?

ワークアラウンド

Kiviタブが表示されなかった場合、Denoでスクリプトを書いて直接更新を行ってください。

update-kv.ts:

const kv = await Deno.openKv();
const res = await kv.set(["word"], "実質ゼロカロリー");
console.log(res);
deno run -A --unstable-kv update-kv.ts

再デプロイ

さて、下記でもう一度デプロイしましょう。

deployctl deploy --prod

もちろん画面は真っ白ですね。リモートのDeno KVには値が入っていません。
Deno Deployの該当プロジェクトを見てみましょう。

https://dash.deno.com/

KVタブを開くと、接続のための文字列が取得できます。

APIキーが必要になりますので、Set up access tokens for Deno CLIをクリックして適当な名前で作成します。

.envファイルを下記の内容で作成します。

DENO_KV_ACCESS_TOKEN=<取得したAPIキー>

Kiviで接続する場合は、Deno DeployのダッシュボードからUUIDをコピーします。

Kivi下部の"Default Database"をクリックして、UUIDをペーストします。

これでローカルからリモートDBに書き込みできるようになりました。

workaround

CLIから接続する場合は、下記のガイダンスに従ってください。

Deno KVのAPIについてもう少し説明

基本的にはget, list, set, deleteを使用します。

https://docs.deno.com/deploy/kv/manual/operations

const res = await kv.get<string>(["config"]);

このように型を指定して値を取得することができます。

  • keyには配列を指定します。これによってコレクションを表現することができます。
  • keyにはstringやnumberだけではなく、Uint8Array, bigint, booleanを使うこともできます。
  • valueには最大64KBまでのオブジェクトを格納することができます。structuredCloneで使えるtypeを使うことができます(Array, Map, Set, DateなどもOK)

詳しくは公式ドキュメントを参照してください。

更新フォームを作る

VSCode経由の更新はちょっと面倒ですね。
更新フォームを作りましょう。

update.tsxを作成します。

import { FreshContext, Handlers } from "$fresh/server.ts";
const kv = await Deno.openKv();

export const handler: Handlers = {
  async POST(req: Request, _ctx: FreshContext) {
    const form = await req.formData();
    const word = form.get("word");
    const res = await kv.set(["word"], word);
    return new Response("Success");
  },
};

export default function Update() {
  return (
    <div>
      <form action="/update" method="post" class="p-8">
        <input name="word" class="border p-2" />
        <button type="submit" class="border p-2">Submit</button>
      </form>
    </div>
  );
}

ここでのポイントは、ハンドラ関数(上半分)でPOSTを受けて、下半分のコンポーネントでGETを受けていることです。このようなスタイルをfreshではmixed handler and component routeと呼んでいます。

このようなフォームを作成することができます。

BASIC認証をかける

勝手に誰かに書き換えられたら困るので、BASIC認証をつけましょう。

import { defineConfig } from "$fresh/server.ts";
import twind from "$fresh/plugins/twindv1.ts";
import twindConfig from "./twind.config.ts";
import basicAuthPlugin from "https://deno.land/x/hashrock_fresh_plugins@1.0.1/basic.ts";

export default defineConfig({
  plugins: [twind(twindConfig), basicAuthPlugin("/update")],
});

.envにパスワードを追加します。

BASIC_AUTH_USER=hoge
BASIC_AUTH_PASSWORD=fuga

これでBASIC認証を設定できました。

deployctl deploy --prod でデプロイします。

なお、本番環境の環境変数はダッシュボードに追加するUIがあります。

ここまででハンズオンは終了です。

時間が余った人向け

  • 複数文を保存できるようにしましょう
  • Fresh Componentsを使ってアイコンなどを追加しましょう
  • メールお知らせ機能をつけましょう
  • Islandを使って動的なUIを追加しましょう

リポジトリ

https://github.com/hashrock/fresh-handson-kakejiku

Discussion