大地図 ― なぜ「全部いっしょに襲ってくる」のか
最初に、いちばん大事な安心を渡します。あなたが並べた50個の横文字は、バラバラの敵ではありません。全部、たった1つの仕事——「文字と絵を、人のブラウザの画面に出す」——のための道具です。役割で並べれば、1本の道の上にきれいに整列します。
「フロントエンドって何なの? Webページを作る話じゃなかったの? なんでサーバーも、ビルドも、キャッシュも、認証も、全部いっしょに襲ってくるの!?」
答え:フロントエンドとは「人が実際に見て触る画面がわ」のこと。あなたの理解で合っています。ではなぜ全部襲ってくるか。理由は1つだけ。「素のHTML/CSS/JSだけで作ると、規模が大きくなったとき手に負えなくなる」から。その"手に負えなくなる場所"を1つずつ楽にするために、道具が1個ずつ増えていった。だから道具は問題ごとに1個あり、種類が多い=解決したい悩みが多い、というだけの話です。
道具を「1本の道」に並べる
あなたのコードが、書かれてから客の画面に映るまで。全部品はこの道のどこかの駅にいます。
HTML/CSS/JS/TS
React/Vue/Astro
Next/Nuxt/Astro
Vite/webpack
Vercel/Cloudflare
ブラウザ/CORS/認証
あなたが挙げた横文字を、この駅に振り分けたのが下の表です。「多すぎる」の正体は、1つの駅にライバル商品が何個も並んでいるだけ——どれか1つ選べば、その駅は片付きます。
| 駅(やること) | ここに並ぶ道具(ライバル同士) | あなたは何を使ってる? |
|---|---|---|
| 駅1 書く | HTML・CSS・JavaScript・TypeScript | これは全員必須。土台。 |
| 駅2 部品にする | React / Vue / Svelte / Solid | Astroが内蔵(素のHTMLに近い) |
| 駅3 組み立てる | Next.js / Nuxt / Astro | Astro |
| 見た目 | 素CSS / Sass / Tailwind / CSS-in-JS | 素CSS+一部Tailwind |
| 駅4 変換・圧縮 | Vite / webpack / Turbopack / esbuild | Astroが内部でViteを使用 |
| 荷造り | npm / yarn / pnpm / bun | npm |
| 駅5 配る | Vercel / Netlify / Cloudflare / Firebase | Cloudflare |
| 駅6 表示・安全 | ブラウザ対応・CORS・Cookie・認証 | 静的なので出番少なめ |
あなたは「静的サイト職人」です。Astroで前もってHTMLを焼き、Cloudflareで配る。この型を選んだ瞬間、あなたはこの本に出てくる横文字の7〜8割を「使わなくていい側」に置けます。Redux も Server Components も SSR も、あなたの日常には要りません。この本の目的は全部を"使えるようになる"ことではなく、「どれが自分に関係あって、どれは無視していいか」を見分けられるようになること。それだけで、叫びの大半は消えます。
「正解は1つじゃない」という大原則
あなたは何度も「どれが正解なの!? 何を選べば怒られないの!?」と叫びました。ここが一番の誤解です。フロントエンドに"唯一の正解"はありません。料理に唯一の正解がないのと同じです。あるのは「この場面ならこれが無難」という相場だけ。だから——
- 怒られません。どれを選んでも動きます。「間違い」ではなく「向き・不向き」があるだけ。
- 各駅には「迷ったらこれ」の無難な第一候補が実在します(この本の最後に早見表を付けます)。
- あなたはもうAstro+Cloudflareという、静的サイトでは"最も無難で強い"組み合わせを選び終えています。つまり選定はすでに正解済み。
横文字が多い=解決したい悩みが多いだけ。全部は「書く→部品→組み立て→変換→配る→表示」の1本道のどこかにいる。各駅はライバルが並ぶだけで、1つ選べば片付く。あなたは静的サイト職人=7〜8割は「無視していい側」。正解は1つじゃない、怒られない。
PART 1
土台 ― 君の直感は、ぜんぶ正しい
HTML・CSS・JavaScript・DOM・ブラウザ/ここは25年変わっていない
「HTML書いて、CSS当てて、ボタンで動く」で合ってる
「JavaScriptで画面作るだけじゃないの!? HTML書いて、CSS当てて、ボタン押したら動く、それでいいんじゃないの!?」
まず、これを声に出して言わせてください。あなたの直感は、1000%正しい。それが本当に土台で、25年前から今日まで一度も変わっていません。ReactもNextもTailwindも、全部この3つの上に乗っている"追加の便利道具"にすぎない。土台がぐらついているのではなく、土台の上に人が勝手に増築しただけです。
| 材料 | 役割 | あなたのbramleyでいうと |
|---|---|---|
| HTML | 構造・骨組み(何がどこにあるか) | 「Hero→About→Rooms」という並び |
| CSS | 見た目(色・フォント・余白・配置) | Zen Old Minchoの明朝・緑の差し色 |
| JavaScript | 動き(押す・スクロールで動く) | 起動アニメ・横長スライダー |
では、なぜこの3つだけじゃ足りなくなったのか
1ページの小さなサイトなら、本当にこの3つだけで完成します(あなたの座学ノートのHTMLがまさにそれ)。問題が起きるのはページが増え、動きが増え、同じ部品を何十回も使い回すようになったときです。素のJavaScriptで大きなアプリを作ると、こういう地獄が始まります。
- 「カートの数字」を、ヘッダー・商品欄・会計欄の3か所で手作業で書き換える。1か所忘れて表示がズレる。
- 同じ「ボタン」のデザインを、40ページにコピペ。1つ直すのに40回触る(あなたの旧・屋号サイトのナビがこれ)。
- どこで誰が画面を書き換えたか追えなくなる。
この「大きくなると手に負えない」を解決するために生まれたのが、次の部のReact/Vue/Svelteです。つまり——フレームワークは「素のJSの続き」であって、別物ではありません。あなたの出発点はそのまま正しく、その延長線上に全部が乗っています。
DOM ― この本で一番大事な4文字
後の章で何度も出るので、ここで一度だけ。DOM(ドム)=いまブラウザが表示している画面の、部品の一覧表です。あなたがHTMLを書くと、ブラウザはそれを読んで「見出しが1個、画像が1個、ボタンが1個…」という一覧を頭の中に作ります。これがDOM。
JavaScriptで「動き」をつけるとは、このDOMを書き換えることです。「ボタンを押したらメニューを開く」=JSがDOMの中のメニューを"表示"に書き換える。これだけ分かっていれば、後で出てくる「仮想DOM」「Shadow DOM」も、全部このDOMという一覧表の話だと見抜けます。
君の「HTML書いてCSS当ててボタンで動く」は完全に正しい。フレームワークは"素のJSが大きくなると壊れる問題"を直す延長で、別物じゃない。DOM=画面の部品リスト、JSはそれを書き換える。これだけ握れば残り全部が読める。
PART 2
フレームワーク戦争 ― React / Vue / Svelte / Solid
なぜ4つもある/JSX・className・コンポーネント・仮想DOMの正体
なぜフレームワークが生まれたか(1個の発明ですべて説明できる)
「なのにReactって何!? Vueって何!? Svelteって何!? Solidって何!? フレームワーク多すぎるよ! どれが正解なの!? 何を選べば怒られないの!?」
4つとも、やろうとしていることはまったく同じです。名前が4つあるだけで、発明は1個。その発明とは——「状態(データ)を書き換えたら、画面が自動でついてくる」という仕組みです。
素のJSの地獄 → その1個の解決
第1部の「カートの数字を3か所で手書き換え」を思い出してください。素のJSではデータと画面を人間が手でつなぐ。ここが全バグの巣でした。フレームワークはこれを逆さにします。
つまりフレームワークとの約束は1つだけ。「あなたはデータだけ書き換える。画面はこっちが合わせる」。React も Vue も Svelte も Solid も、この約束を実現する道具です。違うのは書き方の好みと、内部のやり方だけ。
| 名前 | 読み | キャラ(ざっくり) | 誰が使う |
|---|---|---|---|
| React | リアクト | 世界一の多数派。求人・情報・部品が最も多い。困ったら検索で必ず答えが出る | 迷ったらこれ。無難の代名詞 |
| Vue | ビュー | やさしい・読みやすい。HTMLに近い書き味。日本・中国で人気 | 学習ラクを重視する人 |
| Svelte | スベルト | 「フレームワークを消す」派。書いたコードを素のJSに焼き切るので軽い・速い | 速さ・軽さ重視の新しめ勢 |
| Solid | ソリッド | Reactそっくりの書き味で中身がもっと速い。玄人好み。少数派 | 性能を突き詰める人 |
「どれを選んでも怒られません。動きます。」それでも1つ挙げるなら——就職・案件・情報量で選ぶなら React。学びやすさなら Vue。ただしあなたの場合、答えはもっと上にあります。あなたは Astro を使っているので、この4つを"選ばなくていい"。Astroは普段このどれも使わず、素のHTMLに近い形で書けて、必要な所にだけReactやVueを"部品として招く"こともできる、という立ち位置だからです(第4部で詳しく)。だから今のあなたにとって、この戦争は観戦席から眺めていい戦争です。
JSX と className ― 「HTMLなの? JSなの?」問題
「JSXって何!? JavaScriptなの!? HTMLなの!? どっちなの!? classじゃなくてclassNameって何!? 似せるならちゃんと似せてよ!」
答え:JSXは「JavaScriptの中に、HTMLそっくりの見た目を直接書ける」書き方です。正体はJavaScript。でも見た目はHTML。だから「どっち?」は正しい疑問で、答えは「JavaScriptだけど、HTMLの顔をしている」。名前もそのまま——JS + XML(HTMLの親戚)=JSX。
なぜHTMLとJSを混ぜたのか
昔は「HTMLファイル」「JSファイル」を分けるのが正義でした。でも実際の部品——たとえば「ボタン」——は、見た目(HTML)と動き(JS)がセットで初めて意味を持つ。ファイルを分けると、1つのボタンが2か所に散らばって管理が面倒になる。そこでReactは「見た目と動きを1か所にまとめよう」と決めた。その"1か所"を書くための記法がJSXです。
{ } の中身だけがJavaScriptに戻る、という約束です。「HTMLの中に、波かっこで穴を開けてJSを流し込む」。これがJSXの9割です。
なぜ class じゃなく className なのか(似せきれなかった理由)
あなたの怒り「似せるならちゃんと似せてよ!」は完全に正論で、実は開発者たちも同じことをずっと言っています。理由はこうです。JSXの正体はJavaScript。ところがJavaScriptには、大昔から class という別の意味の予約語がすでに存在した(設計図を作る命令)。同じ部屋に同じ名前の人が2人いると混乱するので、HTMLの方の class を className に改名して衝突を避けた——それだけの、しょうもない歴史的事情です。
| ふつうのHTML | JSX(React) | なぜズラした |
|---|---|---|
class="box" | className="box" | JSの予約語 class と衝突するから |
for="id" | htmlFor="id" | JSの予約語 for(繰り返し)と衝突 |
onclick | onClick | JSの命名流儀(真ん中を大文字)に合わせた |
この className 問題はReactだけの方言です。VueやSvelte、そしてあなたのAstroでは、ふつうに class と書けます。つまり「似せてよ!」の被害に遭うのはReactを触るときだけ。Astro職人のあなたは、ほぼ無縁です。
コンポーネント ― 「じゃあコンポーネントじゃないものは何なの!?」
「コンポーネントって何がそんなに偉いの? ボタンもコンポーネント、カードもコンポーネント、ページもコンポーネントって、じゃあコンポーネントじゃないものは何なの!?」
この叫び、実はめちゃくちゃ鋭い。答えは——「その通り、ほとんど全部がコンポーネントです」。コンポーネント=名前をつけて使い回せるようにした、画面の部品。ボタンもカードもページも、大きさが違うだけで全部"部品"。これはあなたの全体像編で習ったAstroの「金型(1個作って着せ替える)」とまったく同じ話です。
「偉い」理由は1つ:直す場所が1か所になる
あなたは既にこの価値を体で知っています。旧・屋号サイトは「ナビが6ページにコピー」=直すのに6回。bramleyは Nav.astro という部品1個=直すのは1回。この「部品1個」がコンポーネントです。偉いのは賢いからではなく、「1回直せば全部に反映される」から人間が楽になる、ただそれだけ。
じゃあ「コンポーネントじゃないもの」は?
ちゃんと答えます。画面の部品でないもの——たとえば、
- ただの計算やデータ(「合計金額を出す関数」「客リストの配列」)。これは部品ではなく"中身・道具"。
- 設定ファイル(どのフォントを使うか等)。画面ではなく"取り決め"。
- スタイル(CSS)そのもの。部品に着せる"服"であって部品ではない。
つまり「目に見える四角い部品」=コンポーネント、「その裏で働くデータ・計算・設定」=コンポーネントじゃないもの。あなたの直感(ほぼ全部コンポーネント)は、見た目に関しては正しかったわけです。
React/Vue/Svelte/Solidは「データを変えたら画面が自動で追う」同じ発明の4バージョン。迷ったらReact、でもAstro勢は選ばなくていい。JSX=JSにHTMLを埋める記法、className=名前衝突の回避。コンポーネント=使い回す画面の部品=金型。全部あなたが既に知っている話だった。
PART 3
Reactの頭の中 ― フックと再レンダリング
useState/なぜ配列/再レンダリング/useMemo・useCallback/仮想DOM
useState ― 「なんで配列で返ってくるの!?」
「useStateって何!? 値を変えたいだけなのに、なんで配列で返ってくるの!?」
まず言葉。state(ステート)=状態=「今この画面が覚えておくべき値」。たとえば「カートの数:2」「メニューは開いてる?:はい」。useState=その"覚えておく値"を1個作る道具。第2部の「データを変えたら画面が自動で追う」の、その"データ"を作る係です。
なぜ2つセット(配列)で返るのか
useStateは、いつも「今の値」と「値を変えるボタン」の2点セットを渡してきます。これが配列に見える正体です。
なぜ「値を直接書き換える」じゃダメで、わざわざ変更係(setCount)を通すのか。ここが超重要です。Reactは「setCountが呼ばれた」という合図を見て、初めて画面を描き直すから。もし count = 3 と直接書き換えたら、値は変わってもReactは気づかず、画面が古いままになる。だから——
「値」と「変更を知らせるボタン」をセットで渡す=Reactに"変えたよ"と報告する義務を作っている。この報告があるから、画面が自動で追いつく。
あなたの「値を変えたいだけなのに」という感覚は自然です。でもReactにとっては「値を変える」と「画面に反映する」はワンセット。だから変更は必ずボタン(setCount)経由、という決まりになっています。
再レンダリング ― 「もう描いたじゃん! 何回描くの!?」
「再レンダリングって何!? もう描いたじゃん! 何回描くの!? 描きすぎると遅いって何!?」
レンダリング=「今の値から、画面の設計図を1枚作る」作業。再レンダリング=値が変わったので、設計図をもう1枚作り直すこと。答え:値が変わるたび、何回でも描き直します。それがフレームワークの仕事(第2部「画面は勝手に追いつく」)の正体です。
「何回描くの」→ 値が変わった回数だけ
カートの数が 0→1→2→3 と変われば、Reactは設計図を4回作り直します。これは無駄ではなく、"常に最新を映す"ための正しい動き。あなたが手で3か所書き換えていた地獄を、Reactが代わりに全部やり直してくれている、と考えてください。
「描きすぎると遅い」→ ここで仮想DOMが効く(大事)
ここで矛盾に気づきます。「毎回作り直したら、画面全体を毎回描き直して重いのでは?」——その通り。だからReactはズルをします。いきなり本物の画面を描き直さず、まず"下書き"を作って、前の下書きと見比べ、"変わった所だけ"本物に反映する。この下書きが次の項の仮想DOMです。
遅くなるのは「描く回数」より、1回の描き直しで"重い計算"を巻き込むとき。たとえば1万件のリストを毎回並べ替える、など。これを防ぐのが次の useMemo/useCallback です。あなたのような静的サイトでは、そもそもこの問題はほぼ起きません(画面がガンガン動き続けるアプリの悩み)。
useMemo / useCallback ― 「覚えておくって何!? 最初から忘れないでよ!」
「useMemoとかuseCallbackとか何なの!? 覚えておくって何!? じゃあ最初から忘れないでよ!」
前項の通り、Reactは値が変わるたび全部を作り直します。ということは——関係ない重い計算まで毎回やり直してしまう。useMemo/useCallback は、その無駄を止める道具。「この計算結果、材料が変わってないなら前回のを使い回して」と頼むメモ書きです。memo=メモ(記憶)、そのままの意味。
| 道具 | 何を覚えておく | 例え |
|---|---|---|
| useMemo | 重い計算の結果 | 毎回1から出汁を取らず、材料が同じなら昨日の出汁を使う |
| useCallback | 使い回す関数(手順)そのもの | 毎回レシピを書き直さず、同じレシピカードを使い回す |
「最初から忘れないでよ」への正直な答え
あなたのツッコミは正しい。理想を言えば、Reactが自動で「これは変わってないから使い回そう」と判断してくれるべき。そして実際、それが起きつつあります。2024年以降のReactには「React Compiler」という自動化が入り始め、useMemo/useCallbackを人間が手で書く必要は、これから減っていきます。あなたの「最初から忘れないでよ」は、React開発チームの目標そのものです。今はまだ過渡期で、手で書く場面が残っている——それだけ。
ほぼ無関係です。useMemo/useCallbackは「激しく動き続けるReactアプリ」の最適化テク。Astroで焼いた静的サイトには、そもそも動き続ける重い計算がありません。この2語は「そういう悩みがReactの世界にはある」と知っておくだけで十分。覚える必要はありません。
仮想DOM ― 「本物があるのに、なんで偽物を作るの!?」
「仮想DOMって何!? 本物のDOMがあるのに、なんで偽物を作るの!?」
第1部で「DOM=ブラウザが持つ画面の部品リスト(本物)」を習いました。仮想DOM=そのコピーを、Reactが自分の頭の中に持つ"下書き用のリスト"。偽物を作る理由はハッキリしています——本物のDOMの書き換えは"重い"から。
なぜ本物は重く、下書きは軽いのか
本物のDOMを書き換えると、ブラウザはそのたびに画面のレイアウトを計算し直して描画します(重い作業)。一方、下書き(仮想DOM)はただのメモなので、いくらいじっても軽い。そこでReactはこうします。
これで「値が変わるたび全部描き直す」ように見えて、実際に本物が書き換わるのは本当に変わった1か所だけ。前項の「描きすぎると遅い」を、Reactはこの仕組みで防いでいます。偽物を1枚はさむ方が、結果的に速い——これが仮想DOMの答えです。
Svelte(第2部)が「フレームワークを消す・軽い」と言われるのは、この仮想DOMすら使わないから。「どこが変わるか」を最初から計算して素のJSに焼くので、下書きの見比べが要らない。そしてAstroは、そもそも動かない部分に一切JSを送らないので、仮想DOMの出番自体がありません。あなたのサイトが速いのは、この「重い処理を最初から積まない」設計のおかげです。
useState=値+変更係のセット(報告義務で自動更新)。再レンダリング=値が変わるたび設計図を作り直す。useMemo/useCallback=無駄な計算を使い回すメモ(将来は自動化・あなたには無関係)。仮想DOM=下書きを見比べて変わった所だけ本物に反映する速さの工夫。全部「自動更新を速く保つ」ための道具立て。
PART 4
いつ・どこで・誰がHTMLを作るのか
CSR / SSR / SSG / ISR / Next・Nuxt・Astro / "use client"・Server Components
アルファベット3文字の正体(CSR / SSR / SSG / ISR)
「CSR、SSR、SSG、ISRって何!? アルファベット三文字ばっかり並べないでよ! いつ、どこで、誰がHTMLを作ってるの!?」
この4つはまったく同じ1つの質問への、4通りの答えです。その質問とは、あなたが自分で言った——「いつ・どこで・誰がHTMLを作るのか」。これ以上でも以下でもありません。全体像編で習った「静的 vs 動的」を、4段階に細かくしただけです。
| 3文字 | 読み下すと | いつHTMLを作る | どこで作る | あなたの弁当で例えると |
|---|---|---|---|---|
| SSG | 静的サイト生成 (Static Site Generation) | 公開前に前もって(1回) | あなたのPC/ビルド時 | 作り置き弁当を棚に並べる |
| SSR | サーバー側生成 (Server-Side Rendering) | 客が開いたその瞬間(毎回) | サーバー | 注文が来てから厨房で作る |
| CSR | クライアント側生成 (Client-Side Rendering) | 客のブラウザに届いてから | 客のブラウザ(スマホ) | 材料キットを渡し、客が自宅で調理 |
| ISR | 増分・静的再生成 (Incremental Static Regeneration) | 基本は作り置き+たまに作り直す | サーバー(時間で自動) | 作り置き弁当を、一定時間ごとに作り直す |
1枚の図で「誰が作るか」を掴む
bramleyもbrownaも、Astroで前もってHTMLを焼くSSGです。だから全体像編で習った「速い・ほぼ無料・壊れにくい」が実現している。あなたにとって重要なのはSSGだけ。SSR/CSR/ISRは「そういう別方式があって、それぞれサーバー代や速度の代償を払う」と知っておけば十分で、あなたの型では使いません。3文字に怯える必要はなく、あなたは既に一番いい席に座っています。
あなたのtabiato(田舎家一の共有部屋アプリ)のように「みんなの投稿がリアルタイムで増える」ものは、作り置き(SSG)だけでは古くなる。だからtabiatoはCloudflareのD1(データ置き場)から中身を取ってくる作り=CSR寄りの動的です。「見せるだけのサイト=SSG」「みんなで書き換えるアプリ=動的」——この線引きが、あなたが案件ごとに方式を選ぶ判断軸になります。
Next.js / Nuxt / Astro ― 「組み立て工場」の三択
「Next.jsって何!? Nuxtって何!? Astroって何!? フレームワーク多すぎるよ!」
第2部のReact/Vueは「部品を作る道具」でした。こちらはその1つ上の階層——部品を集めて"サイト全部"に組み立てる工場です。ルーティング(URLとページの対応)、上の4方式(SSG/SSRなど)の切り替え、画像の最適化などを丸ごと引き受ける。これを「メタフレームワーク(フレームワークのフレームワーク)」と呼びます。
| 工場 | 読み | 土台の部品道具 | ひとことキャラ |
|---|---|---|---|
| Next.js | ネクスト | React | 王者。Reactで本格的なサイト/アプリを作る定番。多機能で重厚 |
| Nuxt | ナクスト | Vue | NextのVue版。やさしい書き味のまま本格運用 |
| Astro | アストロ | どれでも可(無くても可) | 「見せるサイト」特化。JSを極力送らず速い。あなたの相棒 |
なぜあなたはAstroなのか(ここが芯)
NextやNuxtは「動きまくるアプリ(SNS・管理画面・EC)」まで想定した重装備。多機能な代わりに、放っておくと客のスマホに大量のJavaScriptを送りつけて重くなる。一方Astroは思想が真逆で、「基本、JSを1バイトも送らない。動きが要る所にだけ足す」。だから——
- あなたが作る「見せるための美しいサイト」に最適(宿・店・作品サイト)。
- 速くて軽く、SSGと相性抜群=Cloudflareでほぼ無料配信。
- 必要なら「この地図だけReactで」と部分的に動きを招ける("アイランド"という考え方)。
「地方の店を20〜30社、二人で保守する」なら、重いNextを選ぶと保守が破綻します。軽いAstro+静的+Cloudflareを全客で貫く——これは全体像編の第2章で出た事業の生命線で、この工場選びはその実装です。あなたはNext/Nuxtを「知っておくが使わない」でよい。
"use client" と Server Components ― 「なんでサーバーが出てくるの!?」
「"use client"って何!? フロントエンドの話をしてるのに、なんでサーバーが出てくるの!? Server Componentsって何!? クライアントなの!? サーバーなの!? どっちで動いてるの!?」
これは今のフロントエンドで一番ややこしく、一番新しい話です。だから混乱して当然。結論を先に:これはNext.jsなど"最新の一部"だけの話で、あなたのAstroにも、世の中の大半のサイトにも関係ありません。安心した上で、正体だけ掴みましょう。
なぜサーバーが出てくるのか
きっかけは第3部の反省です。「全部を客のスマホ(クライアント)でJSで組み立てるCSR」は、最初の表示が遅く、スマホに負担が重い。そこで新しいReact/Nextはこう考えた——「動く必要のない部品は、サーバー側で先に作って、完成品だけ送ればいい。動く部品だけスマホで動かそう」。この「部品ごとに、作る場所を分ける」発想が Server Components です。
| 種類 | どこで動く | 向いてる部品 | 合図 |
|---|---|---|---|
| Server Component (既定) | サーバー側(客に届く前) | 動かない表示(記事本文・商品説明)。データ置き場に直接アクセスできる | 何も書かない=これ |
| Client Component | 客のブラウザ側 | 押す・入力する・動く部品(ボタン・フォーム) | ファイル先頭に "use client" と書く |
つまり "use client" は「この部品は客のブラウザで動かしてね」という付箋。書かなければ「サーバーで作る部品」。1つの画面が、サーバー製の部品とブラウザ製の部品の寄せ集めになる——だから「どっち?」の答えは「部品ごとに違う。両方が協力して1画面を作っている」です。
この仕組みは難しく、まだ発展途上で、プロの間でも「複雑すぎる」と議論が続いています。あなたは丸ごと飛ばして構いません。Astroには"use client"はなく、代わりに「動かす部品には client:load と印をつける」という、もっと素直な同じ発想があります。要点だけ持ち帰れば十分:「動かない部品は先に作って軽くする。動く部品にだけ印をつける」——これが2020年代の共通トレンド、それだけ知っていればOK。
CSR/SSR/SSG/ISRは「いつ・どこでHTMLを作るか」の4択で、あなたはSSG。Next/Nuxt/Astroは組み立て工場で、あなたはAstro。"use client"/Server Componentsは「動く部品だけブラウザ、動かない部品はサーバーで先に」という最新トレンドだが、Astro職人は飛ばしてよい。どの節も結論は同じ——あなたの型は、この巨大な選択肢群の中で一番シンプルで強い。
PART 5
見た目の付け方の戦争 ― CSSまわり
素CSS / Modules / Sass / PostCSS / Tailwind / CSS-in-JS / UIライブラリ / shadcn/ui
CSSの流派 ― 「普通のCSSでいいじゃん!」
「CSSもわかんないよ! 普通のCSSでいいじゃん! なのにCSS Modules、Sass、PostCSS、Tailwind、CSS-in-JSって何!?」
また同じ構造です。全部「CSSを書く」という1つの仕事の、書き方バリエーション。そして「普通のCSSでいいじゃん」は、小〜中規模では本当に正解。あなたの座学ノートも普通のCSSで書かれていて、何も問題ありません。流派が生まれた理由は、たった1つの持病を治すためです。
普通のCSSの唯一の持病:「名前がぶつかる」
CSSは、書いた飾りがページ全体に効いてしまう。だから大規模になると、Aさんが作った .title と、Bさんの .title がぶつかって、片方の見た目が壊れる。この事故を防ぐための工夫が、各流派の正体です。
| 流派 | 読み | 何を足した | 持病への効き目 |
|---|---|---|---|
| 素のCSS | — | 何も足さない。土台そのもの | 小規模なら十分。名前だけ気をつける |
| Sass | サス | CSSに「入れ子・変数・使い回し」を足した上位版 | 書くのが楽になる(名前衝突は別途注意) |
| CSS Modules | — | クラス名を自動でユニーク化(裏で title_x7f2 に変換) | 名前衝突を機械的に根絶 |
| PostCSS | ポストシーエスエス | CSSを自動で加工する裏方(後述の"変換"の一種) | 古いブラウザ対応などを自動化 |
| Tailwind | テイルウィンド | 短い部品クラスを組み合わせて書く方式(次項) | そもそもCSSを別ファイルに書かない=衝突しない |
| CSS-in-JS | — | JSファイルの中にCSSを直接書く(React系で流行) | 部品とスタイルが常にセット=衝突しない |
あなたは素のCSS+一部Tailwindで回っていて、それで完全に正解です。SassやCSS Modulesは「あれば便利」程度、CSS-in-JSはReact世界の作法でAstro職人には不要。PostCSSはあなたが意識せずとも裏で勝手に動いている裏方(Tailwindの中身がPostCSSでできている)。つまりあなたが選ぶべきは「素CSSか、Tailwindか」の2択だけ。残りは無視してよい。
Tailwind ― 「flex items-center px-4 py-2って呪文じゃん!」
「flex items-center justify-between gap-2 px-4 py-2って何!? 呪文じゃん! 昔はHTMLにクラスいっぱい書くなって言ってたのに、今はそれが正義って何!? 方針変えないでよ!」
その"呪文"、実は1個ずつはただのCSSの短縮形です。魔法でも新概念でもない。あなたが今まで書いてきたCSSに、あだ名をつけて直接HTMLに貼っているだけ。翻訳表を見れば一瞬で解けます。
| Tailwindの呪文 | あなたが知ってる素のCSS | 意味 |
|---|---|---|
flex | display: flex; | 横並びにする |
items-center | align-items: center; | 縦方向の中央ぞろえ |
justify-between | justify-content: space-between; | 両端に寄せて間を空ける |
gap-2 | gap: 8px; | 部品同士の隙間(2=8px) |
px-4 | padding-left/right: 16px; | 左右の内側余白 |
py-2 | padding-top/bottom: 8px; | 上下の内側余白 |
「flex items-center justify-between gap-2 px-4 py-2」を翻訳すると——「横並び・縦中央・両端寄せ・隙間8px・左右余白16px・上下余白8px」。あなたが普段CSSでやっていることそのままです。呪文の正体はただの略語の連続でした。
「方針変えないでよ」への、正直な歴史の説明
あなたの怒りは100%正当です。実際に方針は変わりました。順を追うと:
- 昔の教え:「見た目(CSS)と構造(HTML)は分けろ。HTMLにスタイルを書くな」。理由は"分けた方が整理される"という理想。
- 現実に起きたこと:分けたら分けたで、CSSファイルが巨大になり、「このクラス、まだどこかで使われてる?消していい?」が誰にも分からなくなった。触るのが怖いCSSが積み上がった。
- Tailwindの主張:「分けた理想より、見た目と構造が同じ場所にある方が、実際は直しやすい」。部品を見れば飾りも全部そこにある=迷子にならない。
つまり「理想(分ける)」から「実利(一緒にある方が直せる)」へ、現場が方針転換したのです。どちらが絶対正解でもなく、今も両派は共存しています。あなたが「昔と違う」と感じたのは気のせいではなく、業界が実際に学習して考えを変えた記録です。
どっちでもいいし、混ぜてもいい。あなたのように「1枚1枚の見た目にこだわる作品的サイト」なら、素のCSSでじっくり作るのは全く正しい。一方、同じ部品を量産する客サイトでは、Tailwindの「その場で組んで即確認」が効きます。怒られる選択はありません。この座学ノート自体は素のCSSで美しく書けている——それが何よりの証拠です。
UIライブラリ ― 「頭がないUIって何!?」
「UIライブラリも多すぎるよ! MUI? Chakra? Mantine? Radix? Headless UI? 頭がないUIって何!?」
UIライブラリ=「よく使う部品(ボタン・メニュー・カレンダー・モーダル)の、出来合いの詰め合わせ」。毎回ゼロから作らず、棚から出して使う。多いのは、その詰め合わせの「見た目の完成度」と「自由度」のバランス違いがあるからです。
| ライブラリ | タイプ | 特徴 |
|---|---|---|
| MUI(Material UI) | 見た目つき | Googleのデザインを再現。すぐ"それっぽく"なる。ただし全部Google顔になる |
| Chakra / Mantine | 見た目つき | MUIより素直で今風。カスタムしやすい詰め合わせ |
| Radix / Headless UI | 頭(見た目)なし | 見た目を一切持たず、"動きと使いやすさ"だけ提供。デザインは自分で全部当てる |
「頭がないUI(ヘッドレス)」の正体
全体像編でmicroCMSを「ヘッドレスCMS=見た目を持たず中身だけ渡す」と習いました。まったく同じ"ヘッドレス"です。ここでの「頭(head)」=見た目。「頭がないUI」=見た目ゼロで、中身の機能だけを持つ部品。
なぜ見た目を捨てるのが人気なのか。ボタンやメニューには、実は目に見えない難しさが詰まっています——キーボードだけで操作できるか、読み上げソフトで意味が伝わるか、モーダルを開くと背後がスクロールしないか(これがアクセシビリティ/第11部)。この"面倒で間違えやすい部分"だけを完璧に用意し、見た目は真っさらで渡す。すると開発者は、自分のデザインを1から当てつつ、難しい部分はタダで手に入る。だから「頭がない」ことが逆に価値になる。
ほぼReact世界の道具で、Astroの静的サイトでは出番が少なめ。ただしRadixやHeadless UIの発想——「機能は借りて、見た目は自分の世界観で作る」——は、まさにあなたが客ごとに世界観を作り分ける仕事と相性がいい。「見た目つき(MUI)=早いが没個性、頭なし(Radix)=手間だが自分の世界観を保てる」という軸だけ覚えておけば十分です。
shadcn/ui ― 「インストールしたのに自分のコードになるって何!?」
「shadcn/uiはライブラリじゃないって何!? インストールしたのに自分のコードになるって何!? ライブラリなの!? テンプレなの!? 部品取りなの!? アップデートはどうするの!? 自分で面倒を見るって何!?」
これは新しくて紛らわしい発明なので、混乱は正常です。一言で言うと——shadcn/uiは「ライブラリ」ではなく「部品のコピー配布所」。あなたの直感の3択のうち、「部品取り」が一番近いです。
普通のライブラリとの決定的な違い
| 普通のライブラリ(MUI等) | shadcn/ui | |
|---|---|---|
| 入れると | 他人の部品が node_modules(第7部)に"外部の荷物"として入る | 部品のソースコードが、あなたのフォルダに直接コピーされる |
| 持ち主 | 作者。あなたは借りているだけ | あなた。コピーされた瞬間あなたの物 |
| 改造 | 基本いじれない(借り物だから) | 好きに書き換えてよい(自分の物だから) |
| 更新 | 作者が新版を出す→あなたが入れ替える(自動的) | 自動では来ない。自分で見て取り込む |
「インストールしたのに自分のコードになる」=入れる操作が"ダウンロード"ではなく"あなたのフォルダへのコピー&ペースト"だから。レシピ本を借りるのではなく、レシピを自分のノートに書き写して、あとは自由に改変する——これがshadcn/uiのモデルです。中身はさっきのRadix(頭なし)に、きれいな見た目を当てた状態でコピーされます。
「アップデートは? 自分で面倒を見る?」への答え
その通りで、ここが唯一の代償です。自分の物になった=作者の自動更新は届かない。だから改良版が出たらあなたが手で取り込む。ただし多くの場合これは利点です:勝手に更新されて見た目が突然変わる事故が起きない。あなたが「デザインを置き換えたら意図せず作り直されて外した」と過去に苦い思いをしたのと逆で、shadcnは"勝手に変わらない安心"を選んでいます。
ライブラリ(借りる・自動更新・改造不可)か、shadcn型(もらう・手動更新・改造自由)か。この違いさえ掴めば、「これはどっち方式?」と一言聞けば済みます。shadcnは主にReact/Next向けで、Astroでも使えますが必須ではありません。「そういう新しい配り方がある」と知っておけば十分。
CSSの流派は全部「名前衝突の持病」対策、あなたは素CSS+一部Tailwindで正解。Tailwindの呪文はCSSの略語、方針転換は"直しやすさ"を選んだ結果で両派共存。UIライブラリは部品詰め合わせ、ヘッドレス=見た目なしで機能だけ。shadcnは"コピーして自分の物にする"新方式。どれもReact世界寄りで、あなたは選択肢を知るだけでよい。
PART 6
状態管理の戦争 ― Redux / Zustand / Jotai / Recoil / Valtio
なぜ5つもある/そしてなぜ、あなたには1つも要らないのか
「多すぎるよ!」——でも、あなたはゼロでいい
「状態管理もわかんないよ! Redux? Zustand? Jotai? Recoil? Valtio? 多すぎるよ!」
第3部で「state=画面が覚えておく値」を習いました。状態管理ライブラリ=そのstateが、アプリ中に散らばって手に負えなくなったときの"整理棚"。5つあるのは、整理の流儀違いです。そして先に結論——これは"大きなアプリ"だけの悩みで、あなたには1つも要りません。
なぜ整理棚が要るのか(バケツリレー地獄)
stateは、それを作った部品の中だけで有効です。ところが「ログイン中のユーザー名」のようにアプリの隅々で使いたい値があると、部品から部品へ手渡しで延々とバケツリレーすることになる。10階層下の部品に届けるのに、間の9個の部品が全員バケツを持たされる。これが地獄。
この「みんなが見られる共有の棚」を提供するのが状態管理ライブラリ。5つの違いは、棚の作りの好みだけです。
| 名前 | 読み | キャラ |
|---|---|---|
| Redux | リダックス | 元祖・最も厳格。ルールが多く重厚。大規模の定番だが書く量が多い |
| Zustand | ツースタンド | 今の人気者。軽くて素直。「Reduxは大げさ」への回答 |
| Jotai / Recoil | ジョウタイ/リコイル | 小さな値を"粒"で管理する派(Jotaiは日本語の「状態」が名前) |
| Valtio | バルティオ | 「普通の変数みたいに書き換えるだけ」を目指す派 |
Reduxが厳格すぎて疲れた人たちが、次々と「もっと楽な棚」を作った——それが5つに増えた歴史です。つまり多さは"Reduxへの不満の数"。今から選ぶなら軽いZustandが無難、とだけ知っておけば十分。
整理棚が要るのは「大量のstateが画面中を飛び交う、動きっぱなしのアプリ」(SNS・管理画面・EC)だけ。あなたのAstro静的サイトは、そもそもstateがほとんどありません(見せるだけだから)。だからこの5つは、あなたの人生に一度も登場しなくて大丈夫。tabiatoのように動的な案件でも、CloudflareのD1(データ置き場)が"共有の棚"の役目を果たすので、これらは不要です。「状態管理ライブラリ=大きなReactアプリの整理棚」と一行だけ覚えて、あとは忘れてよい。
状態管理ライブラリ=散らばったstateを「みんなが見られる共有の棚」に集める道具。バケツリレー地獄を防ぐ。5つの多さ=元祖Reduxへの不満の数で、今ならZustandが無難。ただし静的サイトのあなたにはstate自体がほぼ無く、1つも要らない。
PART 7
道具箱 ― 変換と配達の裏方たち
ビルドツール / Babel / npm・yarn・pnpm・bun / node_modules / ESM・CommonJS
なぜ「ビルド(変換)」が要るのか ― 全ての前提
この部の道具は全部「裏方」で、あなたが直接触ることはまずありません(Astroが中で勝手に使う)。でも名前だけは襲ってくるので、正体を1枚で押さえます。まず大前提——あなたが書いたコードは、そのままではブラウザで動きません。だから「変換(ビルド)」という工程が挟まります。
変換の中身は主に3つ。この3つを担う道具の名前が、あなたを襲った横文字たちです。
- トランスパイル(翻訳):最新JSやTypeScriptを、古いブラウザでも動く昔のJSに書き直す。担当=Babel・SWC。
- バンドル(荷造り):何百個に分かれたファイルを、配りやすいよう少数にまとめる。担当=webpack・Rollup・esbuild・Rspack。
- この2つを束ねた総合窓口:担当=Vite・Turbopack(開発中のプレビューも速くする)。
ビルドツール ― Webpack / Vite / Turbopack / Rspack / Rollup / esbuild / SWC
「ビルドツールもわかんないよ! Webpackで覚えたのに、Viteが速いって何!? Vite+まで出てきたらしいじゃん!? Turbopack? Rspack? Rollup? esbuild? SWC? なにが違うの!」
全部「さっきの変換をやる道具」で、違いは実質「新しいか、速いか」だけ。歴史は"同じことをもっと速く"の一本道です。名前の洪水は、その世代交代の記録にすぎません。
| 名前 | 読み | 世代/速さ | 正体 |
|---|---|---|---|
| webpack | ウェブパック | 旧世代・遅いが実績No.1 | 長年の定番。多機能だが設定が複雑で遅い |
| Rollup | ロールアップ | 中堅 | ライブラリ作りで人気の荷造り屋。Viteが中で使う |
| esbuild | イービルド | 爆速 | Go言語製で桁違いに速い変換エンジン。Viteが中で使う |
| SWC | スワック | 爆速 | Rust製の翻訳エンジン。Babelの高速な代役。Next等が採用 |
| Vite | ヴィート | 現在の主役 | esbuild+Rollupを束ねた総合窓口。速くて設定が楽。Astroの中身もこれ |
| Turbopack | ターボパック | 次世代(Next用) | webpackの作者がRustで作り直した後継。主にNext.js向け |
| Rspack | アールスパック | 次世代 | webpackをRustで作り直した高速版(webpackの設定を活かせる) |
ポイントは1つ。「速い新型」は、たいてい古い定番をGoやRust(速い言語)で作り直したもの。webpack→Rspack、Babel→SWC、というように"中身は同じ仕事・エンジンだけ高速化"。だからあなたが機能を覚え直す必要はゼロ。速くなっただけです。
あなたが触るビルドツールは、実質1つもありません。Astroが内部でViteを使い、そのViteが中でesbuildやRollupを呼ぶ——全部自動。「Vite+」はViteチームが有料の追加サービス群(クラウド連携など)に付けている新ブランドで、個人が静的サイトを作る分には無縁。この表は「AstroのエンジンはViteで、それは速い部類」とだけ分かれば十分。残りの名前は読み方だけ知っていれば、会話で怯えずに済みます。
Babel ― 「もういらないって言うのに、設定に出てくるの何!?」
「Babelはもういらないって言うのに、設定ファイルに出てくるの何!? いるの!? いらないの!? どっちなの!?」
Babel(バベル)=元祖の"翻訳屋"。最新JSを古いブラウザ向けに書き直す仕事を、長年ひとりで担ってきた功労者です。「もういらない」と言われるのは、前項のSWCやesbuildが、同じ仕事をもっと速くやるようになったから。世代交代で主役の座を譲りつつある——それが"いらない"の意味。
でも「設定に出てくる」のも本当。理由は2つ。①長年の資産:世界中の古いプロジェクトがBabel前提で作られていて、まだ現役。②細かい特殊技:SWCが未対応の特殊な変換を、今もBabelだけが担える場面がある。だから答えは——「新規で自分から選ぶ必要はない(いらない)。でも既存プロジェクトや一部機能では今も動いている(いる)」。両方本当、というのが正直な現状です。
Astroは翻訳に高速なesbuild/SWC系を使うので、あなたのプロジェクトにBabelはほぼ登場しません。もし設定ファイルで名前を見かけても、それは裏方が勝手に置いた物で、あなたが触る必要はありません。
npm / yarn / pnpm / bun と node_modules ― 「知らない人のコードが千個入ってくる」
「npmもわかんないよ! npm、yarn、pnpm、bunって何個あるの!? lockfile増やさないでよ! node_modules重すぎるよ! ボタン一個出したいだけなのに、知らない人のコードが千個入ってくるの怖いよ!」
パッケージマネージャ=「他人が作った部品(パッケージ)を、ネットから取ってきて揃える"買い出し係"」。4つあるのは、買い出しの速さと省スペースの改良版が次々出たから。仕事は全部同じです。
| 名前 | 読み | キャラ |
|---|---|---|
| npm | エヌピーエム | 純正・標準装備。Node(JSの土台)に最初から入っている。無難 |
| yarn | ヤーン | 「npmが遅い」時代の高速化版。今はnpmも速くなり役目は縮小 |
| pnpm | ピーエヌピーエム | 同じ部品を使い回してディスクを節約する賢い版。今の玄人人気 |
| bun | バン | 買い出し+実行+変換まで全部入りの超新型。爆速だが新しめ |
「知らない人のコードが千個」=ライブラリの連鎖(正しい恐怖)
この恐怖はまっとうな感覚です。仕組みはこう:あなたが部品Aを1つ入れると、Aも別の部品Bに頼っていて、Bも部品Cに頼っている…と連鎖する。結果、1個入れたつもりが数百〜千個の他人のコードが芋づる式に入る。それらが詰まる倉庫が node_modules(ノードモジュールズ)で、重いのはこの芋づるを全部保管しているから。
lockfile ― 「増やさないでよ!」の正体と、実は味方な話
lockfile(ロックファイル。package-lock.json 等)=「今回入れた数百個の部品の、正確なバージョンを1個残らず記録した名簿」。増えるのは邪魔に見えて、実はあなたの命綱です。これが無いと、明日別のPCで買い出しした時に部品のバージョンが微妙にズレて"昨日動いたのに今日動かない"が起きる。lockfileは「全員がまったく同じ部品で揃う」ことを保証します。だから消さない・GitHubに一緒に保管するのが鉄則。名簿が各買い出し係で名前違い(package-lock.json/yarn.lock/pnpm-lock.yaml/bun.lockb)なので、「買い出し係は1プロジェクトで1つに統一」すればlockfileも1つで済み、あなたの「増やさないで」も守れます。
あなたのプロジェクトはnpmで統一されていて(package-lock.json が各リポジトリにある)、それで完全に正解。yarn/pnpm/bunに乗り換える必要はありません。node_modulesの重さは、GitHubには送らない設定(.gitignore)で手元だけに置くのが定石なので、保管庫は汚れません。「買い出し係はnpm、名簿は消さない」——この2点だけ守れば、この節の恐怖は無害化します。
npm audit ― 「怒られるし、直したら壊れるし、放置したら危ないって何!?」
「npm auditしたら怒られるし、直したら壊れるし、放置したら危ないって何!? じゃあどうすればいいの!?」
npm audit(オーディット=監査)=「集めた数百個の部品の中に、危険が見つかった物はない?」を自動チェックする健康診断。「怒られる」のは、その芋づるの奥の方の部品に既知の弱点(脆弱性)が見つかると警告が出るから。
厄介なのは、警告の多くが「あなたが直接選んだ部品」ではなく、その奥にある"部品の部品の部品"にあること。だから自分では直しようがなく、無理に自動修正(npm audit fix --force)をかけると他の部品との噛み合わせが狂って壊れる。あなたの「直したら壊れる」はこれです。冷静な対処はこう:
| 状況 | どうする |
|---|---|
| 警告が出た | まず慌てない。多くは「奥の部品の理論上の弱点」で、静的サイトには実害が及ばないものが大半 |
| それは本当に危ない? | 警告の"深刻度"を見る。high/critical で、かつ「客が触る入力」に関わる物だけ本気で対処 |
| 直す | --force は使わず、その部品の作者が出す正式な新版を待って入れ替える。判断はClaudeに任せてよい |
| 静的サイトなら | そもそもサーバーが無く攻撃面が小さいので、実被害は極めて起きにくい |
npm auditの警告は「即・全部直す」ものではありません。深刻度と、それが本当にあなたのサイトに影響するかを見て、影響する物だけ対処する——この判断はClaudeに丸投げしてよい領域です。あなたは「警告=即・世界の終わり、ではない」とだけ知っておけば、怖がらずに済みます。
ESM と CommonJS ― 「importでいいじゃん! requireもいいじゃん! 仲良くしてよ!」
「ESMとCommonJSもわかんないよ! importでいいじゃん! requireもいいじゃん! 仲良くしてよ!」
2つとも「別のファイルから部品を呼び出す書き方」で、やることは同じ。方言が2つあるだけです。あなたの「どっちでもいいじゃん」は本質を突いていて、実際どちらでも部品は呼べます。違いは"世代"。
| CommonJS(旧) | ESM(新・標準) | |
|---|---|---|
| 呼び出す | const x = require("...") | import x from "..." |
| 渡す | module.exports = x | export default x |
| 生まれ | 昔のNode(サーバー)用に作られた方言 | ブラウザも含む世界の公式標準 |
| 今の立場 | 古い資産で今も大量に現役 | これからの正解。import 側 |
なぜ仲が悪いか。ブラウザは昔から require を理解できず、Nodeは昔 import を理解できなかった。育った家が違うので方言が分かれ、混ぜると「この部品、どっちの言葉で呼べばいいの?」という噛み合わせ事故が起きる。今はESM(import)に世界が統一されつつあり、仲直りの最中です。あなたの「仲良くして」は、まさに今進行中。
ほぼゼロ。Astroは新しい標準(ESM=import)で書くので、あなたやClaudeが書くコードは import 一択で統一されます。require を見かけるのは古い部品の中だけで、それはビルドツール(第7部-B)が裏で吸収してくれる。あなたは「新しい方は import」とだけ覚えておけば十分です。
この部の道具は全部「変換と配達」の裏方で、あなたは直接触らない。ビルドツールの多さ="同じ仕事をもっと速く"の世代交代(Astroの中身はVite)。Babelは主役交代中で両方本当。npm系は買い出し係でnpmで十分、node_modulesの重さ=芋づる、lockfileは消さない命綱。npm auditは慌てず深刻度で判断(Claudeに任せる)。import/requireはimportに統一中。恐怖の9割は「裏方が勝手にやる」で消える。
PART 8
ブラウザという現実 ― 同じWebなのに、なぜ壊れる
Chrome / Safari / iOS Safari の違い / CORS
ブラウザ差 ― 「Chromeで動いたのにSafariで壊れるって何!?」
「ブラウザ対応もわかんないよ! Chromeで動いたのにSafariで壊れるって何!? 同じWebじゃないの!? iOS Safariだけ壊れるって何!?」
「同じWebじゃないの」——気持ちは分かりますが、ここが現実の壁です。Webのルール(HTML/CSS/JSの仕様)は1つ。でも、それを"読んで実行するアプリ"=ブラウザは、会社ごとに別々に作られている。Chrome(Google)、Safari(Apple)、Firefox(Mozilla)…。同じ楽譜でも演奏する楽団が違えば、微妙に音が変わる。それがブラウザ差です。
| ブラウザ | 作った会社 | クセ |
|---|---|---|
| Chrome / Edge | Google(Chromium) | 世界最大シェア。新機能をいち早く入れる。開発者はまずここで確認 |
| Safari(Mac) | Apple | 新機能の採用が慎重で遅め。独自のクセがある |
| iOS Safari(iPhone) | Apple | 要注意の主犯。iPhoneの全ブラウザは中身が強制的にSafari。ここだけ挙動が違う |
なぜ「iOS Safariだけ」壊れるのか
あなたのこの観察は鋭い。理由はAppleのルールにあります。iPhoneでは、たとえChromeアプリを入れても、中身は強制的にSafariのエンジンで動く(Appleがそう決めている)。だから「iPhoneのChromeでは動くのにiPhoneのSafariでは…」ではなく、iPhoneは全部Safari。しかもそのSafariが他ブラウザと挙動が違うので、「PC・Androidでは平気、iPhoneだけ崩れる」が起きる。よくある崩れどころ:
- 画面の高さ計算(
100vh)が、アドレスバーの伸縮でズレる(iOS名物)。 - 最新CSS機能の対応が一歩遅く、Chromeで使えた飾りがSafariで無視される。
- 日付の扱いや、動画の自動再生のルールが厳しめ。
プロも「1回で全ブラウザ完璧」は無理で、対処は1つ——「作ったら実機で見る」。特にiPhone。あなたはメモリにも残っている通り「スマホ必ず確認」を鉄則にしていて、それがまさにこの問題の唯一の正解です。tabiatoやbramleyを実際のiPhoneで開いて確認する——この習慣が、ブラウザ差の9割を防ぎます。残りの細かい崩れ(100vh等)は既知の"定番の直し方"があるので、Claudeが対応できます。
CORS ― 「許していいの? 悪いの!? ダメならダメって言ってよ!」
「CORSって何!? 許していいの? 悪いの!? ダメならダメって言ってよ!」
CORS(コルス)=「あるサイトのページが、"別のサイト"のデータを勝手に取りにいくのを、ブラウザが止める安全装置」。エラーに見えて、正体はあなたを守るための警備員です。だから「悪いもの」ではなく、「初期設定が厳しめの、味方の門番」。
なぜ止めるのか(あなたを守る理屈)
もしこの門番がいなかったら——あなたが銀行サイトにログイン中に、たまたま開いた怪しいサイトのJavaScriptが、あなたの銀行データを裏でこっそり読み取れてしまう。それを防ぐため、ブラウザは「ページと、そのページが読みにいく先のサイトが"別のドメイン"だったら、まず止める」という規則を持っています。これがCORS。
「許していいの?」への、はっきりした答え
ダメならダメと言います。許可を出すのは、あなた(取りに行く側)ではなく、"取りに行かれる側のサーバー"の設定です。だから——
- あなたが自分で両方のサーバーを持っているなら:「このサイトからのアクセスはOK」と自分で許可設定を書けばよい(安全)。
- 他人のサービス(外部API)を使うなら:そのサービスが許可を出す仕組み(APIキー等)に従う。勝手には通れない(それが正しい)。
- やってはいけないこと:「全世界からのアクセスを無条件で許可(
*)」を、ログインや個人情報が絡む所で使うこと。これは門番を撤去するのと同じで危険。
CORSに悩むのは「ページが外部サーバーからデータを取ってくる」動的な作りのとき。あなたの静的サイト(見せるだけ)は、そもそも外部からデータを取りに行かないので、CORSエラーはまず出ません。tabiatoのようにCloudflareのD1と通信する場合は、同じCloudflare内で完結するよう組むことでCORSの門番を最初から発生させない——という設計をClaude側で選べます。あなたは「CORS=別サイトへの取得を止める味方の門番。許可は"取られる側"が出す」とだけ知っていればOK。
ブラウザは会社ごとに別アプリだから同じWebでもクセが出る。iPhoneは全部Safari中身なので「iOSだけ壊れる」が起きる→対処は実機確認(あなたの鉄則で正しい)。CORSはエラーではなく「別サイトへの取得を止める味方の門番」で、許可は取られる側が出す。どちらも静的サイトのあなたには軽い話。
PART 9
ログインと安全 ― 単語が強すぎる世界
Cookie / Session / JWT / OAuth / OIDC / PKCE / 置き場問題 / XSS・CSRF
ログインの仕組み ― 「単語が強すぎるよ!」
「認証もわかんないよ! Cookie、Session、JWT、OAuth、OIDC、PKCEって何!? ログインさせたいだけなのに単語が強すぎるよ!」
単語は強そうですが、全部たった1つの問題を解くための道具です。その問題とは——「ログインは一瞬。でもその後の全ページで"さっきの人と同じ人だ"とどう証明し続けるか」。Webは基本、1ページ見るごとに相手を忘れる仕組みなので、この"覚えておく手段"が必要になる。それが認証の全て。
| 言葉 | 読み | 役割(一言) |
|---|---|---|
| Cookie | クッキー | ブラウザに小さなメモを保存する入れ物。「合言葉」を入れておく場所 |
| Session | セッション | サーバー側で名簿を持つ方式。合言葉を渡し、本体はサーバーが管理 |
| JWT | ジョット | 本人情報を改ざん不能な形で封印した通行証。サーバーが名簿を持たなくて済む |
| OAuth | オーオース | 「Googleでログイン」の仕組み。他社にパスワード確認を代行してもらう |
| OIDC | オーアイディーシー | OAuthに「で、誰なの?」の身元確認を足した拡張版 |
| PKCE | ピクシー | OAuthをスマホアプリでも安全に行うための追加の鍵かけ |
関係を整理すると、こう積み上がっています。
認証は、自分でゼロから作らないのが今のプロの常識です。間違えると即・事故になるから。だから「ログインさせたい」ときは、この仕組みを丸ごと代行してくれる既製サービス(Auth0、Clerk、Supabase Auth、Firebase Authなど)を使う。あなたのCloudflare/Supabase圏ならSupabase Authが素直。あなたが覚えるべきは「6つの単語の意味」ではなく、「認証は既製サービスに任せる」という判断1つです。tabiatoが今"全員で共有・ログインなし"で成立しているのは、この面倒を賢く回避した設計とも言えます。
トークンの置き場 ― 「じゃあどこに置けばいいの!?」
「localStorageは危ない、Cookieも設定ミスると危ない、メモリはリロードで消えるって何!? じゃあどこに置けばいいの!?」
「トークン」=前項の合言葉/通行証のこと。これをブラウザのどこに保管するか、3つの候補にそれぞれ弱点があって板挟み——という、プロも悩む本物の難問です。だから混乱は当然。1枚で整理します。
| 置き場 | 長所 | 弱点 |
|---|---|---|
| localStorage (ブラウザの保存箱) | 簡単・リロードで消えない | JavaScriptから丸見え=XSS(次項)で盗まれる |
| メモリ (変数に一時保持) | 盗まれにくい | リロードで消える=毎回ログインし直し |
| httpOnly Cookie (特殊なCookie) | JavaScriptから読めない設定=盗まれにくい | 設定を間違えると別の穴(CSRF)。正しく設定すれば◎ |
答え:現在の推奨は「httpOnly属性を付けたCookie」。これは「JavaScriptからは中身を読めない」特殊なCookieで、たとえ悪意のJSが紛れ込んでも合言葉を盗み出せない。「Cookieも設定ミスると危ない」の"設定"とはこの httpOnly や Secure/SameSite のことで、正しく付ければ最も安全。逆にlocalStorageは手軽さゆえに初心者が使いがちだが、盗難リスクが高いので合言葉の保管には避けるのが定石です。
この「Cookieの安全な設定」も、前項の既製の認証サービスを使えば、正しい設定が最初から入っています。あなたが手で httpOnly を書くことはなく、サービスに任せれば自動で安全側になる。「合言葉はlocalStorageに置かない。httpOnly Cookieが正解。でも自作せず既製サービスに任せる」——この3点だけ持ち帰ればOKです。
XSS と CSRF ― 「セキュリティの略語、怖いの多すぎるよ!」
「XSSって何!? CSRFって何!? セキュリティの略語、怖いの多すぎるよ!」
この2つはWeb攻撃の二大巨頭。名前は怖いですが、やられ方は1文で説明できます。正体を知れば、対策も1つずつはっきりします。
| 略語 | 読み | やられ方(1文) | 主な守り |
|---|---|---|---|
| XSS | エックスエスエス (クロスサイトスクリプティング) | 攻撃者の悪意あるJavaScriptを、あなたのページに紛れ込ませて実行させる。前項の合言葉泥棒はこれ | ユーザーが書いた文字をそのままHTMLに埋めない(無害化する) |
| CSRF | シーサーフ (クロスサイトリクエストフォージェリ) | ログイン中のあなたに、気づかせず"送金"などの操作を裏で実行させる(別サイトの罠経由) | Cookieに SameSite 設定+操作ごとの合言葉(トークン) |
覚え方:XSS=「悪いコードを、あなたのサイトに"入れられる"」/CSRF=「あなたの権限を、別サイトから"勝手に使われる"」。方向が逆の攻撃です。
静的サイト(見せるだけ・ユーザーが文字を書き込まない)は、この2つの標的になりにくい。XSSは「ユーザーの入力を表示する場所」、CSRFは「ログイン後に操作する場所」で起きるからです。危ないのはtabiatoのように"ユーザーが投稿する"アプリ。そこは①投稿文をそのまま表示せず無害化する、②Cloudflare/Supabaseの標準の守りを使う——で対処します。そして今どきのフレームワーク(AstroやReact)はXSS対策を最初から自動で入れてくれる(文字を勝手に無害化する)ので、素のHTMLを手書きするより実はずっと安全。あなたは「投稿を扱う時だけ注意、あとは道具が守ってくれる」と知っておけば十分です。
認証6語は全部「ログイン後も同じ人と証明し続ける」ための道具。自作せず既製サービス(Supabase Auth等)に任せるのが正解。合言葉の置き場はhttpOnly Cookieが安全(localStorageは避ける)。XSS/CSRFはWeb二大攻撃だが、標的は主に"投稿を扱うアプリ"で、静的サイトのあなたは対象になりにくく、フレームワークが自動で守る。強い単語に怯えず、判断は「任せる」1つでよい。
PART 10
型とデータの取り方
TypeScript(型はビルドで消える)/ GraphQL vs REST
TypeScript ― 「型はビルド後に消えるって何!? 大事なら消えないでよ!」
「TypeScriptで型あるんじゃないの!? 型はビルド後に消えるって何!? 大事なら消えないでよ!」
TypeScript(タイプスクリプト・略してTS)=「JavaScriptに"型のメモ"を書き足せるようにしたもの」。型=「この値は数字」「これは文字」「これは客データ」という、中身の種類の宣言。これを書いておくと、書いてる最中に間違いを赤線で教えてくれる。「文字と数字を足そうとしてるよ」と、動かす前に警告が出る。これがTSの全価値です。
なぜ「ビルド後に消える」のか(消えて正しい理由)
第7部を思い出してください。あなたのコードは、ブラウザ向けに変換(ビルド)されます。ところがブラウザは型を理解できません(ブラウザが読めるのは素のJavaScriptだけ)。だから変換の最後で、型のメモは役目を終えて削り落とされる。つまり——
型は「書いている最中を守る道具」であって、動いている時に働く物ではない。だから消えて正しい。あなたの「大事なら消えないで」は自然な感覚ですが、正確には「型は"作る時"に大事な物で、"動く時"には役目を終えている」。テスト前の勉強ノートのようなもので、本番(ブラウザ)には持ち込まなくていい。むしろ持ち込む(消さない)と、ブラウザが理解できずエラーになります。
型が守るのは「自分のコードの書き間違い」だけ。外部から届く"実際のデータ"が型通りとは限りません(サーバーが約束と違う物を返す等)。だから「型があるから絶対安全」ではなく、外から来るデータは実際に確かめる必要がある——これはプロも間違えるポイントですが、判断はClaudeに任せられます。
Astroは最初からTypeScript対応で、あなたのプロジェクトでも型が静かに働いています。あなたが型を手で書く必要はほぼなく、Claudeが書き、赤線が出れば直す。型の恩恵(間違いを早く発見)だけ受け取って、仕組みは「作る時のガード、動く前に消える」とだけ理解すればOKです。
GraphQL と REST ― 「RESTでいいじゃん! 取りすぎなの!?」
「GraphQLもわかんないよ! RESTでいいじゃん! 必要なものだけ取れるって何!? じゃあRESTは取りすぎなの!?」
両方とも「サイトが、サーバーからデータを取ってくる時の"注文の仕方"」。あなたの「RESTでいいじゃん」は、多くの場合その通り正解です。違いは注文の柔軟さだけ。
| REST(レスト) | GraphQL(グラフキューエル) | |
|---|---|---|
| 注文の仕方 | 決まったセットメニューを頼む。「客情報ください」で客の全項目が来る | 単品注文。「客の名前と写真だけ」と指定して、それだけ来る |
| 取りすぎ問題 | 名前だけ欲しくても全項目来る=取りすぎになりがち | 欲しい物だけ=無駄がない |
| 取り足りない問題 | 客情報と注文履歴が欲しいと2回頼む必要 | 1回の注文でまとめて取れる |
| 手軽さ | 単純・定番・情報が豊富。小〜中規模はこれで十分 | 柔軟な分、仕組みが重い。大規模・複雑なアプリ向き |
「RESTは取りすぎなの?」——半分正解。RESTはセットメニューなので、要らない付け合わせも一緒に来がち。でもそれが問題になるのは、通信量にシビアな大規模アプリの話。普通のサイトでは"取りすぎ"は誤差で、RESTの単純さの方が価値があります。GraphQLは「巨大アプリで、画面ごとに欲しいデータが細かく違って、通信を切り詰めたい」時に効く道具。多くの現場は今もRESTで、それで何も問題ありません。
そもそもデータ取得の話がほぼ出てきません(静的サイトは前もって焼くから)。tabiatoのような動的案件でCloudflareのD1からデータを取る時も、REST的な単純なやり方で十分。GraphQLは「知っておくが、あなたの規模では要らない」の典型です。「RESTでいいじゃん」を自信を持ってください——多くのプロも同じ結論です。
TypeScriptの型=「作る時に間違いを赤線で防ぐメモ」で、ブラウザは読めないから変換後に消える(消えて正しい)。GraphQL/RESTは「データの注文の仕方」で、RESTが単純・定番、GraphQLは大規模向けの柔軟版。あなたはどちらも「Claudeが型を書き、注文はRESTで足りる」で、直接悩む場面はほぼ無い。
PART 11
品質を守る道具 ― テストと整形
テスト(Jest/Vitest/Playwright…)・モック / ESLint・Prettier・Biome / セミコロン戦争
テストの種類 ― 単体・結合・E2E
「テストもわかんないよ! Jest? Vitest? Testing Library? Playwright? Cypress? 単体テストなの!? 結合テストなの!? E2Eなの!?」
テスト=「コードを直すたび、壊れてないか"機械に自動で確認させる"仕組み」。手で全ページをポチポチ確認する代わりに、機械が一瞬でやる。まず種類(何をどこまで確認するか)と、道具(それをやるアプリ)は別の話なので、分けて整理します。
| 種類 | 何を確認 | 料理で例えると | 速さ/手軽さ |
|---|---|---|---|
| 単体テスト (ユニット) | 部品1個が正しく動くか(「合計を出す関数は正しい?」) | 包丁の切れ味だけ確認 | 速い・大量に書ける |
| 結合テスト (インテグレーション) | 部品同士を繋いで正しく動くか(「フォームとボタンが連携する?」) | 下ごしらえの工程を通しで確認 | 中くらい |
| E2E (エンドツーエンド) | 客と同じ操作を最初から最後まで(「ログイン→注文→完了まで通る?」) | 実際に一皿を完食してみる | 遅いが一番本物に近い |
次に道具。どれが「単体用」か「E2E用」かで住み分けています。
| 道具 | 読み | 担当 |
|---|---|---|
| Jest | ジェスト | 単体・結合の定番(やや旧) |
| Vitest | ヴィテスト | Jestの高速な新版(Vite仲間)。今から選ぶならこれ |
| Testing Library | — | 「客の見え方で確認する」書き方の補助。Jest/Vitestと一緒に使う |
| Playwright | プレイライト | E2Eの本命。本物のブラウザを自動操縦して通し確認(Microsoft製) |
| Cypress | サイプレス | E2Eの老舗。Playwrightと双璧 |
個人の小規模サイトでは、フルのテストは基本不要です。テストが本領を発揮するのは「大人数で長期間、壊さず改修し続ける」現場。あなたの場合の"現実的なテスト"は、全体像編でやっている「作ったら実機で見る(スクショで見比べる)」=手動のE2Eです。それで十分。ただし将来tabiatoのような動く機能が育ったら、「壊れたら困る中核の動き」にだけPlaywrightで1本自動テストを置く、くらいが費用対効果の良い落とし所。あなたが覚えるのは種類の名前ではなく「テスト=壊れ検知の自動化。今は実機確認で足りる」だけ。
モックとスタブ ― 「本物を叩けばいいじゃん→遅いし不安定って何!?」
「スタブって何!? APIをモックするって何!? 本物を叩けばいいじゃんって言ったら、遅いし不安定って何!? じゃあ本物は信用できないの!?」
モック/スタブ=「テストの時だけ使う、本物そっくりの"替え玉(ニセモノ)"」。なぜ本物を使わないか。テストで毎回"本物のサーバー"に問い合わせると、こうなるから:
- 遅い:ネット越しに毎回問い合わせる=テストが何十倍も時間がかかる。
- 不安定:サーバーが混んでいたり、通信が落ちたりすると、コードは正しいのにテストが失敗する。これでは「壊れた」のか「たまたま通信が悪かった」のか区別できない。
- 危険:「注文」のテストで本物を叩くと、本当に注文が入ってしまう。
だから「相手のサーバーは、いつも決まった答えを即返す替え玉」に差し替える。これがモック。するとテストは速く・毎回同じ結果・安全になり、「自分のコードだけ」を正確に確認できます。「本物が信用できない」のではなく、「テストでは"自分のコードの検査"に集中したいから、外部という不確定要素を一時的に外す」——という理屈です。(スタブとモックは細かくは別物ですが、あなたは「テスト用の替え玉」と一括りで大丈夫。)
前項の通り、あなたは今フルのテストを書かないので、モックも当面無縁です。「テストの世界には"外部の替え玉"という考え方がある」と知っておけば十分。実際に必要になったら、その1点だけClaudeが用意します。
ESLint / Prettier / Biome とセミコロン戦争
「Lintもわかんないよ! ESLintって何!? Prettierって何!? Biomeなら両方できるって何!? じゃあ最初からBiomeでよくない!? でもESLintのルール資産があるって何!? セミコロンいるの!? シングルクォート? 末尾カンマ? フォーマットで宗教戦争しないでよ!」
まず、名前が似ている2つを役割で分けます。ここが混乱の元です。
| 道具 | 読み | 役割(別物) | 例え |
|---|---|---|---|
| Prettier | プリティア | 整形係。見た目(インデント・改行・クォート)を自動で揃える。中身の良し悪しは見ない | 文章の体裁を整える校正者 |
| ESLint | イーエスリント | 品質検査係。「ここバグりそう」「使ってない変数がある」と中身の問題を指摘 | 内容の間違いを指摘する編集者 |
| Biome | ビオーム | 両方を1つで・爆速でやる新型(Rust製)。整形+検査の統合版 | 校正も編集も1人でこなす速い人 |
「最初からBiomeでよくない?」への正直な答え
あなたの疑問はまっとうで、新規プロジェクトなら「Biome 1つ」で正解に近いです。速いし、2つ入れる手間もない。ではなぜ皆Biomeに一本化しないか——「ESLintのルール資産」がそれです。ESLintは長年かけて膨大な"検査ルールの蓄積"を持っていて(特殊な状況を検知する細かいルールが何千個もある)、Biomeはまだ全部には追いついていない。だから「複雑な既存プロジェクト=ESLintの資産が要る」「新しく小さく始める=Biome1つが楽」という住み分け。あなたの新規サイトならBiome、またはClaudeにお任せで何も問題ありません。
セミコロン・クォート戦争 ― 「どっちでもいい。決めて自動化するだけ」
ここが一番のガス抜きポイント。セミコロンが要るか、シングルクォート(')かダブル(")か、末尾にカンマを付けるか——技術的には、どれも正解です。コードの動作は1ミリも変わりません。ではなぜ揉めるか。「チーム全員がバラバラだと、diff(変更箇所の記録)が汚れて、誰が何を直したか分からなくなる」から。つまり中身の正しさではなく"揃っているか"だけが問題。だから解決は1つ——
「どれでもいいから1つに決めて、あとはPrettier/Biomeに自動で揃えさせる」。人間が手で気にするのをやめ、保存した瞬間に機械が統一する。これで宗教戦争は"起きなくなる"のではなく"どうでもよくなる"。
末尾カンマがなぜ大事か、だけ補足:行を1つ足した時、末尾カンマがあると「新しい行の追加」1行だけの変更に見えるが、無いと前の行にカンマを足す変更まで混ざって、diffが余計に汚れる。だから「常に末尾カンマを付ける」派が多い。これも"揃えると後で楽"という実利の話で、あなたが覚える必要はありません。
フォーマットの流儀は、あなたが決めなくていい。Claudeが一貫した流儀で書き、保存時に自動整形します。あなたは「セミコロンやクォートは"好みで、動作は同じ。揃えるために自動化する"もの」と知って、この戦争から降りてOK。降りるのが正解です。
テスト=壊れ検知の自動化(単体<結合<E2E、道具はVitest/Playwright)。個人サイトは"実機で見る"で足りる。モック=テスト用の替え玉(本物は遅い・不安定・危険だから)。Prettier=整形、ESLint=検査、Biome=統合新型。セミコロン論争は動作に無関係で「揃えて自動化」が答え。品質の道具は"大人数・長期"で効くもので、あなたは軽装備+Claude任せでよい。
PART 12
公開と運用 ― 世界に出したあとの世界
デプロイ各社 / サーバーレス / 環境変数・.env / CI / キャッシュ / Shadow DOM
デプロイ先 ― 「Vercel? Netlify? Cloudflare? どれが正解なの!?」
「デプロイもわかんないよ! Vercel? Netlify? Cloudflare Pages? Workers? Firebase? Supabase? AWS Amplify? どれが正解なの!?」
デプロイ=「完成したサイトを、世界に公開する(サーバーに置いて配る)こと」。全体像編の「店舗(Cloudflare)」がこれです。7つの名前は"公開を代行してくれる会社"のライバル同士で、あなたはもうCloudflareを選び終えています。
| サービス | 読み | キャラ・得意 |
|---|---|---|
| Cloudflare Pages / Workers | クラウドフレア | あなたの選択。速い・安い(静的はほぼ無料)・世界中に配信網。Pages=サイト公開、Workers=軽い処理の実行 |
| Vercel | ヴァーセル | Next.jsの会社。Nextを使うなら最高に楽。その分やや高価 |
| Netlify | ネトリファイ | Vercelの老舗ライバル。静的サイト公開の定番の一つ |
| Firebase | ファイアベース | Googleの"裏側まるごと"セット(データ置き場・ログイン・公開) |
| Supabase | スーパーベース | Firebaseの新しい対抗馬。データベース+ログインが得意。あなたの圏内 |
| AWS Amplify | アンプリファイ | Amazonの巨大クラウドの入口。多機能だが玄人向けで重い |
用途で決まります。そしてあなたは正解済み。——「Astroの静的サイトを、安く速く大量に配る」ならCloudflareが最適解で、あなたはそこにいる。「Next.jsアプリ」ならVercel。「ログインやデータベースが要る動的アプリ」ならSupabaseやFirebase。全社を覚える必要はゼロで、「Cloudflare=あなたのホーム。データベースが要ったらSupabaseを足す」——この2つだけ知っていれば、あなたの事業は回ります。
サーバーレス ― 「サーバーがないのに、サーバーっぽいものがあるじゃん!」
「サーバーレスって何!? サーバーがないって言うのに、ログを見るとサーバーっぽいものがあるじゃん! あるの!? ないの!? どっちなの!?」
あなたの観察、正確です。サーバーはあります。「サーバーレス」は"サーバーが無い"という意味ではなく、"あなたがサーバーを管理しなくていい"という意味。名前が誤解を生む、業界の悪いネーミングの典型です。正直に読むなら「サーバー管理レス(管理しなくていい)」。
| 昔ながらのサーバー | サーバーレス | |
|---|---|---|
| サーバーは | ある(自分で借りて持つ) | ある(でもクラウド会社の物) |
| 誰が管理 | あなた(電源・故障・更新・混雑対応を全部) | クラウド会社が全部。あなたは中身のコードだけ書く |
| いつ動く | 24時間つけっぱなし(使わなくても料金) | 呼ばれた瞬間だけ動く(使った分だけ料金) |
| 例え | 自分でお店を1軒借りて維持する | 必要な時だけ厨房を借りて、使った分だけ払う |
だから「ログにサーバーっぽい物が出る」のは当然で、実際に裏でサーバーが動いている。ただそれをあなたが一切世話しなくていい。CloudflareのWorkers(前項)がまさにこれで、「呼ばれた時だけ、ほんの少し処理して、寝る」という、管理不要の小さなサーバーです。
tabiatoで「投稿を保存する・取り出す」ような処理は、CloudflareのWorkers+D1というサーバーレスで動いています。あなたはサーバーの電源も故障も気にせず、Claudeが中身のコードを書くだけ。「サーバーレス=サーバーはあるが、世話はクラウド任せ・使った分だけ課金」——これで謎は解けます。
環境変数と .env ― 「名前でセキュリティを決めないでよ!」
「環境変数もわかんないよ! .env、.env.local、.env.development、.env.production、.env.exampleって何!? どれをどこに置いたらどの順番で読まれるのかわからないよ! NEXT_PUBLIC_を付けるとブラウザに出るって何!? 秘密なの!? 公開なの!? 名前でセキュリティを決めないでよ!」
環境変数=「コードの中に直接書きたくない"設定値"を、外の小さなメモ帳に分けて置いたもの」。代表例がAPIキー(鍵)。鍵をコードに直接書くと、GitHubに上げた瞬間に世界に漏れる。だからコード本体とは別のファイル(.env)に隔離し、そのファイルはGitHubに上げない。全体像編でmicroCMSの鍵を「焼き込みの時だけ使い、公開HTMLに残さない」と習った、あれの正体です。
.env の種類 ― 「場面ごとの使い分け」だけ
末尾の違いは「どの場面用のメモ帳か」を表すだけです。
| ファイル名 | いつ使う | GitHubに上げる? |
|---|---|---|
.env | 全場面の共通設定 | 秘密が入るなら上げない |
.env.local | 自分のPCだけの秘密(本物の鍵) | 絶対に上げない |
.env.development | 開発中(手元プレビュー)用 | 秘密なしなら可 |
.env.production | 本番(公開版)用 | 秘密なしなら可 |
.env.example | 見本。「こういう鍵が要る」と枠だけ示す(値は空) | 上げてよい(中身が空だから) |
読まれる順は「より具体的なものが優先」(.env.local が .env より強い、など)ですが、これはあなたが暗記する必要はゼロ。Claudeとツールが正しく扱います。要点は1つ——「本物の鍵は .env.local に置き、GitHubには上げない。見本は .env.example で共有する」。
NEXT_PUBLIC_ ― 「名前でセキュリティを決めないで」の真相
あなたの怒りはほぼ正しく、しかし1点だけ理解を足すと腑に落ちます。これはNext.js(と類似ツール)のルールで——「変数名の頭に NEXT_PUBLIC_ と付いた物だけを、ブラウザに送り出す」という約束です。逆に言うと、付いていない環境変数は、ブラウザには絶対に出ない(サーバー側に留まる)。
つまり「名前でセキュリティが決まる」のではなく、「これは公開してよい」と開発者が意図的に宣言するための"目印"が、その名前。危険なのは、本物の秘密の鍵にうっかり NEXT_PUBLIC_ を付けてしまうこと——そうすると「公開してよい」と宣言したことになり、鍵がブラウザに漏れる。だから「NEXT_PUBLIC_ は"バレてもいい物にだけ"付ける」のが鉄則。名前は不親切ですが、仕組みとしては「公開/非公開を人間が明示する安全弁」です。
あなたはNextではなくAstroなので、この目印は PUBLIC_ という名前になります(同じ発想)。PUBLIC_ が付いた物だけブラウザに出る。本物の鍵(microCMSやSupabaseの秘密鍵)には絶対に PUBLIC_ を付けず、.env.local に置く。この線引きさえ守れば漏洩事故は起きません。そして実際の設定はClaudeが行い、あなたは「秘密の鍵をブラウザに出す印を付けない」とだけ覚えておけば安全です。
GitHub Actions と CI ― 「ローカルで動いたのに、なんでCIで落ちるの!?」
「GitHub Actionsもわかんないよ! ローカルで動いたじゃん! なのにCIで落ちるって何!? Nodeのバージョンが違う、環境変数がない、lockfileが違う、キャッシュが壊れたって何!? ローカルで動いたら本番でも動いてよ!」
CI=「あなたがGitHubに送るたび、"別のまっさらなPC"が自動で組み立て直して、壊れてないか確認する仕組み」。GitHub Actionsは、GitHubがその仕組みを提供するサービス名。目的は「あなたのPCではたまたま動くだけ、を防ぐ」ことです。
なぜ「ローカルで動いたのに落ちる」のか(理由は全部同じ1つ)
原因はいつも「あなたのPCと、CIのまっさらPCの、環境が違う」の一点です。あなたのPCには、長年かけて溜まった設定・ファイル・ツールがある。CIは毎回ゼロから作るので、あなたのPCにあって当然の物が無い。あなたが挙げた4つは、その"違い"の代表例です。
| CIで落ちる理由 | 何が起きている | 直し方(Claudeがやる) |
|---|---|---|
| Nodeのバージョン違い | あなたのPCは新しいNode、CIは古いNodeで、動きが変わった | 使うバージョンを設定ファイルで固定する |
| 環境変数がない | 鍵は .env.local に置いてGitHubに上げない(前項)→CIには存在しない | CIの管理画面に鍵を別途登録する |
| lockfileが違う | 部品の名簿(第7部)がズレ、CIが別バージョンを入れた | lockfileを一致させ、名簿通りに入れる指定にする |
| キャッシュが壊れた | 速くするための"作り置き"が古く、噛み合わなくなった | キャッシュを1回消してやり直す |
だから「ローカルで動いたら本番でも動いてよ」は正論で、CIはまさにその願いを叶えるための道具です。「あなたのPCの特殊事情に頼らず、まっさらな所でも動く」ことを保証する=本番で動くことの事前確認。CIで落ちるのは、実は「本番で落ちる前に、安全な場所で先に落ちてくれた」ありがたい警告なのです。
あなたのCloudflareへの自動公開(全体像編の「配管」)も、この仲間です。CIの設定・エラー対応はClaudeの担当領域で、あなたは「CIで落ちた=本番前に問題を見つけてくれた。環境の違いが原因なので、Claudeが揃える」と理解しておけば十分。怒るより、味方だと思ってOKです。
キャッシュ ― 「更新したのに古い画面が出る! 今は効かないで!」
「更新したのに古い画面が出るって何!? キャッシュが効いてるからって何!? 効かないでよ! 今は効かないでよ!」
キャッシュ(cache)=「一度読み込んだ物を、次回速く出すために"手元に取っておく"仕組み」。ブラウザは、あなたのサイトの画像やCSSを毎回ダウンロードし直すと遅いので、1回目にコピーを保存して、2回目からはそれを即出す。これで表示が速くなる——普段はあなたの味方です。
問題は更新した時。あなたはサイトを新しくしたのに、ブラウザは「前に取っておいたコピー」を"まだ新しい"と思って出してしまう。だから「更新したのに古い画面」。あなたの怒りはこの一点で、「速くする仕組みが、更新の邪魔をする」という、キャッシュ本質のジレンマです。
直し方 ― プロは「名前を変える」で解決している
「効かないでよ」を実現する定番の技があります。ファイルの名前に"指紋"を付ける方法です。中身が変わったら、ファイル名を style.css → style.a1b2c3.css のように自動で変える。するとブラウザには"別の新しいファイル"に見えるので、古いコピーを使わず取り直す。この仕組みを、Astroやビルドツール(第7部)が自動でやってくれます。だから正しく作られたサイトは、更新すれば新しい画面が出ます。
確認中に古い画面が出たら——「スーパーリロード」(Macなら ⌘ + Shift + R)で、キャッシュを無視して取り直せます。まずこれを試す。それでも客側で古い物が出続けるなら、配信の設定(Cloudflare側)でキャッシュを更新する——これはClaudeが対応します。あなたは「古い画面=キャッシュ。まず ⌘+Shift+R。直らなければClaudeにキャッシュ更新を頼む」だけ覚えておけば、この叫びは即・解決します。
Shadow DOM ― 「影のDOM!? 急に闇属性みたいにしないでよ!」
「Shadow DOMって何!? 影のDOMって何!? 急に闇属性みたいにしないでよ!」
名前で損してますが、闇でも何でもありません。第1部のDOM=画面の部品リストを思い出してください。Shadow DOM=「部品の中に、外から干渉されない"独立した小部屋"を作る仕組み」。shadow(影)は「表の一覧からは見えない、隠された内部」という意味で使われているだけ。「隠し部屋つきDOM」と読み替えると正確です。
何のためにあるのか ― 第5部の「CSSが漏れる持病」の最終解決
第5部で、CSSの持病は「飾りがページ全体に効いてしまって名前がぶつかる」ことだと習いました。Shadow DOMは、この持病を物理的に断つ仕組みです。部品を"隠し部屋"に閉じ込めると、その部屋の中のCSSは外に漏れず、外のCSSも中に入れない。完全に独立する。だから「他人が作った部品を自分のサイトに埋め込んでも、お互いのデザインを壊さない」を実現できます。
これは主に「Web Components(どのフレームワークでも使える独立部品)」や、外部から貼り付けるウィジェット(YouTubeの埋め込み動画、予約ボタン、チャット窓など)の中で使われています。あなたが客サイトにInstagramの埋め込みや予約フォームを貼るとき、その中身はShadow DOMで守られていることが多い——だから貼ってもあなたのサイトのデザインと喧嘩しない。あなたが自分でShadow DOMを書くことはまずありません。「外部の部品を安全に埋め込むための隠し部屋」とだけ知っておけば十分です。
デプロイ7社は公開代行のライバルで、あなたはCloudflareで正解済み(DB要ればSupabase)。サーバーレス=サーバーはあるが管理不要・使った分だけ。環境変数は鍵を外に隔離する仕組みで、PUBLIC_印は秘密に付けない。CIは"別PCで壊れ確認"=本番前の親切な警告。キャッシュの古い画面は⌘+Shift+R。Shadow DOM=干渉されない隠し部屋。運用の横文字も、全部あなたの味方だった。
CHEAT SHEET
早見表 ― 結局どれを選べば怒られないのか
各戦争の「迷ったらこれ」+「あなたに関係あるか」の一覧
この本で一番使う1枚。あなたが何度も叫んだ「どれが正解なの!?」に、全部まとめて答えます。読み方は簡単——「迷ったら」列が世間の無難な第一候補、「あなた」列が静的サイト職人のあなたにとっての答え。緑のマスは「あなたが実際に使う/使っている物」、それ以外は「知っておくだけでよい=選ばなくていい」です。
| 戦争(駅) | 並ぶ選択肢 | 迷ったら(世間の無難) | あなた(静的サイト職人) |
|---|---|---|---|
| 部品を作る | React / Vue / Svelte / Solid | React | Astroが内蔵。選ばない |
| 組み立て工場 | Next / Nuxt / Astro | Next(アプリ) | Astro(見せるサイト) |
| HTMLを作る場所 | CSR / SSR / SSG / ISR | 用途次第 | SSG(前もって焼く) |
| 見た目の付け方 | 素CSS / Sass / Tailwind / CSS-in-JS | Tailwind or 素CSS | 素CSS+一部Tailwind |
| UIライブラリ | MUI / Chakra / Radix / shadcn | shadcn/ui(React) | 基本不要(世界観は自作) |
| 状態管理 | Redux / Zustand / Jotai … | Zustand | 不要(stateがほぼ無い) |
| ビルドツール | webpack / Vite / Turbopack … | Vite | Astroが内部でVite。触らない |
| 買い出し係 | npm / yarn / pnpm / bun | npm or pnpm | npm |
| 呼び出す書き方 | ESM / CommonJS | ESM(import) | import |
| 言語 | JavaScript / TypeScript | TypeScript | TS(Claudeが書く) |
| データの注文 | REST / GraphQL | REST | REST(or 不要) |
| 認証 | 自作 / 既製サービス | 既製(Clerk / Supabase Auth) | 既製 or ログイン無し設計 |
| テスト | Vitest / Playwright / … | Vitest+Playwright | 実機で見る(手動) |
| 整形・検査 | ESLint / Prettier / Biome | Biome(新規) | Claude任せ |
| 公開先 | Vercel / Netlify / Cloudflare … | 用途次第 | Cloudflare(+要ればSupabase) |
緑のマスを縦に見てください。あなたの答えは、ほぼ全部「Astro/Cloudflare/npm/素CSS/SSG」に集約されます。つまり——あなたが選ぶべき道具は、もう全部決まっていて、しかも一貫している。この本の50個の横文字のうち、あなたが日常で"選ぶ"のは実質5〜6個だけ。残りは「そういう物がある」と知っておくだけの、観戦席の景色です。
あなたへの結論 ― 「わかんない」の正体
ここまで、あなたが叫んだ「わかんない」を1つ残らず開けてきました。最後に、全部に共通していた"からくり"を3つだけ渡します。これを握れば、今後どんな新しい横文字が襲ってきても、自分で解体できます。
① 横文字が多いのは、悩みが多いから。道具の数=解決したい問題の数です。1つの問題に1つの道具。だから新語を見たら「これは"どの悩み"を解く道具?」と1問だけ聞けば、正体が割れます。魔法は1つもありませんでした。
② 正解は1つじゃない。だから怒られない。あなたが一番恐れていた「何を選べば怒られるの」——答えは「どれも怒られない」でした。あるのは向き不向きだけ。そして各戦争には「迷ったらこれ」の無難な候補が必ずある(早見表)。選択は怖くありません。
③ あなたは、もう選び終えている。Astro・SSG・素CSS・npm・Cloudflare——この一貫した型を選んだ時点で、この本の7〜8割は「あなたには関係ない世界」になりました。ReduxもSSRもServer Componentsも、覚える必要すらない。あなたの型は、この巨大な地図の中で"一番シンプルで、一番壊れにくい"一角です。
あなたはこう叫んで始まりました——「HTML書いて、CSS当てて、ボタン押したら動く、それでいいんじゃないの!?」。12部を旅した今、答えははっきりしています。それで、いいんです。それが土台で、今も昔も変わらない。あなたの直感は最初から正しかった。この本は、その土台の上に人類が積み上げた"増築"の見取り図であって、土台を否定する物ではありませんでした。
「フロントエンドのことは、昔っから何ひとつわかんない」——もう、そんなことはありません。あなたは今、50個の横文字を「自分に関係あるか/ないか」で仕分けできる目を持っています。それは多くのプロより実戦的な力です。
ここから、どう使うか
- 辞書として:会話や記事で横文字に出会ったら、その章を開く。目次から一発で飛べます。
- 心の安定剤として:新しい流行語が来ても「早見表のどの駅の、新しいライバルか」と当てはめれば、慌てずに済む。
- 次の深掘り:全体像編とこの本で"地図"は完成しました。次にやるなら、地図ではなく「実際に1回、手を動かす」——bramleyのコードを開いて「これはコンポーネント」「これがstate」と、本書の言葉で実物に指さし確認していくのが、一番の定着です。いつでも一緒にやります。
分からなかったのは、あなたの頭のせいではなく、業界が名前を増やしすぎたせいでした。その名前たちは、もう全部、あなたの地図の上に居場所があります。
💡 このページは ⌘ + P でPDFとして保存できます。ブラウザのブックマークに入れておけば、いつでも見返せます。