[{"data":1,"prerenderedAt":393},["ShallowReactive",2],{"content-/family-trips-astro-cloudflare-launch":3,"all-pages-for-dir":391,"og-image-/family-trips-astro-cloudflare-launch":392},{"id":4,"title":5,"body":6,"category":372,"description":373,"extension":374,"meta":375,"navigation":376,"ogImage":377,"path":378,"project_name":26,"published":379,"publishedAt":380,"seo":381,"stem":382,"tags":383,"todo":377,"unpublished":379,"updatedAt":377,"__hash__":390},"pages/2026-05/2026-05-17/family-trips-astro-cloudflare-launch.md","家族旅行アーカイブを Astro + Cloudflare Pages で立ち上げた記録（pnpm の minimumReleaseAge で躓いた話含む）",{"type":7,"value":8,"toc":359},"minimark",[9,13,17,20,28,32,35,66,69,73,83,86,93,105,109,119,122,148,151,155,170,176,179,194,197,208,211,214,217,228,235,239,242,309,316,323,326,333,336,339,356],[10,11,12],"h2",{"id":12},"きっかけ",[14,15,16],"p",{},"「家族旅行の計画を Cloudflare にデプロイしたい」と思い立った。8月の大分帰省を皮切りに、行き先ごとに地図とガントチャートを置いて、何泊どこに泊まって何をしたかを後から見返せるアーカイブにしたい。",[14,18,19],{},"ホテルブッキングや航空券の予約画面はすぐ消えるし、メモアプリだと地図が貼れない。自分のサイトとして残せば、子供が大きくなったときに親が辿った旅程をそのまま見せられる。",[14,21,22,23,27],{},"新規プロジェクト ",[24,25,26],"code",{},"family-trips"," をローカルに切って、Claude Code に「ゼロから組んで」と頼んだ。手は動かさず、フレームワーク選定とつまずきポイントの判断だけする立場で進めた。",[10,29,31],{"id":30},"なぜ-nuxt-ではなく-astro-にしたか","なぜ Nuxt ではなく Astro にしたか",[14,33,34],{},"普段は Nuxt 4 でブログを動かしているので、横展開で Nuxt を使う手もあった。Claude Code に選ばせたら Astro が出てきた。理由を読んで、これは Astro でいいと納得した。",[36,37,38,50,60],"ul",{},[39,40,41,45,46,49],"li",{},[42,43,44],"strong",{},"コンテンツコレクションがアーカイブ構造と噛み合う",": 「旅行ごとに1ページ」のサイトは、",[24,47,48],{},"src/content/trips/2026-08-oita.md"," を置くだけで型付きルートが生える Astro の構造と相性が良い",[39,51,52,55,56,59],{},[42,53,54],{},"SSG に振り切れる",": 旅行記は基本的に静的で、サーバー側で動的処理を回す要件がない。Astro はビルド後の ",[24,57,58],{},"dist/"," をそのまま配ればよく、Nuxt の SSG 設定で過去にメモリ問題を踏んだ経験から、構造がシンプルなほうが安心できた",[39,61,62,65],{},[42,63,64],{},"JS が軽い",": 地図表示（Leaflet）と多少のドロワー開閉だけ動けばよく、フレームワーク全体を JS で動かす必要がない",[14,67,68],{},"Vue インテグレーションを足せば、必要なところだけ Vue コンポーネントを置ける。実際に地図コンポーネントは Vue で書いた。",[10,70,72],{"id":71},"pnpm-の-minimumreleaseage-で-astro-が弾かれた","pnpm の minimumReleaseAge で Astro が弾かれた",[14,74,75,78,79,82],{},[24,76,77],{},"pnpm create astro@latest"," を回したら、Astro 6.3.3 のインストールでエラーが出て止まった。Claude Code に原因を追わせたら、pnpm の ",[24,80,81],{},"minimumReleaseAge"," 設定が引っかかっていた。",[14,84,85],{},"これはサプライチェーン攻撃の対策で、リリースから一定期間（自分は3日に設定）経っていないパッケージを自動で弾く仕組み。Astro 6.3.3 は2日前リリースで条件を満たさず、インストールが拒否されていた。",[14,87,88,89,92],{},"設定を緩める選択肢もあったが、緩めずに Astro 側のバージョンを下げて回避するほうが筋がいい。10日前リリースの 6.3.1 を ",[24,90,91],{},"package.json"," で明示的に指定して、再インストールでパスした。",[94,95,96],"blockquote",{},[14,97,98,101,102,104],{},[42,99,100],{},"学び",": pnpm の ",[24,103,81],{}," は、悪意あるパッケージが公開直後に拡散する前にブロックする防波堤として効く。発生から24時間以内に検知・取り下げされるケースが多いので、3日待つだけで攻撃成功率がかなり下がる。ハマったときに「設定を消す」ではなく「バージョンを下げる」で逃げるのが正しい振る舞い。",[10,106,108],{"id":107},"cloudflare-pages-は-astro-アダプター不要","Cloudflare Pages は Astro アダプター不要",[14,110,111,112,115,116,118],{},"Astro には Cloudflare アダプターがあるが、今回は使わなかった。Cloudflare Pages は静的ファイルを配るだけのモードで動かせるので、",[24,113,114],{},"pnpm build"," の ",[24,117,58],{}," をそのままアップロードすれば動く。SSR を後から欲しくなったらアダプターを入れる、で十分だと判断した。",[14,120,121],{},"Vue インテグレーションと Leaflet を足して、",[36,123,124,130,136,142],{},[39,125,126,129],{},[24,127,128],{},"BaseLayout.astro","（共通レイアウト + サイトナビ）",[39,131,132,135],{},[24,133,134],{},"index.astro","（トップページ。旅行一覧のテーブル）",[39,137,138,141],{},[24,139,140],{},"[...slug].astro","（動的に旅行詳細ページ）",[39,143,144,147],{},[24,145,146],{},"TripMap.vue","（Leaflet で地図表示。OpenStreetMap タイル使用で API キー不要）",[14,149,150],{},"をひと通り組み上げてもらった。地図タイルが API キー不要で動くので、設定の初期コストがゼロで済むのが嬉しい。",[10,152,154],{"id":153},"github-にプッシュして-cloudflare-pages-で配信","GitHub にプッシュして Cloudflare Pages で配信",[14,156,157,158,161,162,165,166,169],{},"ローカルでビルドが通ったところで、GitHub の private リポジトリ（",[24,159,160],{},"keikomatsu/family-trips","）を作って ",[24,163,164],{},"main"," ブランチに push してもらった。",[24,167,168],{},"gh"," CLI で一気に流れた。",[14,171,172,173,175],{},"最初は Wrangler から Direct Upload モードでデプロイした。CLI から ",[24,174,58],{}," をそのままアップロードする方式で、すぐ動いた。",[14,177,178],{},"ところがデプロイ後に「GitHub と連携してプッシュごとに自動ビルドさせたい」と気が変わった。ここで罠を踏んだ。",[94,180,181],{},[14,182,183,185,186,189,190,193],{},[42,184,100],{},": Cloudflare Pages の ",[42,187,188],{},"Direct Upload モード","と ",[42,191,192],{},"GitHub 連携モード","は、後から相互変換できない。GitHub 連携にしたければ、Direct Upload で作ったプロジェクトを削除して、ダッシュボードから OAuth フローで作り直すしかない。",[14,195,196],{},"Direct Upload で作っていたプロジェクトを Wrangler で削除して、ダッシュボードで GitHub 連携モードのプロジェクトを新規作成し直した。OAuth はブラウザでクリックする工程が残るので、そこだけ自分で踏んだ。",[14,198,199,200,203,204,207],{},"Cloudflare Pages の Node.js バージョン指定は ",[24,201,202],{},"NODE_VERSION=22"," を環境変数に入れておけば、最新の 22.x として解決される。Astro 6 の要件（",[24,205,206],{},">=22.12.0","）を満たすので、これで放置できる。",[10,209,210],{"id":210},"家族メンバーだけが見られるようにする方針",[14,212,213],{},"サイト全体を世界に公開する気はない。家族の旅程・実家の位置・宿泊先がそのまま地図に出ているので、外に出るとプライバシー的にまずい。",[14,215,216],{},"ロックは Cloudflare Access（Cloudflare Zero Trust の一部）で掛ける方針にした。家族のメールアドレスをホワイトリスト登録すると、サイトを開いたとき One-time PIN がメールで届き、PIN を入力した人だけが中身を見られる。",[36,218,219,222,225],{},[39,220,221],{},"パスワード設定もアプリ側の認証実装も不要",[39,223,224],{},"メールアドレス単位で許可を出すので、家族数名分の登録で済む",[39,226,227],{},"Cloudflare 側で完結するので、Astro 側のコードに認証ロジックを書かなくていい",[14,229,230,231,234],{},"これは今日は方針を決めただけで、設定は次のセッションに回した。デプロイされた ",[24,232,233],{},"*.pages.dev"," がまだ公開状態なので、早めに閉じる必要がある。",[10,236,238],{"id":237},"wikimedia-画像のホットリンクで-orb-に弾かれた","Wikimedia 画像のホットリンクで ORB に弾かれた",[14,240,241],{},"トップページに「滞在ガイド」セクションを足して、福岡・札幌・沖縄・台北の代表写真を Wikimedia から拾って表示しようとしたら、画像が出ない。Chrome の Network パネルを見たら ORB（Cross-Origin Read Blocking）でブロックされていた。",[243,244,245,258],"table",{},[246,247,248],"thead",{},[249,250,251,255],"tr",{},[252,253,254],"th",{},"試したこと",[252,256,257],{},"結果",[259,260,261,274,285,293,301],"tbody",{},[249,262,263,271],{},[264,265,266,267,270],"td",{},"Wikimedia の画像 URL を ",[24,268,269],{},"\u003Cimg src>"," で直接参照",[264,272,273],{},"ORB でブロック。localhost からのホットリンクを Wikimedia が拒否",[249,275,276,282],{},[264,277,278,281],{},[24,279,280],{},"wget"," で User-Agent 指定なしで取得",[264,283,284],{},"Wikimedia のホットリンク規約で 403 拒否",[249,286,287,290],{},[264,288,289],{},"具体的な User-Agent を付けて再取得",[264,291,292],{},"サイズが大きすぎて「Use thumbnail size」エラー",[249,294,295,298],{},[264,296,297],{},"800px 指定で再取得",[264,299,300],{},"サイズ違反で再度エラー",[249,302,303,306],{},[264,304,305],{},"500px 指定で再取得",[264,307,308],{},"成功。画像が落ちてきた",[14,310,311,312,315],{},"最終的に ",[24,313,314],{},"public/images/guides/"," にダウンロードして、同一オリジンから配信する形に切り替えた。ホットリンクで楽しようとすると Wikimedia のポリシーに弾かれるので、最初から落として持つのが筋。",[94,317,318],{},[14,319,320,322],{},[42,321,100],{},": Wikimedia の画像をサイトに使うなら、ホットリンクではなくダウンロードしてセルフホストするのが前提。User-Agent と画像サイズ（500px 推奨）の2点を押さえれば API キーなしで取得できる。",[10,324,325],{"id":325},"出来上がったもの",[14,327,328,329,332],{},"ローカルで ",[24,330,331],{},"pnpm dev"," を立ち上げて、Chrome DevTools で確認したら、トップページのテーブル一覧と大分旅行ページの地図ピンが両方表示された。HTTP 200 OK、コンソールエラーなし。リポジトリは GitHub に上がっていて、Cloudflare Pages 連携で自動ビルドが回っている。",[14,334,335],{},"旅行ページ側はその後さらに発展して、ガントチャートで「飛行機 / レンタカー / 実家泊 / 観光 / 食事 / 外泊 / 仕事」のレーンを並べる縦長レイアウトに作り直した。ここは別の日のログに残す。",[10,337,338],{"id":338},"振り返り",[36,340,341,344,350,353],{},[39,342,343],{},"フレームワーク選定で「Nuxt の横展開」ではなく「目的に合うもの」を選び直せたのは Claude Code に提案させた効果が大きかった。自分一人で決めると慣れた選択肢に寄りがち",[39,345,346,347,349],{},"pnpm の ",[24,348,81],{}," で躓いたのは、最初は「インストールエラー」としか出ないので原因に辿り着くまで時間がかかる。今日メモを残しておけば、次に新規プロジェクトで同じ警告を見たときに10秒で原因を特定できる",[39,351,352],{},"Cloudflare Pages の Direct Upload と GitHub 連携の相互変換不可は知らないと事故る。Direct Upload で動かしてみてから本番運用を GitHub 連携にする、というよくありそうな手順が踏めない",[39,354,355],{},"Wikimedia の画像は最初からダウンロードしてセルフホストする前提で組むのが正解。試行錯誤の途中で「とりあえずホットリンクで動かす」をやってもどうせ後で全部置き換えになる",[14,357,358],{},"明日以降は Cloudflare Access の設定と、福岡経由ルートの比較ページを進める。",{"title":360,"searchDepth":361,"depth":361,"links":362},"",2,[363,364,365,366,367,368,369,370,371],{"id":12,"depth":361,"text":12},{"id":30,"depth":361,"text":31},{"id":71,"depth":361,"text":72},{"id":107,"depth":361,"text":108},{"id":153,"depth":361,"text":154},{"id":210,"depth":361,"text":210},{"id":237,"depth":361,"text":238},{"id":325,"depth":361,"text":325},{"id":338,"depth":361,"text":338},"dev","8月の大分帰省を起点に、家族旅行の計画と記録を残すサイトを Astro でゼロから立ち上げた。Nuxt ではなく Astro を選んだ理由、pnpm のサプライチェーン攻撃対策設定でハマったところ、Cloudflare Pages の Direct Upload と GitHub 連携モードの違い、Wikimedia 画像の ORB ブロック対処までを一気通貫で残す。","md",{},true,null,"/family-trips-astro-cloudflare-launch",false,"2026-05-17T00:00:00.000Z",{"title":5,"description":373},"2026-05/2026-05-17/family-trips-astro-cloudflare-launch",[384,385,386,387,388,26,389],"astro","cloudflare-pages","pnpm","cloudflare-access","leaflet","supply-chain-security","8_oxUehHEWVuMKRWU1j5gVWgMmnRCnziEnA6LIqm3OE",[],"https://log.eurekapu.com/og/blog/family-trips-astro-cloudflare-launch.png?v=2026-05-17T00%3A00%3A00.000Z&title=%E5%AE%B6%E6%97%8F%E6%97%85%E8%A1%8C%E3%82%A2%E3%83%BC%E3%82%AB%E3%82%A4%E3%83%96%E3%82%92%20Astro%20%2B%20Cloudflare%20Pages%20%E3%81%A7%E7%AB%8B%E3%81%A1%E4%B8%8A%E3%81%92%E3%81%9F%E8%A8%98%E9%8C%B2%EF%BC%88pnpm%20%E3%81%AE%20minimumReleaseAge%20%E3%81%A7%E8%BA%93%E3%81%84%E3%81%9F%E8%A9%B1%E5%90%AB%E3%82%80%EF%BC%89&author=Kei%20Komatsu&sig=53ad5c402152cc51",1782528837518]