発表:このサイト、ついにAIで再構築しました

発表:このサイト、ついにAIで再構築しました

ゴールデンウィークにCodeWFをAIで再構築完了:Razor Pages、SEO、検索の不正キーワードフィルタリング、読み込み最適化、コンテンツのホットアップデート、最小テストセット、そしてサイトリポジトリの使用方法。

最終更新 2026/05/01 21:32
dotnet9
読了目安 8 分
カテゴリ
.NET AI Web開発
テーマ
Webサイト
タグ
AI Razor Pages サイト再構築 CodeWF パフォーマンス最適化

宣言します。

このサイト、ついにAIで再構築しました。

「AIに数行のコードを適当に補完してもらう」程度の参加度ではありません。

ページの作り直し、構造の整理、ルーティングの互換性確保、SEO、読み込み最適化、コンテンツ連携、Markdownのクリーニング、最小テストセット、CI、そしてこの記事そのものに至るまで、AIが深く関わっています。

結果は明白です。

効率がめちゃくちゃ高い。

そこで、この記事では今回の再構築を正式に記録し、ついでに一つお話しします。

AIを敬遠しないでください。代替されるかどうかはともかく、まずは使いこなす方法を学べば、本当に事半功倍(少ない労力で大きな効果)になります。

まずは結果から

トップページ

トップページはもう「ただコンテンツを並べる」だけではありません。

情報の階層を整理し直しました。最新記事、プロジェクト、ドキュメント、ツールへの導線がより明確になり、ファーストビューもより焦点が絞られ、メンテナンスが継続されている個人技術サイトとして、バラバラなページの寄せ集めではなくなりました。

これで少なくとも二つのことができるようになりました。

  1. 初めて訪れたユーザーに、このサイトが主に何を書き、何をするのかが伝わる。
  2. 常連の読者が戻ってきたときに、新しいコンテンツやよく使う導線をより早く見つけられる。

検索

検索は今回特に重視した部分です。

以前の多くの個人サイトでは、検索は「とりあえず検索できる」だけで、体験は正直イマイチでした。

今回、検索ページ、検索ルーティング、キーワード処理、結果表示を一気に作り直し、特に実用的な詳細を追加しました。

検索時に不正キーワードのフィルタリングを追加。

これは見せかけではなく、本当に役立ちます。

実装は複雑にせず、考え方はシンプルです。

  1. まずユーザー入力を標準化処理。
  2. 次に site/blocked-search-keywords.json の辞書とマッチング。
  3. ヒットしたら即座にブロックし、汚いキーワードが検索結果のフローに入らないようにする。

これにはいくつか利点があります。

  • 奇妙なキーワードによる検索ページやログの汚染を減らす。
  • 低品質な検索トラフィックが繰り返しページにヒットするのを防ぐ。
  • 公開サイトにとって、不必要な汚れ仕事を省ける。

この機能は大きくありませんが、非常に「サイト運営者視点」です。

プロジェクトセンター

プロジェクトセンターも整理し直しました。

以前は多くのプロジェクト、コンポーネント、NuGetパッケージ、ツールへの導線が異なる記事に散在していて、読者が全体像を把握しにくかったです。

今回、それらをなるべく一つの明確なエントリにまとめました。

以下の情報がより早く見えるようになりました。

  • 私がどのようなプロジェクトを進めているか。
  • どれがオープンソースリポジトリか。
  • どれがツール型ページか。
  • どのコンテンツがすぐに使えるか。

これは私自身にとっても重要です。

なぜなら、サイトは「他人に見せるため」だけでなく、自分のプロジェクトのショーケースであり、能力のアーカイブでもあるからです。

記事詳細ページ

記事ページは今回最も細かく確認しました。

なぜなら、技術サイトの使い勝手は、トップページがどれだけ派手かではなく、本文ページが読みやすいかに大きく依存するからです。

今回、主に以下の点をチェックしました。

  • Markdownレンダリングでおかしな問題が起きないようにする。
  • コードブロックの表示を整える。
  • ページの情報構造をより明確にする。
  • リソースの参照方法をできるだけ統一する。

最近、過去の記事にあるMarkdown構造の異常も一掃しました。例えば、古い記事に混ざった旧形式のコードフェンス、バッククォートのくっつき、言語タグの欠落などです。

こうした問題は普段目立ちませんが、蓄積するとフロントエンドのレンダリングが非常に厄介になります。

今回、具体的に何を再構築したのか

一言で言えば、

単なる外装の変更ではなく、サイトをより「プロダクト」に近い状態に整理し直しました。

今回、主に以下のことを行いました。

  • ページ構造の再編成。
  • ルーティングの互換性の補完。
  • SEO基礎能力の強化。
  • 検索体験の作り直し。
  • 不正キーワードフィルタリング。
  • リソースドメインの独立。
  • 読み込みパフォーマンスの最適化。
  • コンテンツのホットリロード対応。
  • README、最小テストセット、CIの補完。
  • 過去のMarkdown構造問題の一掃。

もし開発者であれば、これが何を意味するかおわかりでしょう。

多くの場合、本当に時間がかかるのは「ページを一つ書くこと」ではなく、バラバラで過去の負債が多く、細かい問題が多いものを、じっくりと長期間メンテナンス可能なリポジトリに仕上げることです。

AIはこの点で、本当に大きな助けになりました。

実装の詳細を少し

1. サイトリポジトリとリソースリポジトリを分離

今回も「二つのリポジトリ」という考え方を維持しました。

CodeWF/           # サイトリポジトリ
Assets.Dotnet9/   # リソースリポジトリ

CodeWF はサイト自体のページ、コンポーネント、ルーティング、レンダリング、SEOを担当。

Assets.Dotnet9 は記事、設定、画像、ナビゲーション、ツールデータなどの「コンテンツアセット」を担当。

この分け方はますます気に入っています。

なぜなら、コンテンツサイトで最も恐ろしいのは、記事を一つ修正しただけでサイトのロジックまで巻き込んでしまったり、ページを修正したらコンテンツリソースも一緒に固定されてしまうことだからです。

分離すると、頭がずっとクリアになります。

利点も明白です。

  • サイトコードとコンテンツリソースの責務が明確。
  • 記事を修正するときにサイトロジックまで巻き込まなくて済む。
  • 独立したデプロイとキャッシュに適している。
  • 後でコンテンツ同期や静的リソースの高速化もやりやすい。

2. サイトドメインとリソースドメインを分離

この詳細は特に述べておきます。

サイトのエントリとリソースアクセスは、二つのドメインでデプロイしています。

リソースリポジトリ内の画像、カバー、記事内埋め込みリソースは、一律このドメインを使用します。

https://img1.dotnet9.com

そのため、この記事内の画像参照もすべてこのような絶対パスになっています。

https://img1.dotnet9.com/2026/05/codewf-homepage.png

これは「プロっぽく見せるため」ではなく、後々の手間を減らすためです。

サイトページとリソースアクセスを分離すると、多くのことがより簡単に処理できます。

例えば、

  • 静的リソースのキャッシュ戦略を個別に設定できる。
  • リソースの移行やCDNがより柔軟になる。
  • サイトのメインドメインへの負荷が減る。
  • 記事コンテンツの独立したメンテナンスと公開に適している。

3. コンテンツのホットリロード対応

この機能はとても気に入っています。

現在、ローカル開発時には、記事やJSON設定、一部の画像リソースを変更しても、毎回サイトを再起動する必要がありません。

内部では FileSystemWatcher を使用してリソースディレクトリの変更を監視しています。

監視対象は以下を含みます。

  • Markdown
  • JSON
  • png/jpg/webp/svg などの画像リソース

こうしたものは非常にシンプルで、「テクニックを見せびらかす」ようなものではありません。

しかし、普段自分でサイトや記事を書いている人なら、これがどれだけ時間を節約してくれるかわかるでしょう。

なぜなら、記事を書く上で最も面倒なのは、書くこと自体ではなく、「修正して、再起動して、また確認する」という繰り返しだからです。

4. 読み込み速度も今回真剣に取り組みました。どのようにやったか、簡単に共有します

この部分では、派手な指標を追うのではなく、考え方は非常にシンプルです。

まず、最も無駄にパフォーマンスを浪費している箇所を埋める。

つまり、圧縮すべきは圧縮し、キャッシュすべきはキャッシュし、遅延させるべきは遅延させ、優先すべきは優先する。

第一に、圧縮。

これが最初に手をつけたことです。副作用がほとんどなく、効果が安定しているからです。

サイトで ResponseCompression を直接有効にし、BrotliGzip の両方を有効にし、さらに image/svg+xml も圧縮範囲に加えました。

HTML、CSS、JS、SVG などのテキスト系リソースはそもそも圧縮に適しており、配信前に圧縮することで、ファーストビューの転送サイズが直接小さくなります。

この最適化は派手ではありませんが、価値があります。「理論的に速くなる」だけでなく、ユーザーが初めてページを開いたときに、最初のリソースダウンロードが本当に軽くなるからです。

第二に、静的リソースのキャッシュ。

この部分もかなり実用的に補完しました。「キャッシュをやった」と曖昧に言うだけではありません。

.css.js.png.jpg.webp.svg、フォントファイル、さらに一部の json/txt には、次のヘッダーを付与しています。

Cache-Control: public,max-age=604800

つまり、1週間のキャッシュです。

考え方は単純です。ユーザーがページを開くたびに、古いリソースを毎回再ダウンロードさせるべきではありません。

特にブログのようなサイトでは、多くのリソースはそもそも頻繁に変更されません。キャッシュがヒットすれば、2回目以降のアクセスが格段に快適になり、不必要なリクエストも減ります。

また、asp-append-version="true" も設定しています。例えば、サイト内の site.csshome.csssite.jsbootstrap.min.css にはバージョンパラメータが付いています。

これにより、リソースを長めにキャッシュしつつ、スタイルやスクリプトが更新された後も、ユーザーが古いファイルを保持し続ける心配がありません。

直接的な利点:

  • 古いリソースは安心してキャッシュできる。
  • ファイルが更新されるとURLが自動的に変わる。
  • 手動でキャッシュをクリアする必要がなく、ユーザーが古いスタイルを取得する心配もない。

第三に、画像の読み込み。

画像については「一律同じ処理」という怠惰な方法は取らず、「リスト画像」と「主要画像」の二種類に分けて処理しました。

記事一覧ページ、トップページのカード、カテゴリページなど、ファーストビュー以外の主要画像は、基本的に次のようにしています。

loading="lazy" decoding="async"

つまり、遅く読み込めるなら遅く、非同期にデコードできるならメインスレッドをブロックしない。

しかし、記事詳細ページのトップカバーなど、より重要な視覚要素については、あえて遅延読み込みはせず、通常の読み込みを維持しつつ、decoding="async"fetchpriority="high" を追加して、本当に優先して表示すべき画像を優先的に表示するようにしました。

個人的には、「すべての画像をlazyにすれば最適化完了」というやり方は好きではありません。実際のページでは、画像の重要度は全く異なり、処理方法も異なるべきです。

第四に、ページレンダリングパスの整理。

この部分は要するに、以下のような厄介な状況を減らすことです。

ページコンテンツがまだ出てこないのに、あれこれのリソースが先にキューに並んでしまう。

例えば、一部の重要でない外部リソースは遅延処理しています。

  • cdnjs に対して preconnect を設定。
  • Font Awesome のスタイルシートは media="print" onload="this.media='all'" 方式で非同期読み込み。
  • Prism のコードハイライトスタイルも同様の処理。
  • 百度統計のスクリプトは、ページ読み込み時に同期的に読み込むのではなく、window.load 後に requestIdleCallback または setTimeout で遅延挿入。

これらの点を個別に見れば大したことではありませんが、組み合わさることでページのリズムがスムーズになります。

まず本当に先に見せるべきものをユーザーに届け、その後にアイコン、統計、拡張スタイルを補う。この順序が何よりも重要だと思います。

第五に、SEOとアクセスエントリの整理。

この部分は表面的にはSEOに見えますが、私はむしろ「サイトのエントリを整理し直す」ことだと考えています。

なぜなら、コンテンツサイトは多くの場合、ページが書けないから死ぬのではなく、以下の理由で死ぬからです。

  • 検索エンジンがそのページが本当に本文なのか判断できない。
  • 同じコンテンツに複数のエントリがあり、重みが分散される。
  • 共有してもリンクだけで、カード情報が不完全。
  • 自分でルーティングを変更したら、過去のエントリとクロールエントリが両方とも切れる。

そこで今回、この部分を以前よりも真剣に補完しました。

まず最も基本的な層:canonical、Open Graph、Twitter Card。

現在、ページは統一してcanonicalを出力し、記事詳細ページでは og:typearticle に、og:image を記事カバーに設定し、公開日時、更新日時、著者などの情報も一緒に含めています。

これらの情報は普段は直接目に見えないかもしれませんが、非常に重要です。

なぜなら、検索エンジン、ソーシャルプラットフォーム、集約ツールはまず、これが記事なのか普通のページなのか、メインリンクはどれか、カバー画像はどれか、を判断する必要があるからです。

これらの基本情報が不完全だと、自分では「ページが開ければいい」と思っていても、検索や共有のシステムはそうは考えません。

さらに、記事ページの構造化データも補完しました。

単にタイトルとdescriptionを書くだけでなく、Article タイプのJSON-LDを直接出力し、以下の情報を含めています。

  • headline
  • description
  • image
  • datePublished
  • dateModified
  • author
  • publisher
  • mainEntityOfPage

これは一般の読者にはほとんど存在感がありませんが、検索エンジンがページのタイプ、本文の正体、公開日時などを理解するのに非常に役立ちます。

次にRSSとsitemapについても、単なる飾りではありません。

RSSは現在、最新10件の記事を自動出力し、空のリンクを置いて体裁を整えるだけではありません。

sitemapもトップページだけでなく、以下のエントリをすべて整理して含めています。

  • トップページ
  • ブログ一覧
  • カテゴリページ
  • 特集ページ
  • タグページ
  • ドキュメントページ
  • ツールページ
  • 各記事詳細ページ

そして、各ノードには lastmodchangefreqpriority が付いています。

これは非常に基本的に見えますが、クロールパスにとっては特に重要です。なぜなら、検索エンジンに対して「どのページがより重要か」「どのページがより頻繁に更新されるか」「どのコンテンツを優先的にクロールすべきか」を明確に伝えることになるからです。

もう一つ、私が個人的に気にしている細かい点は、robots の制御です。

検索結果のようなページは、本来コアコンテンツページとしてインデックスされるべきではないため、特定のエントリには noindex,follow を設定し、不必要なページがインデックスに参加するのを防ぎます。

こうした処理は掃除に似ており、普段は目立ちませんが、後々の手間を大幅に減らせます。

最後に、アクセスエントリと互換性のあるルーティング。

今回、/blog/search/doc/sitemap.xml といったより直感的なエントリもそのまま残しました。

これは単に「URLがきれいに見えるため」ではなく、以下の二つの目的のためです。

  1. ユーザーとクローラーがサイト構造を理解しやすくする。
  2. 将来的にページの構成方法をさらに調整しても、過去のエントリや一般的なアクセスパスが一度にすべて切れることがないようにする。

厳密に言えば、この部分は完全に「ブラウザのレンダリングが速くなる」ということではありません。

しかし、コンテンツサイトにとって、アクセス効率はフロントエンドの数百ミリ秒だけでなく、どのように発見され、クロールされ、共有され、重みを無駄にしないかも含まれます。

そのため、この部分全体を今回の最適化に含めました。

これらは個別に見れば大したことではありません。

しかし、一つ一つ積み重ねることで、体感的な違いは明らかです。

多くの場合、サイトが速くなるのは、ある一つの「神最適化」によるものではなく、本来やるべき小さなことを、一つ一つ正しく行うことによるのです。

もしこのリポジトリを直接動かしてみたい場合

この部分も簡潔に書きます。「なかなか使えそうだ」と思っても、実際に動かそうとしたときにエントリがない、という事態を避けるためです。

1. まず二つのリポジトリをクローン

git clone https://github.com/dotnet9/CodeWF.git
git clone https://github.com/dotnet9/Assets.Dotnet9.git

考え方はシンプルで、一つはサイトコード、もう一つはコンテンツリソースです。

2. ローカルでリソースディレクトリを指定

$env:Site__LocalAssetsDir = "D:\github\owner\Assets.Dotnet9"
dotnet run --project D:\github\owner\CodeWF\src\WebApp

つまり、サイト起動時にリソースリポジトリ内の記事や設定を直接読みに行きます。

3. 記事の置き場所

記事は以下の構造で配置します。

YYYY/MM/slug.md

例:

2026/05/labor-day-ai-rebuilt-my-site.md

4. サイト設定はどこで変更するか

よく使うコンテンツはリソースリポジトリの site ディレクトリにあります。

例えば、

  • site/categories.json
  • site/albums.json
  • site/doc/navigation.json
  • site/tools/tools.json
  • site/blocked-search-keywords.json

つまり、このサイトはバックエンドCMSに強く依存した構造ではありません。

Markdown、JSON、画像を変更するだけで、ほとんどのコンテンツ更新が完了します。

AIは今回、具体的に何をしてくれたのか

この部分は特に述べたいと思います。

なぜなら、多くの人がAIと聞くと、過度に神格化するか、本能的な拒否反応を示すからです。

私自身の感想は、

AIの最も価値のある点は、あなたの代わりに考えることではなく、実行速度を引き上げるのを助けてくれることです。

今回、主に以下のことを手伝ってもらいました。

  • 再構築のアイデア整理。
  • ページやルーティング調整の具体化。
  • README、CI、最小テストセットの補完。
  • 過去のMarkdown構造問題の一掃。
  • 記事構造の整理補助。
  • 記事カバーSVGの生成と調整。
  • バラバラな作業を完全なサイクルにまとめるのを支援。

以前は、多くの作業は「できない」のではなく、あまりに細かく、雑多で、気力を使うため、先延ばしにしてやらなくなっていました。

今はAIのおかげで、方向性が明確で、受け入れ基準が厳格であれば、多くの「やる気が起きない」作業を前に進めてくれます。

今後もAIを使ってさらに多くのツールを作っていく

これも先に言っておきます。

今後もこのサイトをベースに、さらに多くのオンラインツールを作っていきます。

ただし、最初から大きく完全なものを追求するつもりはありません。

考え方はシンプルです。

まずはサイト運営者自身の実際のニーズを満たす。足りないツールがあれば、まずAIに開発を依頼する。

例えば、

  • コンテンツ処理の小さなツール
  • 開発補助の小さなツール
  • 画像やテキスト変換ツール
  • 日常のサイト運営、コーディング、記事執筆に密着した実用的なツール

これには二つの利点があります。

第一に、ツールが数を稼ぐためではなく、実際に使われること。

第二に、実際の使用シナリオがあることで、ツールが少しずつ磨かれやすいこと。

こんなサイトを作る意味はもうあまりない、と言う人もいる

この意見は理解できます。

もしトラフィック、収益化、プラットフォームの配信効率だけを考えるなら、多くの独立した技術サイトは必ずしも最適解ではありません。

そのため、もし誰かが、

「でも今は、こんなサイトを作る意味はあまりない気がする」

と言ったら、私の答えは非常にストレートです。

はい、半分は同意します。

私にとっての意味は、主にどれだけ多くの人が見てくれるかではありません。

より重要なのは二つのことです。

  1. ここ数年自分の書いた記事の記録を示すこと。
  2. 達成感を満たすこと。

誰かが見てくれるなら、もちろん嬉しい。

誰も見なくても、それでも作り続けます、ハハ。

なぜなら、それはもともと自分のコンテンツの拠点であり、プロジェクトのショーケースであり、長期間にわたって何かを蓄積できる場所だからです。

提案もPRも歓迎します

もしこのサイトを使ったり、リポジトリのコードを見たりして、何かフィードバックがあれば、大歓迎です。

以下のリポジトリでお待ちしています。

フィードバックの内容としては、

  • ページの体験に関する問題
  • 検索体験に関する問題
  • Markdownレンダリングの問題
  • リソース構成の提案
  • 新しいツールのアイデア
  • 文章や誤字の修正
  • 直接PRを送る

サイトリポジトリでもリソースリポジトリでも、一緒に改善していきましょう。

最後に一言

今回の再構築を終えて、一番の感想は「AIはすごい」ではありません。

むしろ、

AIを使いこなせる人は、以前よりもずっと楽に、そして速くなる。

AIを拒否するのは急がないでください。

まず、どうやって要件を出し、タスクを分解し、結果を検証し、AIを効率的なコラボレーションアシスタントとして使うかを学んでください。

そうすれば、今まで面倒で、取り掛かりたくなくて、先延ばしにしていた多くのことが、本当にできるようになることに気づくでしょう。

最後に、ついでに付け加えます。

この記事も同様にAIの支援を受けて完成しました。私が方向性、事実確認、最終稿の確定を担当しました。

もしあなたも個人サイト、コンテンツサイト、ツールサイトを運営しているなら、ぜひ交流しましょう。

さらに探索

関連読書

その他の記事
同じカテゴリ / 同じタグ 2026/05/25

CodeWF.Markdown:PDFテキストはコピー可能、画像は埋め込み可能。WeChat公式アカウント/知乎/掘金にコピーしてもHTMLソースが表示されない

CodeWF.Markdown と Vex における Markdown のエクスポートと公開コピーの技術実装を共有:MarkdownDocumentExporter、ExportKind、共有画像読み込み、SVG/GIF/WebP のラスタライズ、Word 埋め込みメディアリソース、テキスト選択可能なPDF、Windows CF_HTML リッチHTMLクリップボード、拡張可能なレイアウトテーマ。

続きを読む
同じカテゴリ / 同じタグ 2026/05/25

CodeWF.Markdown:Avalonia 12 ベースの Markdown レンダリングコントロール

この記事では、CodeWF.Markdown のリポジトリアドレス、NuGet インストール方法、フルパッケージライン、Lite パッケージライン、リアルタイム編集プレビュー、タイポグラフィテーマ、コードハイライト、画像プレビュー、数式、複数ビューアのカバレッジ、インクリメンタルレンダリング機能について紹介します。

続きを読む
同じカテゴリ / 同じタグ 2026/05/24

CodeWF.AvaloniaControls に新しい Guide ガイドコントロールを追加:AtomUI Tour から Vex への実装

CodeWF.AvaloniaControls に追加された Guide ガイドコントロールを紹介し、マスクハイライト、ポップアップの位置決め、動的メニュー MenuItem ガイド、非モーダルヒント、TabItem 切り替え、および Vex での初回起動ガイドの実装に重点を置いています。

続きを読む
同じカテゴリ / 同じタグ 2026/05/18

枝见 Zhijian:Avalonia を使用した Markdown マインドマップエディター

この記事では、Avalonia ベースのローカルマインドマップエディター「枝见 Zhijian」を紹介します。空の新規作成、フォルダ読み込み、正確な初心者ガイド、macOS ショートカットキー対応、アウトライン/Markdown/マインドマップの同期、ノードメモ、ミニマップ、ズーム、キャンバスドラッグ、Markdown/OPML/XMind ファイルの交換をサポートしています。

続きを読む