フレームワークや複数のライブラリなしでWebサイトを構築する
(kodingkitty.com)- Koding Kittyは小規模な企業サイトに静的HTML中心のスタックを採用し、大規模CMSやフレームワークがなくても必要なページとブログを運営している
- 選定基準は速度・開発のしやすさ・安価なホスティング・低い複雑さであり、WordPress・ノーコード・フレームワーク・Jamstackはいずれも要件に対して設定や学習の負担が大きかった
- コンテンツはMarkdownやビジュアルエディタではなくHTMLで直接記述し、テキストとHTML/CSS/JSウィジェットが混在する投稿構成を扱いやすくしている
- 繰り返し構造と共通ブロックはJinjaテンプレートで処理し、45行のPythonスクリプトが変更検知、HTMLレンダリング、Tailwind CSS CLIの呼び出しをつないでいる
- 静的サイトのため安価なホスティングで十分で、Hetzner Webhostingは2 EURから始まり、Hacker Newsのトップページ掲載による急激なトラフィック増にも耐えた
シンプルなスタックを選んだ理由
- Koding KittyのWebサイト技術スタックは、最近の軽量Web開発の流行に従うというより、実際の要件に合わせて意図的にシンプルに構成されている
- 目標は開発者にとって摩擦の少ない構成であり、複雑なフレームワークやライブラリの組み合わせよりも、シンプルな解決策のほうが顧客にとって良い場合があると考えた
- 個性的だがやりすぎではないデザインはさまざまな方法で実現できたが、現在の構成は必要な範囲に合わせた選択である
要件と初期基準
- 最初から静的Webサイトとして作ることに決めていた
- 必要な機能はフロントページ、ショーケース、ブログ程度で、それ以上は多くなかった
- 基準は4つだった
- 高速なWebサイト
- 迅速な開発
- 安価なホスティング
- 最小限の複雑さ
検討したが除外した選択肢
-
WordPressおよび類似CMS
- WordPressがインターネットに大きく貢献してきたことは認めている
- しかし、控えめな要件に対しては過剰だった
- コンテンツをデータベースに保存する必要も、プラグインやビジュアルエディタも必要なかった
-
ノーコードツール
- Webコーダーがノーコードツールを使うのはしっくりこないと感じた
- コンテンツを自分で所有し、Webサイトを思いどおりに扱いたかった
- コードで作るほうがノーコードのWYSIWYGエディタより速いと考えた
- 初期学習と継続的な学習がなお必要だという点も負担だった
-
フレームワーク
- フレームワークの経験はあったが、その一式の設定を持ち込みたくはなかった
- データベース、設定、ライブラリ、管理機能など、構成要素が多くなりすぎる可能性があった
- 完全にカスタマイズはできても、結果的にWordPressに近い形になる可能性があると判断した
-
Jamstackおよび静的サイトジェネレーター
- 静的サイトジェネレーターは要件にかなり合っているように見えた
- 言語を選んでコーディングし、その後ボタンやスクリプトで高速な静的サイトを作成できる
- ただし初期設定と、初期・継続の学習が必要だった
- Markdownでブログを書く利便性は認めつつも、全体としてはよりシンプルな解決策を選んだ
KittyStackの構成
- Koding Kittyの構成は4つの要件を中心に整理されている
-
高速なWebサイト
- 静的Webサイトは高速に動作する
-
迅速な開発
- コンテンツはMarkdownや高機能エディタではなくHTMLで記述する
- Koding Kittyの投稿はテキストとHTML/CSS/JSウィジェットを混在させるため、HTMLを直接書くことが適していた
-
安価なホスティング
- 静的サイトのホスティング費用は、プロバイダーと必要な追加機能によって異なる
- 静的サイトは大規模なハードウェア構成を必要としないため、最小構成を選べる
- Hetzner webhostingは2 EURから始まる
- Koding KittyのサイトはHacker Newsのトップページに載るレベルのトラフィック急増にも耐えた
-
最小限の複雑さ
- 一部のページや投稿には繰り返しパターンがある
- コピー&ペーストでも可能だが、時間が経つと制御しづらくなる可能性がある
- ループと、ヘッダー・フッターのようなコードブロックのインクルード機能が必要だった
Jinjaとビルドフロー
- 繰り返し構造と共通ファイルのインクルードはJinjaテンプレートで処理している
- Jinjaはループ、ナビゲーションバーやフッターのようなファイルのインクルード、そのほかのテンプレート機能を提供する
- チームは過去にJinjaベースのフレームワークを使った経験があり、新しいシステムを学ぶ必要がなかった
シンプルなツールチェーン
- 最終的な静的ページは45行のPythonスクリプトで生成している
- コメントと空行も含めた行数である
- ビルドフローは次のとおり
- 開発者が
index.src.htmlを修正する Watchdog.pyがファイル変更を検知する- Jinjaテンプレートを
index.htmlとしてレンダリングする - Tailwind CSS CLIを呼び出して
styles.min.cssを生成する
- 開発者が
- 開発中はLive Serverがファイルを配信し、変更時に再読み込みする
- デプロイ時にはファイルをFTPで手動アップロードする
複雑さを抑えたWeb開発の利点
- Web開発は、多くを犠牲にしなくてもシンプルに保てる
- 選択肢をいくつかに絞ると、かえってより自由に感じられることがある
- 多くの顧客にとっては、より速く、よりシンプルで、より安価なソリューションが役立つ可能性がある
- 同じ結果をもっと複雑でない技術スタックで達成できるかどうか、Web全体を見渡して判断する必要がある
1件のコメント
Hacker Newsのコメント
写真ポートフォリオでも同じアプローチに落ち着いた。開発から写真に移ってみると、他の写真家のように Squarespace に依存しなくていいのが利点だった
Ghost、Statamic、Phoenix/Vaporで作るサーバーベースの選択肢や、一般的な静的サイトジェネレーターをいろいろ試した末に、結局はテンプレートなしで素のHTMLを書き、rsync で Hetzner のサーバーに上げる方式になった
ナビゲーションのような共通UIにテンプレートがないのは少し気になるが、正規表現で数分以上かかる変更はまだなく、初期に貪欲な正規表現で内容を消してしまったことは git が救ってくれた
画像サイズや形式ごとの派生生成は面倒だが、Ghost のような固定化されたレイアウトに頼らず新しいレイアウトを試せる。さらに、たいていの静的サイトジェネレーターが使うライブラリやCLIツールよりも、RAWエディタの Capture One でWeb向け画像を書き出したほうが品質がわずかによく見えた
遅くはあるが、写真集を作ることにより近いと思う。最初は手間がかかるが、一度終わればそれで終わりで、今後20年間いろいろなCMSの間を行き来して壊す必要もない
実質的には数個のHTMLファイルにテンプレートの力を加えた構成で、Flickr API でこのサイト専用アルバムから写真を取得し、Netlify は
git pushするだけで自動デプロイされるホスティング込みの総費用は0ドルで、Flickrアプリでスマホから写真を管理できる。Netlify のおかげで実際のサーバーボックスを触る必要もなくて助かる
最近自分が使った方法も参考になるかもしれない(https://news.ycombinator.com/item?id=36592641)。Google Sheet をデータソースに使うのは簡単だったし、写真ファイルシステムに置き換えても同じだったはずだ
これは「シンプル(simple)」なのではなく、シンプルに見えるだけ(simplistic) に近いように思える。何もしないで角を削れば、比較的単純なWebサイトは作れる
このページで見えるほぼ唯一の非自明な機能であるダークモードを見ても、遅延ロードされたJSで処理しているせいで、ページを読み込むたびに避けられない 白い画面のちらつき が発生する。きちんとやるなら CSS の body クラス方式であるべきで、動かない解決策は単純だろうが複雑だろうが意味がない
さらに、localStorage とダークモード設定のためのJS 3行程度のために https://hyperscript.org/ のようなカスタムの「hyperscript」インタープリタ全体を持ち込むのは、「単純さは究極の洗練」という趣旨にも反する。96KBの未キャッシュなライブラリをそのためだけに読み込むのは奇妙で、HTMLの検証が通らないのもこれが原因なのか気になる
最後に、二値トグルはシステム/ブラウザ設定を無視するので、よくないダークモード実装だ。スマホOSでダークモードを有効にしていても、ユーザーが手動で有効にするまでライトモードで表示されるし、時間や周囲の明るさに応じて変わるシステム設定も尊重できない。localStorage は期限切れになることもあるし端末も変わるので、何度も設定し直す必要があり、ユーザーは開発者の言う「シンプル」な実装に同意しない可能性が高い
システム/ブラウザ設定、時間帯ベースの切り替え、周囲光などを考慮すると、シンプルなWebサイトという哲学と衝突する複雑さが大きくなる。単にダークモードを外すほうがよく、HNも常にライトモードだが夜に読むのに大きな問題はない
ふつうは
prefers-color-schemeを尊重しつつトグルも提供したくなるし、ユーザーが以前そのサイトで自分で選択していたなら、その選択を優先したくなる。そうなると、やはりJSと localStorage が必要になる自分の好みの方法は、インラインスタイルで
body {visibility: hidden; opacity: 0;}を入れることだ。前のページを維持したまま、DOMContentLoadedの時点でprefers-color-schemeと localStorage を確認し、body クラスを正しく設定してからページを描画させられる自分のサイトはCSSでライト/ダークテーマを尊重し、手動トグルはない。JSなしの純粋なHTML/CSSサイトを個人的な目標にしていて、ライト/ダーク設定はユーザーの設定を尊重すべきだと思っている。トグルが必要ならサイト内ではなく、ブラウザツールバーの設定であるべきだ
/u/gwern が読んでいるなら、自分のサイト https://daveon.design/ は gwern デザインと Tufte.css の影響を受けている。古い出版物や写本、個人的な趣味も混ざっているが、現代的でクリーンな個人Webサイトがどんな見た目になり、何を載せられるのかという最初の着想を与えてくれた核となる事例が gwern だった
あえて言うなら、今の SvelteKit + Skeleton は、使えるプロトタイプを作る速さという点で本当に印象的です
Svelteをきちんと知らなくても、ファイルベースルーティングさえ理解すれば、あとは必要になるまでほぼHTMLで済みますし、Tailwindも最初から入っていて、テーマもおおむねバニラに近いです
ここ数か月でAstro、Lit、Next.js、Go組み込みテンプレート、pug、Eleventyなどいろいろ使ってみましたが、今のところほぼあらゆる面でこの組み合わせがいちばん気に入っています
Skeleton自身のサイト https://www.skeleton.dev/docs/get-started を見るだけでも、Page Downを押してもスクロールせず、ナビゲーションバーにマウスを載せてもスクロールせず、印刷すると画面に見えている部分だけで切れてしまいます。この問題は報告しましたが、まだ大きな優先事項ではないようで、それでも多くのサイトがこのコンポーネントパターンを使っています
Skeletonはダークテーマの色を反転すれば良いライトテーマになると考えているようですが、実際にはそうではありません。DaisyUI のほうがより成熟していて、高性能で、広く使われており、アクセシビリティにも真剣に取り組んでいます。JSなしでCSSアニメーションだけで実現しているのも驚きですし、難しいHTML/CSSの部分を解決しつつ、簡単なSvelteの部分は自分で書けるようにしてくれます。Svelteへの依存度も低いので、DaisyUIのHTMLをほかのフレームワークへ移しやすいです
Tailwindはすぐに動きますし、Netlifyのような場所へのデプロイもとても簡単です。現時点で最高の静的サイトビルダーで、記事で説明されている方法よりずっとシンプルだと思います
+page.tsと適切な設定を使えば静的ウェブサイトも作れますし、マルチページアプリやシングルページアプリにも進めますなんてことだ、HTMLとCSS でウェブサイトを作るなんて狂気の沙汰みたいです
冗談はさておき、テンプレートを除けば同じスタックを使っています。ウェブ開発者でないなら、CSSフレームワークの必要性はあまり分からず、自分で作るほうがずっと簡単です。サイトジェネレーターもHugoを使ってみましたが、時間はまったく節約できませんでした
数か月前にCSSの腕を上げようとして、いくつかの会社のウェブサイトを再現してみましたが、HTMLとCSSだけで見た目はすべて再現できました。ところが、その会社たちの実際のウェブサイトはJSを無効にするとまったく表示されませんでした
私たちはフレームワークの上にフレームワーク、新しい言語、新しいツールを積み上げ続けていて、その大半は複雑さと次の世代の忙しい仕事を増やすだけです。本当にそうしたものが必要な5%のウェブサイトは例外です
実際にサービスを販売しているサイトだという点も興味深く、価格帯がどれくらいだったのかも気になりました
いちばんミニマルで生産的なやり方は、単に PHP を使うことだと思います。その言語はもともとそういう用途のために作られたからです
単純なサイトならcomposerもルーターロジックも不要で、header/footer/navigationファイルを別に作って各ページからincludeすれば済みます
header.php、pagename.php、footer.phpをincludeすれば済みます。単純なサイトならこうしていますし、とても簡単で速いですHTMLがCSSやJSのように外部HTMLを挿入できたなら、これすらたいてい不要だったはずです。好きに使えるようにしてくれればいいのですが
何かを修正してgit commit/pushすれば、30秒以内に変更が世界中へ反映されます。かなり素晴らしいですし、別途サーバーホスティングも不要です
「できるだけシンプルに、しかしそれ以上にシンプルにしすぎない」という言葉を思い出した。たぶん Albert Einstein の言葉ではないだろう。
純粋な HTML + CSS で、CSS を各 HTML タグ内やページ内に書くやり方は、始めるには悪くない。ページが 2 つになれば、CSS は別ファイルに切り出すことになる。
しかし、同じ形式の複数ページを持つサイトを作り始めると、include のあるテンプレートシステムと静的サイトジェネレーターが必要になる。
ページがデータ駆動なら、データを食わせてページを吐き出すプログラマブルなサイトジェネレーターが必要で、データが「リアルタイム」なら、ビューごとにページを生成しなければならないので、少なくとも PHP の領域、さらに言えば実行中のサーバーを持つ現代的な Web フレームワークの領域に進むことになる。
最近、趣味関連のプロボノサイトを作った。ダンスの宣伝とイベント用のサイトで、オーナーは技術に詳しくないダンス講師だ。Eleventy(https://www.11ty.dev/) で Netlify の無料枠に静的サイトを生成し、講師が今後のイベントを定義できるように Google Sheet からデータを取得するカスタムビルドコードを追加した。
作るのに十数時間かかったが、今では運用・管理コストなしでうまく動いている。完全な最小構成と Rails/Phoenix/Django 級の間に、強力なスイートスポットがあると分かった。
ただ、サイトのページ数はほぼ確実に 3 ページを超えるだろうから、一般的なコードブロックが 3 回以上使われるかどうかとは少し事情が違うかもしれない。
Google Sheets API をクライアント側から呼んでデータを埋める構成なのか、そうだとしたらキャッシュ層があるのか、それとも各クライアントが毎回新しいコピーを受け取るのかも気になる。
フレームワークと複雑さをめぐる議論は、もう本当にうんざりだ。
クライアントが多段階の公開ワークフロー、国際化、規制準拠のアクセシビリティを備えたカスタム CMS を求めるなら、クライアントが期待する期間内に作るために強力なツールが必要になる。エンタープライズにはこういうクライアントが多く、だからこうしたツールへの需要も大きい。B2C しかやったことがないなら驚くかもしれないが、これが技術産業という氷山の水面下の部分だ。
静的ブログに複雑な Next.js の設定や Vite のツールチェーンが不要なのはその通りだ。だが、こうしたツールを真面目に論じている人たちは、単純なブログサイトを作ろうと言っているわけではない。チュートリアル用に縮小された例がブログであることはあっても、現実の問題は別だ。
だから、フレームワーク嫌いは少し落ち着いてほしい。シンプルに Web サイトを作るよいアイデアがあるなら、チュートリアルを公開すればいいし、魅力があれば適切な場面で人々がその方法を使うだろう。ただ、あいまいな「激辛ツールチェーンと流行りのフレームワーク」という敵を仕立てて反対するのはやめてほしい。
あるいは、ユーザー数が 2 桁で UX 要件もない社内業務アプリを長く作ってきたという理由だけで、すべて分かったつもりになっているのかもしれない。こうした情報量の低い判断が議論を押し流してしまう。
今度は、そのコードを引き継ぐ人が受け取れるアップデートもなく、Stack Overflow で助けを得るのも難しい。
なぜ作業ごとに違う道具を使ってはいけないと考えるのか分からない。フレームワークが不要な場面もあるが、非常に単純で、しかも頻繁に変わらないものを作るのでなければ、私の経験ではまれだ。
チームとクライアントがいる状況で、「シンプルな道具」のサイトがどう回るのか想像しにくいし、それは非難ではなく、本当に分からないという意味だ。
このやり方でさえ、私にはもう複雑すぎるように聞こえる。
文章は Gemtext、つまり Gemini 用の Markdown で書き、それを HTML に変換し、索引ページを生成するPython スクリプトを作った。
CSS は 42 行しかないので各ページに埋め込み、ファイルごとに 42 行増えるコストが 2 回目の HTTP リクエストより大きくなることはないと計算した。
Python ライブラリやテンプレートなしで、予想よりずっとシンプルだった。いちばん難しかったのは、メーリングリスト向けに送るメールを生成する部分だった。いくつものフレームワークや静的サイトジェネレーターを調べるのに数か月、まともな CSS を見つけるのに数週間を費やした。
git の記録によれば、WordPress 18 年分の記録を取り込むところまで含めて 2 週間ハックして終わらせた。純粋な Python なので新しく学ぶこともなく、バグがあれば簡単に直したり変えたりできる。自分のコードだからだ。
コンピューター科学者は、何でも再利用しようとするより、その場しのぎの特注解法をただコーディングできるという事実をすっかり忘れてしまった。学習して調整する時間のほうが、自分で作る時間より長い。
コード: https://git.sr.ht/~lioploum/ploum.net
サイト: https://ploum.net
私のサイトは 2003 年にバルサ材から削り出してイーサネットケーブルにエポキシで貼り付けた 6502 プロセッサで配信している。変更したくなったら、ヘアドライヤーで EPROM を温めて、望みのビットが反転するようにする。テンプレートもコードも肥大化もない。
下へスクロールしながら技術の歴史をたどる感じが、郷愁を誘う。
誤解していなければ、一般的な静的サイトジェネレーターと大きくは違って見えない。PythonベースのJinjaテンプレートでHTMLファイルを生成するのと、RubyベースのLiquidテンプレートでHTML/Markdownファイルを生成するJekyllとの違いのように見える
includeのためのPHPサイトや既存の静的サイトジェネレーターのほうが、ずっと理にかなっていると思う
理解できない。静的サイトジェネレーターを望まなかったのに、結局静的サイトジェネレーターを自分で書いたことになる