「静的ウェブサイト」の理論と現実
(utcc.utoronto.ca)- 静的・動的ウェブサイトの違いは曖昧になったという見方とは異なり、長い運用の時間軸では 静的ファイルベースのウェブサイト は依然として異なる性質を持つ
- ウェブ初期から続くファイル配置の方式と 静的ファイル配信 の効率性は、静的サイトが長く維持されやすい理由である
- 静的ウェブサイトはウェブサーバーとコンテンツの間に、ファイルシステムのような 明確な責任の境界 があり、双方が互いに知る必要のあることが限定的である
- 動的ウェブサイトはウェブサーバーとユーザーコードの間の境界を小さく単純にしにくく、その境界とAPIを一つに 標準化するのも難しい
- 区別の基準は作業量や変更頻度ではなく、境界がどこにあり、各側が何を気にする必要があるかにある
静的ウェブサイト論争の出発点
- Wesley Aptekar-Cassels の There is no such thing as a static website は、静的ウェブサイトと動的ウェブサイトの違いは思ったより小さいと見ている
- 静的ウェブサイトは見た目以上に 動的で複雑 である
- 動的ウェブサイトを作って運用することは以前より簡単になった
- 個々の論点は説得力を持って展開されているが、静的・動的ウェブサイトの差が縮まったという結論にまではつながらない
耐久性と責任境界が生む違い
- 長い時間軸で見ると、静的ファイルベースのウェブコンテンツは高い 耐久性 を示してきた
- 具体的なウェブサーバーやホストは変わっても、静的ファイルとディレクトリツリーにファイルを配置する方式はウェブ初期から続いている
- 静的ファイル配信は動的ウェブサイトでもよく必要とされ効率的であるため、静的ファイルだけを持つサイトも同じ利点を活用できる
- 静的コンテンツだけを提供すれば、継続運用しやすい安定したサイトになり、これは歴史的に動的ウェブサイトには当てはまらなかった
- 静的ウェブサイトの核心は、単純で強い分離 を持つ責任境界にある
- 一方には HTTPS 証明書の更新のような動的アップデートまで含む静的ウェブサーバーの複雑さがある
- もう一方には静的ファイルがあり、その間にはファイルシステムまたはファイルシステムに類するものが置かれる
- 双方が互いに求めるものは非常に限定的である
- 動的ウェブサイトはウェブサーバーとユーザーコードの間に、このような小さく明確な境界を持ちにくい
- 単一の境界と API に標準化できる可能性も低い
- ウェブはある意味で静的ファイルを提供するよう設計されている側面がある
- この違いは、静的ファイルウェブサーバーを動的ウェブサーバーや実行環境よりも運用・移行しやすくしている
- 静的ファイルウェブサーバーは見つけやすい
- 現在の運営者が停止しても、サイトを別の場所へ移しやすい
- この耐久性は少なくとも単一サーバーに収まる 中小規模の静的ウェブサイト に当てはまる
- 静的ウェブサイトと動的ウェブサイトの区別は曖昧ではない
- サイトを作って運用するのにかかる作業量や、HTTPS 証明書更新のように定期的に変わる要素の量が基準ではない
- 基準は境界がどこにあり、各側が何を気にする必要があるかである
- 静的ウェブサイトは両側を独立して扱える鋭い境界を持ち、動的ウェブサイトにはそうした境界が本質的に存在しないため、必要なら人為的に線を引かなければならない
1件のコメント
Hacker Newsのコメント
コンテンツサイトで生計を立てていて、今年 Craft CMS から自作の静的サイトジェネレーターに移行した
もうサーバーや CMS を気にする必要がなく、アップデートも不要で、重いデータベースや複雑なキャッシュ構成もなくなった。今は単なる静的ファイルサーバーなので、より安定していて保守もほとんど必要ない
最高なのはオフラインで作業できること。テキストエディタさえあればよいので、小さな Macbook 12" でもとても速く感じる
バージョン管理も非常に便利で、変更のレビューや巻き戻しができ、全コンテンツに対して正規表現で検索・置換できる。テキストファイルは扱いやすい
この移行がどんな感覚だったか、そしてなぜうまく機能しているのかをここに書いた: https://nicolasbouliane.com/projects/ursus
ただ、再コンパイルやデプロイができない人にとっても、この技術がもっと身近になるとよいと思う。高速で安価にサイトを作れる方法だが、Hugo のような既存ツールはユーザーにかなり多くを前提としていて、参入障壁になっている
記事も楽しく読んだ。マイグレーションに使った html-to-markdown の元のバージョンを作ったのは自分だが、今でも有用に使われているのを見るとうれしい
速くて、必要な内容がきちんと揃っていて、無駄がない
個人的には、過去と現在の Berlin を舞台にした TV シリーズや映画のセクションがあるとよいし、実際の Berlin をどれだけリアルに描いているかの簡単な評価もあるとうれしい
ウェブサイト全体の 95% 以上は、人気コンテンツの 70% を RAM にキャッシュし、残り 30% を 10,000 IOPS のランダム読み取りが可能な SSD から配信するだけで十分だった可能性が高い
サイトデザインをいじり続けるのでなければ、サイトと HTML の生成はローカルマシンで行われるべきで、全体生成も 1 秒未満で終わるべきだ
ただし、GitHub、バージョン管理、テキストエディタ中心の方式は、依然として技術者やプログラマー寄りだ。ホスティング型 WordPress のようなもの、あるいは昔の Dreamweaver / Frontpage 時代に近い何かが必要だ
特別なことを実装したいときに細部まで掘り下げられるのがよい。たとえば Favorite Git Aliases の記事を編集すると、
.bash_aliasesファイルに変換されて GitLab にプッシュされ、GitHub にもミラーされるようにできる興味のある人向けに https://jdsalaro.com に置いてある。スタックや理由はまだ詳しく書いていないが、少しずつ文書化する予定だ
まずは Sphinx 用 Markdown と Myst のチートシート(https://jdsalaro.com/cheatsheet/sphinx-myst-cheat-sheet/)と、
environment.pickleを読み込む方法(https://jdsalaro.com/howto/sphinx-load-environment-pickle/)を書いておいたこれは電力のような資源消費が減り、より小さなハードウェアで足りることを意味し、何より セキュリティ の改善にもつながる。静的ウェブサイトは攻撃しにくく、起こり得る欠陥もウェブサイトのコードではなくウェブサーバー側に限定される
普段は Hugo を使っているが、機能が非常に豊富で完成度も高い。多言語サイトも作ったことがある
静的ウェブサイトに Turbo Hotwired を統合するのも検討に値する。ナビゲーションの応答性を高め、サーバーとクライアントの双方の負荷を減らせる
必要なら Turbo を Mercure と統合してリアルタイムのページストリーミングも可能だ
静的サイトと動的サイトの最大の違いは セキュリティ上の攻撃面 だ
静的サイトのウェブサーバーは、最悪の場合でも誤ったファイルを配信するよう誘導される程度で、そもそも配信してよいファイルだけをサーバーに置いておけば緩和できる
動的サイトはコードを実行するよう誘導される可能性があり、アクセス可能なデータベースから誤ったデータを返させたり、データを変更させたりもできる
WordPress の侵害はしょっちゅう起きるが、Nginx の侵害はそうではない
技術的には、コードを実行しないウェブサイト など存在しない。ウェブサーバーからファイルシステムドライバ、OS に至るまで、すべてコードだ
静的ファイルが攻撃面を減らすのは確かだが、なぜそうなるのかを深く考え、静的サイトのような安全性を備えた賢い動的システムを設計すべきだ
結局のところ鍵となるのは入力と、その入力をどう扱うかだ。どれほど複雑なコードを実行していても、入力をまったく受け取らなければ攻撃はできない。もちろん入力がなければどのページを見せるかも分からないので、静的サイトにも入力はある。重要な違いはそこにある
静的サイトの攻撃面が小さいことには同意するが、より大きな理由は nginx が平均的な WordPress プラグインの組み合わせよりはるかに多くのレビューを受け、開発速度も遅いからだと思う
自分で静的ウェブサーバーを作るなら、最初のバージョンは基本的な WordPress インストールより攻撃に弱い可能性が高い
静的サイトは理論上、アップデートがまったく不要なことすらあり得る。HTML バージョンのような対象が変わらない限り、アップデートという概念自体がほとんどない
aliasディレクティブのあるlocationブロックの末尾で スラッシュ を付け忘れるケースは例外だ開発者の観点では、Web が提供する抽象化、つまり HTTP/S 上で提供されるハイパーメディアを基準にすると、区別はかなり明快です。
この抽象化のセマンティクスは、特定のパスにヘッダーと本文を持つリクエストが入り、ヘッダーと本文を持つレスポンスが返るという構造です。TLS のような中間的なネットワークの詳細は隠されています。
実際、最新のフレームワークは認証セッションやリクエストヘッダーまで自動管理し、開発者からさらに多くのものを隠しています。この抽象化の中では、「静的はリクエスト/状態に依存せず、動的は依存する」という標準的な区分はきれいに成り立ちますが、その区分は抽象化が提供するセマンティクスに依拠しています。
これは、TCP が根本的にはパケットベースの下位構造の上でコネクション指向プロトコルとして動作するのに似ています。TCP はストリーム型またはパケット型のデータ転送が必要なアプリケーションに使えます。
「実際には IP の上にあるのだから区別はない」と主張することもできますが、それは誤った抽象化レイヤーから見ていることになります。
だからといって、記事の要点が間違っているという意味ではありません。開発者は「ステートレスな Web サイト」の下にある状態性を常に意識すべきであり、必要だと思うよりも数レイヤー深く抽象化を理解しておくほうがよいのです。
個人 Web サイトは静的と動的が微妙に混ざっています。大部分は静的ですが、ブログ部分は動的レンダリングです。
ブログ URL にアクセスすると、ディスクから Markdown ファイルを取得して HTML に変換し、その HTML をテンプレートに入れて残りのページや CSS などを構成します。
それでも高速で効率的です。先週、自分のブログ記事の 1 つが HN で 1 位になったとき、友人が「Cloudflare を設定してあることを願う」とメッセージしてきました。設定していませんでしたが、2 コア・1GB メモリの VPS のロードアベレージは 0.15 を超えませんでした。
「ほとんどは HTML だが、このファイルのこの行に来たらコードを実行して別形式のファイルをパースし、その結果を出力に挿入する」といった形です。
2001 年には、各ブログ記事にコメント欄のようなものを付けた静的 Web サイトを作るのに非常に妥当でした。この種の PHP は十分に安価だったので、一般的な ISP でも
/~userdir/に置いて公開インターネットにさらすことを許可していたものです。データベースに重く依存しすぎない合理的な構成であれば、小さな VPS でも Hacker News からの流入に十分耐えられます。
Threads を立ち上げるなら Facebook がやっているようなスケーリングが必要でしょうが、普通の読み取り専用サイトなら大金をかける必要はまったくありません。
動的コンテンツをテンプレートに差し込むため、あるいはビルド時間や複雑さを減らすためといった理由は思いつきますが、自分が考えていない別の理由があるのかもしれません。
wasmを少しかじっている部外者の立場からすると、なぜサーバーでユーザーコードを実行して「動的」なWebページを生成することが、単純なファイルサーバーより優れているのか理解できなかった。
動的な部分はブラウザで実行して、サーバーは単にファイルだけ配信すればいいのではないかと思う。90年代のブラウザがこうした処理にひどく向いていなかった点は例外だが。
単純さとスケーラビリティの面では、CDNの前段にある単純なファイルサーバーに勝てるものはない
また、標準のブラウザ機能を壊さない技術がどれだけあるかも重要だ。
ちなみにGitHubは、ソースコードを閲覧していると戻るボタンを私の環境では今でも40%くらい壊す。Chrome on OSXを使っているが、どうしてそうなるのかも分からない。
私の経験では、サーバー側でHTMLを生成するサイトのほうが、クライアントレンダリングに依存するものより速くて安定しているように感じる。ブラウザキャッシュが空の状態で、1ページあたり画像50枚以上あるbooruを開くほうが、あちこちにキャッシュ済みで何日も更新されていないテキストだけのGitHubページを開くより、いつも速くて快適に感じられる
たとえば、ユーザー投稿コンテンツをデータベースに保存したいこともあるし、認証が必要なこともあるし、数GBのデータセットに対する全文検索を提供しなければならないこともある。ブラウザからアクセスできないものへのインターフェースを提供したり、ユーザー入力を検証したりする必要がある場合もある。
これらはすべて、サーバー上で実行されるユーザーコードを必要とする。そうなると、サーバー上のデータをよく定義された転送プロトコルに変換してクライアントへ送り、再度変換してHTMLにしなければならない。
逆方向も同じで、悪意あるカスタムクライアントを防ぐには、クライアント側とサーバー側の両方で入力検証をする必要がある。
あるいは、サーバーで直接HTMLにしてしまえば終わりだ。作業量はずっと少なく、ほとんどのアプリケーションでは実質的に同じ体験を提供できる
データベースのパスワード、APIキー、暗号鍵のように隠す必要がある秘密情報があるなら、サーバー上のコードで処理しなければならない。すべてのコードがクライアントで実行されるなら、攻撃者がその秘密情報を見つけられる可能性は常にある。
また、クライアントにはより小さく制限されたAPIを提供するほうが、攻撃面を減らしやすい。クライアントをデータベースに直接接続させるなら、権限やセキュリティ設定が正確で問題ないことを保証しなければならないが、アプリが扱う本や映画の一覧だけを提供するなら、防御を突破するのはもっと難しい。
初回ロード時にすぐ使えるデータの塊として提供すると、サイトがより応答性高く感じられることも多い。アプリケーションをダウンロードしてローディング表示を見せ、その後にデータを取得して表示する方式と実時間が同じでも、ユーザーには前者のほうが速く感じられる。
サーバーは通常、データベースや必要な他のサーバーの近くにあるため、前段で必要なものをロードするほうが速いことがある。こうした環境でのネットワーク呼び出しはより安定している。すべての処理をユーザー側に押しつけると、より遅く不安定な呼び出しを扱う必要がある。
サーバーは、ユーザーのブラウザよりもはるかに一貫したプラットフォームである可能性が高い。ブラウザも良くなったが、いまだに微妙な違いが多い。サーバーなら必要なツールやランタイムのバージョンを正確に指定でき、より決定的に更新できる。
もちろん、これは常に全面的に当てはまるわけではなく、例外もある。私は主にフロントエンドアプリケーションを扱っているが、作業の大半または全部をブラウザで行う、よく設計されたアプリケーションにも大きな価値がある。ただし、それはたいていかなり複雑なWebアプリであるか、いずれにせよブラウザである程度レンダリングが必要な場合だ
生成は一度きりで、しかも非常に速く終わる。
その後は、ユーザー視点では静的ページの数多くの利点がそのまま当てはまる。
リソース使用量は桁違いに少なく、ページの応答性もずっと高い。ユーザー体験もはるかに優れているのに、ここ10年ほど私たちはそれをあまり気にしてこなかった
rsyncでWebサーバーに上げるだけのサイトを運営したことがある。すべてのページは動的にレンダリングされていた。利点は、一度設定したあとはWebサイトのことを文字どおり再び気にする必要がなく、好きなMarkdownを書くだけでよかったことだ。
とても良かった。Webホスティング事業者がPHPをやめるまでは
こういう理由で、NextJSの静的ページ書き出しがとても好きだ。
ビルドして、静的な
.html、.js、.cssだけを好きなCDNや静的Webサーバーにデプロイする。個々のページやルートはビルド時に事前レンダリングされるので、初回ロードが非常に速く、検索エンジンのインデックスも可能だ。NextJSが
.jsコードをチャンクに分割して事前読み込みするやり方も、高速なロード体験に貢献している。豊富な機能が必要なら、好きなREST APIにつないでいくらでも動的にできる。MDXプラグインを使えば、同じプロジェクト内で完全に静的な領域やコンテンツ中心のサイトも簡単に作れる。
ただ、v13のApp Routerが出てから、静的書き出し機能が十分に重視されていないように感じる。Page Routerにあった機能のうち、shallow routingや静的rewrite/redirectが静的書き出しでは欠けている。
静的書き出しを使えば商用のVercel製品はまったく不要になるので、長期的にはこの機能自体をなくしてしまうのではないかと心配だ
大半はJavaScriptすら不要で、React、JSX、ミドルウェア、サーバーサイドレンダリングのようなものも必要ない。
これほど多くの可動部分とnpm依存関係を持つものを長期保守するのは想像しにくい。用途がないという意味ではないが、ランディングページ1枚を作るために1.8 GiBのGitチェックアウトと828,128行のコードから成るプロジェクトに飛び込む前に、シンプルに考えるべきだ
Dan Abramovの例を見ればいい: https://gist.github.com/gaearon/9d6b8eddc7f5e647a054d7b33343...
これはVercelのビジネスモデルのせいではなく、Next.jsの利用比率から見てこのユースケースがあまり一般的でないからだ。
「静的rewrite」が何を意味するのか、よく分からない。それはミドルウェアで処理されるものではないのか?
90年代のある時点で「静的サイトジェネレーター」という言葉を聞く前に、m4で自分のサイトを生成していた。
その後 PHP、Python へ移り、今は Jekyll を使って再び静的な方式に戻っている。
可能である限り、静的な方式のほうがはるかに良い。SSL 証明書以外は、すべてを自分の都合に合わせて修正できる。
PHP のアップグレードで何かが壊れたらすぐに直さなければならず、終わるまでサイトが落ちる状況と比べるとそう思う。
静的サイトは、ジェネレーターが壊れても失敗した結果がそのまま静的な状態で残る。新しい記事を上げる必要がなければ問題ない。
サーバーが落ちても、友人にファイルをいくつかホスティングしてくれと頼めば済む。「PHP バージョン X を設定 Y で動かしてるよね? postgres もあるよね?」と聞く必要はない。
友人によっては「自分のコンピューターに PHP を入れたくない」と言うかもしれない。
複雑さで言えば、
sed "s/VERSION/1.2.3/g"より一段階上くらいに感じる。すべてを外部シェルコマンドで処理できるなら、Python みたいなものをインストールしなくて済む。ここ数年、静的と動的の利点を両方得られるアーキテクチャパターンを探ってきた。
動的なサーバーサイドコードを実行できつつ、スケールのコストが非常に低く、何かが壊れても自己回復する方式だ。
これを Baked Data パターン と呼んでいる: https://simonwillison.net/2021/Jul/28/baked-data/
中核となるアイデアは、サイトデータの完全な読み取り専用コピーを、アプリケーションに同梱されたアセットとして配布することだ。
完全な静的サイトのように、変更があるたびにサイト全体を再デプロイしなければならないため、継続的に更新されるサイトには向かない。
利点は、Vercel のような安価な動的 scale-to-zero ホスティングにデプロイでき、アプリのコピーを複数立ち上げてどんなトラフィックにも対応でき、アプリが落ちてもホストが自動で再起動できる点だ。
サーバーサイド検索やコメントシステムを持つ静的サイトを見たことがあるが、各記事やコメントを個別のフラットファイルとして送信し、そこから静的ページを自動再生成する仕組みだった。
違いは、Markdown ファイルではなく sqlite に保存して、そこからビルドする点なのだろうか。一般的なバックエンド/サーバーサイド機能を持つ静的サイトと比べたとき、目立つ意味のある違いはそれくらいに見える。
コンパイル済みバイナリ実行ファイルには、ファイルや画像のようなエンコードされた バイナリリソース を含めることが珍しくなかった。実行ファイルのサイズが大きくなるので、大量には入れなかった。
C や C++ の例: https://github.com/graphitemaster/incbin
興味深いのは、実行ファイル内のデータが変わらないようにプログラムを作っていたことだ。コンパイル済みコードがマシン上で実行されるし、セキュリティの面でも理にかなっている。
しかしコンテナ、たとえば docker を考えると、実行中のコンテナはパッケージ化された実行ファイルに似ているが、ファイルシステムも持っている。
コンテナにデータを入れるのは、実行ファイルに埋め込まれたリソースと似た概念だが、違うのはそのデータが変更可能なことだ。
ただし、コンテナ内でランタイム時にデータが変わっても、永続ストレージをアタッチしなければ保持されない。
最近は、なぜ「実行ファイルと、実行ファイル内に含まれる揮発性データ空間」を持つ単一ファイルのようなものを作らなかったのか、不思議に思っている。プログラムと、データベースのようなデータを一つのファイルに結合できるはずだからだ。
これは「Baked Data」と少し関係のある発想だ。実行ファイルにリソースを埋め込むというのは、結局エンコードされたデータを実行ファイルの中に入れるということだ。
スクリプト言語では、base64 でエンコードしたデータを変数に直接入れたスクリプトファイルを作ることもできる。
後者の二つの方式は比較的小さな静的データにしか向かないが、実行ファイルのこうした制約を何らかの形で取り払う技術が作れたら面白いと思う。
自分のプロジェクトページもこの方式でホスティングしている: https://usmanity.com/projects
新しいプロジェクトを一覧に追加したり、既存項目の詳細を変えたりするたびに HTML ファイルを直接編集したくなかったので、Notion を使い、GitHub にコミットする前にデータを焼き込んでいる。
有効化すると、サイトのすべてのページをディレクトリ内の HTML として焼き出し、
.htaccessを変更してすべてのトラフィックをそちらに送っていた。コンテンツを更新すると、全部を再度焼き出していた。https://www.drupal.org/project/boost
静的サイトでまだ大きく欠けている部分は、編集用の CMSをどこにホスティングするか だと思う
私の認識が間違っていたら訂正してほしいのだが、Decap CMS(旧 Netlify CMS)はブラウザで動作し、GitHub 経由で読み取りや編集を行ったあと、再ビルドとデプロイをトリガーできる。しかし CORS のため、ブラウザが GitHub API と直接通信できず、小さなサーバーやプロキシが依然として必要だと思う
Netlify はリクエストをプロキシする GitHub バックエンドをホスティングしてくれるが、そうすると Netlify とその価格政策の変更に縛られる
GitLab と BitBucket も同じ問題があるはず: https://github.com/isomorphic-git/isomorphic-git#cors-suppor...
最小限の設定で解決できる簡単な方法はあるだろうか? ブラウザ拡張で CORS を選択的に緩和することもできるかもしれないが、理想的ではない
Git ベースの静的サイトジェネレーターに、Markdown 編集とリアルタイムプレビュー付きの CMS が組み合わさり、ブラウザで動作して、ホスティングやサーバーの制約が少ないなら、無数の小さな Web サイトやブログに合いそうだ
静的ジェネレーターは JSON フィードのようなものからそのデータを読み取り、ページを生成すればよい。たとえば各製品レコードに HTML 形式の本文説明を含めることができる
そうすれば、他の人が製品情報を更新しても Web サイトは依然として静的なままでいられる。Airtable が適していると思っていたが、意外にも HTML フィールドをうまくサポートしていなかった
好きな方法で Web サイトを作り、FTP で Surreal を接続したあと、ユーザーや顧客に許可された部分だけを編集させればよい
月 12 ドルは、心配事がなくなる対価としてはとても安く、非技術ユーザーに完全な WYSIWYG エディターを提供できる
[1] https://www.surrealcms.com
現在この拡張は、ノート PC にローカルインストールした VS Code では動作するが、GitHub Codespaces では動作しない
無料の GitHub Codespaces の範囲内で、適度な利用時間制限つきでこれを動かせるなら勝ち筋になりそうだ。開発環境を自分のコンピューターにインストールする必要がなく、完全にオンラインでバージョン管理された構成を持ちつつ、静的サイトは S3 のような場所で配信し、それでも完全な CMS 体験を得られる
静的サイトの非常に重要な点は、ずっと簡単に 置いておいて忘れられる ことだ
S3 バケットサイトのようなところに置いておけば、ほとんど心配しなくてよい
PHP や、さらに悪いことにセルフホストの WordPress で「置いておいて忘れる」サイトを作ると、数か月ごとに確認しない間にロシアのポルノ広告だらけになることがある
静的サイトをいくつか運用しているが、常に稼働していて修正の必要がないと分かっているのは本当に素晴らしい。対して動的サイトは、落ちていないか確認するためのアラートが必要だ