Closed7

Aleph.jsでJamstackサイトを作る ~ デプロイまで ~

ピン留めされたアイテム
Yo IwamotoYo Iwamoto

このスクラップについて

Deno の React フレームワーク,Aleph.js を触ってデプロイまでしてみたので,途中経過や詰まった部分を書きます.
https://alephjs.org/
情報は少ないものの,プロジェクト初期化 → Vercel にデプロイまでの記事はぼちぼちあるようなので,そこに載ってなかった内容が書ければいいかなと思います.

参考にした記事

https://takagi.blog/alephjs-application-deploy-to-vercel/
https://zenn.dev/ryusou/articles/alephjs-microcms

デプロイ先

https://aleph-mypage.vercel.app/

リポジトリ

https://github.com/you-5805/aleph-mypage

Yo IwamotoYo Iwamoto

忘れないように,詳細を書く前に困ったことを全部書き出しておきます.

困ったこと

まだ分からん

  • VSCode でのフォーマッタの詳細設定
  • モジュールのキャッシュの反映のラグ
  • VSCode でのモジュール auto import,拡張子省略

その他

  • Vercel では Aleph.js の API Routeに未対応
Yo IwamotoYo Iwamoto

Vercel のデプロイコマンドでのバージョン指定

Vercel への Aleph.js プロジェクトデプロイに関しては公式でもドキュメントがあるんですが,aleph の最新バージョンである v0.3.0-alpha.33 には対応していません.
https://alephjs.org/docs/deployment

そのため,利用しているバージョンに合わせてビルドコマンドも変更する必要があります.
ちなみに公式ではこのコマンドをビルドコマンドに指定しようと書いています.

curl -fsSL https://deno.land/x/install/install.sh | sh -s v1.6.3 && /vercel/.deno/bin/deno run -A https://deno.land/x/aleph@v0.2.28/cli.ts build

https://deno.land/x/aleph@v0.2.28/cli.ts のバージョン部分を更新して https://deno.land/x/aleph@v0.3.0-alpha.33/cli.ts にするということは分かったんですが,これでビルドがこけて1時間ほど溶かしました.
抜けていたのはコマンド内の sh -s v1.6.3 部分で,これは Deno のバージョンになるので,現時点で最新の sh -s v1.6.3 に更新して,最終的にコマンドは

curl -fsSL https://deno.land/x/install/install.sh | sh -s v1.1.11.5 && /vercel/.deno/bin/deno run -A https://deno.land/x/aleph@v0.3.0-alpha.33/cli.ts build

になります!これを指定しましょう.

↓ ローカルで aleph --version をしたときのログ

$ aleph --version
Check https://deno.land/x/aleph@v0.3.0-alpha.33/cli.ts
aleph.js 0.3.0-alpha.33
deno 1.11.5
v8 9.1.269.35
typescript 4.3.2

ちなみに僕はこの方のリポジトリを参考にして,ルートディレクトリにdeploy.shを配置,ビルドコマンドには以下を指定してデプロイしています.

$ sh deploy.sh

https://zenn.dev/yskszk63/scraps/b1b00a25d240fe

Yo IwamotoYo Iwamoto

useDeno は SSR モードじゃないと使えない

今回,Notion APIとか (未定) を使ってJamstack なサイトを実装してみたいなと思ったので,SSG をはさむ必要がありました.Aleph.js では,Next.js でいう getStaticProps を行うための API として,useDeno フックが用意されているので,これを使うことになります.

getStaticProps では Page コンポーネントとは分けて関数を export し,その返り値が default export されている Page コンポーネントの props に渡されるような流れでしたが,useDeno はコンポーネント内で呼び出します.コールバック内のコードは Deno ランタイムで実行されているようですね.
具体的にはこういう書き方をします.

index.tsx
export default function Page () {
  const blogs = useDeno(async () => await getBlogs());
  return (
    <>
      {blogs.map((blog, index) => (
        <Blog key={index} blog={blog} />
      ))}
    </>
  );
};

困ったのは,これを普通に aleph devaleph build & start でビルドする度に以下のエラーになり,useDeno が呼ばれないことでした.

ERROR 'useDeno' hook in SPA mode is illegal: /pages/index.tsx

「SPAモードってなんやねん,指定してへんぞ」としばらく詰まっていたんですが,SSG を行なっている他の方のリポジトリを見たところ,aleph.config.js の設定によるもののようでした.

aleph.config.js
export default {
  "ssr": true,
};

ここの ssr の値が false になっていると SPA mode という扱いになるようで,true にすると無事 useDeno が動きました.サーバーサイドで動くコールバックを渡すのに hooks ってなんか変な感じがしますが,そうでもないんですかね.

また,SSG 時には何かしら API を叩いてコンテンツを取得するかと思いますが,今回は Node のランタイム API である process は使えないので,Deno の Deno.env を利用します.
具体的にはこんな感じになるかと思います.

index.tsx
const blogs = useDeno(async () => {
  const token = Deno.env.get('NOTION_API_TOKEN');
  return await getBlogs({ token });
};
Yo IwamotoYo Iwamoto

import_map.json の挙動

Deno は Node.js の開発者 Ryan Dahl 氏が Node.js の反省を元に開発した JS, TS ランタイムです.Node.js にあった package.jsonnode_modules の存在は彼にとっては反省点のようで,Deno ではこれらが廃止され,全てのモジュールは URL から直接 import されるようになっています.(正直まだ初心者なのでその辺の反省点はそこまでピンときませんが!)

index.tsx
import { useDeno } from 'https://deno.land/x/aleph@v0.3.0-alpha.33/framework/react/mod.ts';

そこで,全てのファイルにいちいち以下のような import 文を書いていたら大変だということで,import_map.json で URL と alias を対応づけて,import 文では alias の方を利用できるようになっています.

import_map.json
{
  "imports": {
    "framework/react": "https://deno.land/x/aleph@v0.3.0-alpha.33/framework/react/mod.ts"
  }
}
index.tsx
import { useDeno } from 'framework/react';

(ちなみに Deno はビルトインで ES モジュール をサポートしていて,逆にrequireなどは利用できません)

ここで途中まで分からずかなり困っていた仕様が,

  1. alias は上の ~/mod.ts のようなファイルだけでなく,framework/react/ のようにディレクトリに対しても貼れる.
  2. import_map.json に書かれていても,マシン上にキャッシュされていないモジュールはエディタ上であらゆるサジェストが効かない.

という2点です.
書くの疲れてきました.

2については当たり前なんですが,Node.js に慣れていた身からするとあれ?となりしばらく詰まります (僕だけかもしれません).
Deno では,URL からモジュールを初めて import するときに,マシン上にモジュールをキャッシュします.Node.js でいうと node_modules にパッケージがダウンロードされている状態です.これがないと,import 文を書いたときに,import_map.json に書いているにも関わらず赤波線が出て,モジュールを格納した変数をホバーしても何も表示されず,あれ,URL 間違ったかなとなります.
VSCode では URL ホバー時のポップアップからこの初回キャッシュを走らせることができますが,以下のように CLI で行えるので,これをしましょう.

$ deno install <module_url>

それだけでした.
というか,node_modulesを廃したのは分かったんですが,import したモジュールをキャッシュしてるのはこれとはまた別なんですかね?

Yo IwamotoYo Iwamoto

普通に見つかりませんでした.どこ?

というのも,公式ドキュメントでは Link を https://deno.land/x/aleph/mod.ts から import しているんですが,これは v0.2.28 時点での情報で,現在の v0.3.0-alpha.33 では aleph/mod.ts は存在していません.
https://alephjs.org/docs/basic-features/routing
ドキュメントやコード内を探したんですが見つけられなかったので,onClickrouter.push(href) する,Link らしきコンポーネントを作って対応しました…

react-routernext/linkLink の内部実装はおろか生成しているDOMの詳細も知らないので分からないんですが,確か a タグで囲みつつ,クリック時には web サーバーにリクエストを送るのを止めるみたいなコンポーネントだった気がするので,また調べます.

ちなみに useRouter フックは https://deno.land/x/aleph@v0.3.0-alpha.33/framework/react/mod.ts で export されています.不安定だと難しいですね.

Yo IwamotoYo Iwamoto

VSCode でのフォーマッタの詳細設定

これが分かりません.
Deno では リンタやフォーマッタは組み込まれていて,deno lintdeno fmt で実行できます.めちゃくちゃ速いです.
が,VSCode 上で save 時に走っているのは多分これじゃないですよね…
設定はこうなってます

.vscode/settings.json
{
  < 省略 >
  "deno.lint": true,
  "editor.defaultFormatter": "denoland.vscode-deno",
  "editor.formatOnSave": true
}

"deno.enabel": true になっている workspace 内で .ts, .tsx, .js, .jsx ファイルが save されたら 拡張機能であるdenoland.vscode-deno というフォーマッタが走るということかと思うんですが,この denoland.vscode-deno 拡張機能でフォーマットの詳細設定をするインターフェイスが見つからず,初期設定のままフォーマットされている状態です.

このスクラップは2021/07/15にクローズされました