外部JSゼロ・爆速・プライバシー配慮の自作コンポーネントをブログに追加した話

更新日:
作成日:
約5分で読めます

どーも、ちょりんだです。

なぜ「外部JSゼロ」にこだわったのか

モダンなWeb開発では、ReactやVue、あるいは各種UIライブラリの導入が当たり前になっています。しかし、個人ブログのような小規模サイトでそれらを導入すると、以下の課題が生じます。

  • バンドルサイズの肥大化:使わない機能まで読み込まれる
  • プライバシー懸念:CDN経由の外部スクリプトはユーザーの行動を追跡する可能性がある
  • 表示速度の劣化:追加のHTTPリクエストとJS実行コスト
  • メンテナンス負担:ライブラリアップデートや脆弱性対応

特にブログは「読む」ことが主目的です。UIの派手さより、コンテンツが素早く表示されることが最優先です。

実装したコンポーネント群

高優先:読者体験を直結する機能

⏱️ 読了時間表示

// 文字数÷600字/分で計算(日本語の平均読書速度)
const minutes = Math.max(1, Math.ceil(charCount / 600));
  • ビルド時生成:Astroのビルドプロセスで計算
  • JSゼロ:サーバーサイドで完結
  • 表示例:「約3分で読めます」

📑 目次(ToC)

  • 見出しから自動生成:h2/h3を抽出
  • スクロール追従:CSS scroll-margin でスムーズ移動
  • レスポンシブ:モバイルでも見やすいレイアウト

📋 コードコピーボタン

// インラインJSで完結(10行程度)
navigator.clipboard.writeText(code).then(() => {
  btn.textContent = 'Copied!';
  setTimeout(() => (btn.textContent = 'Copy'), 2000);
});

🔗 SNSシェアボタン

  • 外部JSなし<a> タグとURLパラメータのみ
  • 対応サービス:X, はてなブックマーク, LINE
  • プライバシー安全:外部タグやトラッキングなし

中優先:UXを向上させる機能

🌙 ダークモード

// localStorage + prefers-color-scheme
const theme = localStorage.getItem('theme') || 
  (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
document.documentElement.classList.toggle('dark', theme === 'dark');
  • システム設定尊重prefers-color-scheme
  • 状態永続化localStorage
  • FOUC対策:インラインスクリプトで先読み

📊 読了プログレスバー

// パフォーマンス最適化
window.addEventListener('scroll', updateProgress, { passive: true });
  • 固定表示:ページ最上部
  • 滑らかなアニメーション:CSS transition
  • 軽量:5行のJSで実装

🔍 全文検索

  • Pagefind:ビルド時に検索インデックス生成
  • 外部通信なし:クライアントサイドで完結
  • 日本語対応:形態素解析なしでも実用レベル

📄 OGPメタタグ

  • 自動生成:Astroのビルド時
  • Twitter Card対応summary_large_image
  • URL正規化canonical タグ

低優先:あると嬉しい機能

⬆️ トップに戻るボタン

  • 表示条件:300pxスクロール時
  • smooth scrollscrollTo({ behavior: 'smooth' })
  • アクセシビリティaria-label 付き

⬅️➡️ 前後の記事ナビ

  • 静的生成:ビルド時に隣接記事を計算
  • レスポンシブ:スマホで縦並び
  • タイトル省略:2行まで表示

技術的工夫

CSS変数とTailwindの組み合わせ

/* ダークモード対応 */
@custom-variant dark (&:where(.dark, .dark *));

/* コンポーネント */
.bg-white dark:bg-slate-800

インラインJSの活用

  • 小規模な処理:イベントリスナー程度
  • FOUC対策<script is:inline> で先実行
  • パフォーマンス:追加のHTTPリクエストなし

ビルド時最適化

  • 静的生成:可能な限りSSG
  • インデックス生成:Pagefind
  • 画像最適化:将来のOGP自動生成に備え

パフォーマンス計測

Lighthouseスコア(改善前→改善後)

  • Performance: 85→98
  • Accessibility: 92→100
  • Best Practices: 87→98
  • SEO: 95→100

バンドルサイズ

  • JS: 0KB(自作コンポーネントのみ)
  • CSS: 12KB(Tailwind、purge済み)
  • 合計: 約45KB(画像除く)

まとめ

外部ライブラリに頼らず、必要な機能だけを自作することで、以下のメリットが得られました。

  1. 爆速表示:不要なJSの読み込みなし
  2. プライバシー配慮:外部スクリプトやトラッキングなし
  3. メンテナンス性:コード量が少なく、理解しやすい
  4. 学びの機会:Web標準技術の深い理解

もちろん、大規模なアプリケーションではReactやVueの価値は絶大です。しかし、個人ブログのような小規模サイトでは、「シンプルであること」が最強の機能だと改めて実感しました。

リファクタリングはコードだけでなく、アーキテクチャ選択にも適用できる。最小限の依存で最大の価値を。

今後もこのブログを通じて、技術選定の思考プロセスを共有していければと思います。

Share