個人のポートフォリオサイトを CloudflareとAstroで作った話

2.2K Views

May 25, 24

スライド概要

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

個人のポートフォリオサイトを CloudflareとAstroで作った話 Serverless Meetup Osaka #01:begin

2.

今日伝えたいこと • Pagesは、ポータルサイトやポートフォリオサイトで輝く • エッジで表示したい情報を収集・キャッシュしよう • 「コンテンツを加工処理するCMS」が今後出てくるかも

3.

HELLO! ✋ 岡本 秀高 (Hide) • Stripe Developer Advocate • WordCamp Kyoto 2017 • @hidetaka_dev • https://hidetaka.dev

4.

hidetaka.dev

5.

仕事・趣味で書いた記事 公開したOSS 書籍やイベント情報 Etc…

6.

hidetaka.devのデータソース • microCMS: 登壇情報や書籍執筆履歴など • WordPress: 個人ブログ • Qiita / Zenn / dev.to: 仕事での技術ブログやワークショップ資料 • npm / WordPress.org API: 公開したOSS情報 • Markdown (Markdoc): 日英でのスピーカープロファイル • etc…

7.

欲しかったもの • いろんなデータソースから情報を収集する仕組み • マネタイズしないので、できるだけ無料でできる環境 • いい感じの見た目を、コピペかノーコードで作れる環境

8.

astro.build fl https://developers.cloud are.com/pages/framework-guides/deploy-an-astro-site/

9.
[beta]
--const packages = (await listMyNPMPackages())
.map((object) => object.package)
.sort((a, b) => new Date(b.date).getTime() new Date(a.date).getTime())
--<ul
role="list"
class:list={[
"grid grid-cols-1 gap-x-12 gap-y-16",
Astro.props.class
]}
>
{packages.map(pkg => (
<Card as="li">
<CardTitle href={`${pkg.links.npm}`}>
{pkg.name}
</CardTitle>

</ul>

))}

<CardCta>Read package</CardCta>
</Card>

コンポーネントごとに
データ取得処理を
SSR / SSGで実装できる

10.
[beta]
--import AboutPage from "../../containers/pages/
AboutPage.astro";
import { getLanguageFromURL } from "../../libs/
urlUtils/lang.util"
/**
* Static Page
* This page will rebuild by the microCMS Webhook
*/
export const prerender = true
const currentPage = new
URL(Astro.request.url).pathname;
const lang = getLanguageFromURL(currentPage);
--<AboutPage lang={lang} />

アプリ / ページ単位で
SSR / SSGの制御ができる

11.

Astroにした理由 • サイト・ページ単位でSSR・SSGができる • コンポーネントにサーバーサイドfetchが書ける • データを使いたい場所、現場でデータ取得ができる • アシスタントの名前をHuston AIにするセンス

12.

UIはTailwind UIを利用(課金)

13.
[beta]
--const {class:className, ...props} = Astro.props
--<a
href="/"
aria-label="Home"
class:list={[className, 'pointer-events-auto']}
{...props}
>
<img
src={Astro.props.avatarImage}
alt=""
sizes={Astro.props.large ? '4rem' : '2.25rem'}
class:list={[
'rounded-full bg-zinc-100 object-cover',
Astro.props.large ? 'h-16 w-16' : 'h-9 w-9'
]}
/>
</a>

Tailwind UIの
HTMLタグを
Astroコンポーネント化

14.

Astro x Tailwind UIにした理由 • Astroなら、HTMLをほぼコピペだけで使えた • いい感じのパーツをかき集めてコンポーネント化 • 取得したデータを流し込みして、ページにする

16.

Cloudflare Pages • 個人のポートフォリオなら、ほぼ無料で使え・・・そう • Gitインテグレーションで CI / CD • SSRも使えるが、Workers同様の制限がある • CLIでローカル実行も可能

17.

Cloudflare Pagesに決めた理由 • 無料で使える上に、SSRや CI / CDも使える • Honoと日本コミュニティの存在 • 困った時に、日本に頼れる場所がある -> 実際すぐに泣きついた

18.

Astro(SSR)では、envをgetRuntimeで取得 fl https://developers.cloud are.com/pages/framework-guides/deploy-an-astro-site/

19.

ビルド時、 APIキーがundefinedに

20.

Discordで中の人(Cloudflare & microCMS)に聞きながら対処

21.

const runtime = getRuntime(request) if (runtime && runtime.env) { const cfRuntimeAPIKEY = (runtime.env as any).API_KEY as string if (cfRuntimeAPIKEY) { return createClient({ serviceDomain: 'hidetaka', apiKey: cfRuntimeAPIKEY, }) } } const envAPIKEY = import.meta.env.API_KEY if (envAPIKEY) { return createClient({ serviceDomain: 'hidetaka', apiKey: import.meta.env.API_KEY as string, }) } ビルド時用に、 Viteでの環境変数の 取得処理も追加して対応

22.

わかったこと • SSR時とビルド時で環境(ランタイムなど)が違う • ビルド時に環境変数を入れる場合、.envファイルを利用 • .envファイルを配置するために、GitHub Actionsでビルド

23.

Viteのビルドツールが dev / proで違うらしい (@miu_crescentさん情報) https://gist.github.com/kenmori/e1fdd19e383c9d311afa057071896fca

24.

Cloudflare Pagesでハマったところ 実行環境が、「Node.js」ではない

25.

Cloudflare Pagesでハマったところ 実行環境が、 「Node.js」ではない

26.

fl https://www.cloud are.com/ja-jp/learning/serverless/glossary/what-is-chrome-v8/

27.

npm uninstall http npm uninstall fs

28.

http / fsなどは 2023/06/19時点で まだ利用できない

29.

ケース1: Markdown / Markdoc • 一部ページに、Markdoc(Markdown)を利用したコンテンツ • SSGでは問題なく動作 • SSRにすると、fsでエラーが発生 • microCMSにコンテンツを移動させて対応

30.

ケース2: RSS Feed Loader • ZennなどからRSSフィードを読み込む処理 • ライブラリによってhttpが内部で使われている • fast-xml-parserとnode-fetchにリプレイス • レスポンス内容が変わるので、ギリギリに気づくと焦る

31.

ギリギリで慌てないために • wrangler / workerdでローカルテスト • 他の人の事例を調べて、代替ライブラリを模索 • 不安になったら、そのライブラリだけ試すPages PJを作ろう

32.

定期ビルドでのコンテンツ更新は諦めた • Cloud are Pagesにも「ビルドの定期実行」はない • 大人しくSSRで更新しよう • microCMSなどのWebhookから、 「デプロイフック」でビルドする形で検討しなおそう fl • Workersのスケジュール実行からデプロイフックを叩けばできるかも?

33.

名前とブランチを指定して、URL取得

34.

感想戦 CMSはどこに行くのか

35.

CMSは、 コンテンツの「何」を管理するのか? • 従来型:「入稿・保存・出力・表示」すべて一元管理 • Headless:「表示」を手放し、収集と処理をより柔軟に • 「収集と処理」は、誰がどう管理する?

36.
[beta]
$url = 'https://api.openai.com/v1/chat/completions';
$data = array(
'model' => 'gpt-3.5-turbo',
'messages' => array(
array(
'role' => 'system',
'content' => "You're the blog writer good at
the summarizing existing posts. Please generate a short
summary of the user input text by the following
conditions. rule1: The summary should be written in ' .
$lang . '. rule2: The summary should less than ' .
$summary_length . ' words. rule3: The summary should not
include any code example."
),
array(
'role' => 'user',
'content' => $content,
)
)
);
$headers = array(
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $this->api_key,
);
$response = wp_remote_post($url, array(
'body' => json_encode($data),
'headers' => $headers,
'timeout' => 100
));

要約やタグ付け、
インデックス生成は
LLMで外部化・自動化できる

37.

AlgoliaなどのFaaSで ノーコードでも 使える環境は多い

38.

コンテンツは「加工処理」されて ユーザーに届けられるようになる • 人によって異なるお勧め商品・オファー • チャネルや媒体によって異なるLP・メッセージ・CTA • 会話の流れによって変わるコンテンツ

39.

「誰に」 「なにを」 「どう伝えるか」を管理するシステム

40.

Digital Experience Platform (DXP) 「デジタルでの体験」を 管理するシステム

41.

altis - WordPressを使ったDXP

42.

エッジフロントエンドで、 Composable Contentと DXPの話をしよう https://dxpwtf.substack.com/p/composable-content-platforms-2023