Next.js、Tailwind CSS、Vercelでプロフェッショナルな個人ブログをゼロから構築:午前2時までバグ修正で苦しむのはやめよう!

Development tutorial - IT technology blog
Development tutorial - IT technology blog

Quick start: 5分で始めよう、細かい説明は後で!

もう午前2時だ。サーバーはうめき声を上げ、あのバグは何度も現れる。誰もが空虚な理論を分析する精神状態ではないだろう。ブログをすぐにスムーズに動かすための、迅速かつ効率的な解決策が必要だ。これは、あなたのブログをあっという間にオンラインにするための、爆速ロードマップだ。

ステップ1:Next.jsプロジェクトの初期化

ターミナルを開き、以下のコマンドを入力してください。これにより、TypeScriptとESLintが統合された新しいNext.jsプロジェクトが初期化されます。個人ブログにはPages Routerで十分なので、App Routerについて尋ねられたらNoを選択してください。


npx create-next-app@latest ten-blog-ngu-quyen --ts --eslint

数秒待ちます。Success! Created ten-blog-ngu-quyen at ...というメッセージが表示されたら完了です。それでは、作成したプロジェクトディレクトリにcdします。


cd ten-blog-ngu-quyen

ステップ2:Tailwind CSSの設定

Tailwindは、従来のCSSと格闘することなく、迅速にUIを作成したい場合の救世主です。以下のコマンドを使用して、プロジェクトにインストールしましょう。


npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

これら2つのコマンドを実行してTailwindをインストールし、tailwind.config.jspostcss.config.jsという2つの重要な設定ファイルを生成します。次に、tailwind.config.jsを開き、contentセクションにTailwindを使用するファイルのパスを追加します。


// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{js,ts,jsx,tsx,mdx}',
    './components/**/*.{js,ts,jsx,tsx,mdx}',
    './app/**/*.{js,ts,jsx,tsx,mdx}',
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};

次に、プロジェクトのメインCSSファイルにTailwindのディレクティブを追加する必要があります。通常は./styles/globals.cssまたは./app/globals.cssですが、選択した構成によって異なります。Pages Routerを使用している場合、編集する必要があるファイルは./styles/globals.cssです。


/* styles/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

/* 必要に応じて、ここにカスタムCSSを追加します */

ステップ3:テスト実行とVercelへのデプロイ

アプリケーションが問題なく動作するか試してみましょう:


npm run dev

ブラウザを開き、http://localhost:3000にアクセスしてください。Next.jsのデフォルトページが表示されれば、すべて順調です。さて、デプロイの段階です!これがVercelの真の利点であり、すべてが驚くほどシンプルです。

  1. プロジェクトがGitHub/GitLab/Bitbucketにコミットされていることを確認します。
  2. Vercel Dashboardにアクセスし、ログインします(アカウントがない場合は登録してください)。
  3. New Projectを選択し、リポジトリをインポートします。Vercelは自動的にこれをNext.jsプロジェクトとして認識し、すべてを設定します。
  4. Deployをクリックします。数分で、あなたのブログは無料の公開URLを持つことになります!

どうですか?バグ探しで眠気を覚ますためのコーヒーをすする時間よりも早くデプロイが完了します!これでブログが動作したので、ひとまず安心できるでしょう。しかし、これはまだ始まりに過ぎません。

詳細な解説:なぜこの3つの組み合わせなのか?

夜が明け、バグも修正されました。それでは、なぜこの技術の組み合わせが個人ブログにとって理想的な選択肢なのか、特にそれらが原因で眠れない夜を避けたい場合に、深く掘り下げて分析してみましょう。

Next.js:単なるピュアReactではない

Next.jsは、決して新しいフレームワークではありませんが、ウェブサイト開発、特に個人ブログのようなコンテンツが豊富なページにとって、計り知れない価値をもたらします。具体的には、以下の点が挙げられます。

  • Server-Side Rendering (SSR) & Static Site Generation (SSG): これらは私がNext.jsに最も惹かれた2つの機能です。あなたのブログのコンテンツは、ユーザーのブラウザがJavaScriptをダウンロードして処理するのを待つのではなく、サーバー上で、またはビルドプロセス中にHTMLとして事前に生成されます。これにより、ページの読み込み速度(performance)とSEOが大幅に改善されます。実際の例として、SSGを使用するブログは100-200msでページを読み込むことができ、一般的なSPAアプリケーションの500-1000msと比べて格段に高速です。Googlebotは、迅速に表示され、コンテンツが利用可能なページを常に優先して、より簡単にindexします。

    
            // getStaticPropsを使ったSSGの例
            // pages/posts/[slug].tsx
            export async function getStaticProps(context) {
              const { slug } = context.params;
              // MarkdownファイルまたはAPIから記事データを取得
              const post = await getPostBySlug(slug);
              return {
                props: { post },
                revalidate: 60 // 60秒ごとにページを再生成
              }
            }
    
            export async function getStaticPaths() {
              // 記事のスラッグのリストを取得
              const posts = await getAllPosts();
              const paths = posts.map(post => ({ params: { slug: post.slug } }));
              return {
                paths,
                fallback: false // すべてのパスがビルド時に生成される場合はfalse
              }
            }
            
  • 自動Router生成: pagesディレクトリ(またはApp Routerを使用する場合はapp)にファイルを作成するだけで、Next.jsが自動的に対応するルーティングを生成します。この機能は、多くの記事を持つブログにとって非常に便利です。
  • API Routes: 仮にあなたの個人ブログが、お問い合わせフォームの送信や閲覧数の統計などの簡単なバックエンド機能を必要としている場合、Next.jsはプロジェクト内に直接APIエンドポイントを構築することを可能にします。これにより、別途サーバーをセットアップする必要がなくなり、時間とリソースを大幅に節約できます。

Tailwind CSS:ユーティリティこそが王道

最初は、Tailwind CSSのユーティリティファーストの哲学に少し抵抗がありました。HTMLにずらりと並んだ長いクラス名を見ると、少し「目が疲れる」と感じるかもしれません。しかし、一度慣れてしまうと、BEMやCSS Modulesのような従来のメソッドには戻りたくなくなります。その理由は一体何でしょうか?

  • 開発速度の向上: HTML/JSXファイルから離れることなくCSSを書くことができます。すべてのプロパティはユーティリティクラスとして提供されています。flexitems-centerjustify-betweenp-4text-lgbg-blue-500のようなクラスを組み合わせるだけで、ユーザーインターフェース(UI)は非常に迅速に完成します。これにより、手書きのCSSと比較して生産性が30-50%向上します。
  • CSSの衝突回避: Tailwindの各クラスは、一意のCSSプロパティを表します。これにより、ある場所でスタイルを変更しても、意図せず他のコンポーネントに影響を与える心配がなくなります。これはUI関連の小さなバグを大幅に減らすのに役立ち、特に大規模プロジェクトで非常に有用です。10万行を超えるCSSを持つ大規模プロジェクトでは、TailwindのおかげでUIバグの数を20%削減できる可能性があります。
  • 最終的なファイルサイズの軽量化: PurgeCSSが組み込まれているため、Tailwindは実際に使用するCSSクラスのみを最終製品にバンドルします。これにより、ブログのサイズが大幅に軽量化され、ページの読み込み速度も向上します。たとえば、平均的なプロジェクトでは、PurgeCSSで最適化された後、CSSファイルのサイズを数百KBから10KB未満に削減できます。

Vercel:シンプルなデプロイ、高いパフォーマンス

VercelはNext.jsを開発している企業であり、そのためこのプラットフォームがNext.jsアプリケーションのデプロイに完璧に最適化されているのは当然のことです。私にとってVercelは、強力で信頼できる「アシスタント」のような存在です。

  • 自動デプロイ(Git連携): Gitリポジトリ(GitHub、GitLab、Bitbucket)にソースコードをプッシュするだけで、Vercelは自動的にブログの新しいバージョンをビルドしてデプロイします。この速度は非常に速く、プッシュした後、水を注ぎに行っている間にブログがデプロイされていることさえあります。これは、手動のCI/CDプロセスに苦労したことのある開発者にとって本当に素晴らしいことです。Next.jsプロジェクトは、Vercel上で通常60-90秒でデプロイされます。
  • グローバルCDN: Vercelは強力なコンテンツデリバリーネットワーク(CDN)を活用しています。これにより、コンテンツはユーザーに最も近いサーバーから配信されるため、あなたのブログは世界中のどこからでも最適な速度でアクセスできます。例えば、ヨーロッパのユーザーは、アメリカからダウンロードするのではなく、最も近いヨーロッパのサーバーからコンテンツを受け取り、レイテンシを100ms未満に削減できます。
  • 個人プロジェクトは無料: VercelのHobbyプラン(無料)は、ほとんどの個人ブログに十分なリソースを提供します。これには、100GBの帯域幅と1日あたり100回のビルドが含まれています。ブログを構築し始めたばかりの場合でも、ホスティング費用について心配する必要はありません。

高度な最適化:コンテンツの最適化と管理

ブログが安定稼働した後、私たちは自然とコンテンツ管理の改善と最適化を探し始めるでしょう。これが、もう少し「高度な」技術を適用する必要がある時です。これは、50,000行のコードベースをリファクタリングする際に私がその価値を痛感した教訓でもあります。つまり、最初から適切な基盤を構築することが非常に重要だということです。

Markdown(MDX)でのコンテンツ管理

HTMLでブログを書くのは、本当に苦痛です!Markdownは完璧な選択肢です。Markdown(またはJSXコンポーネントと組み合わせたMDX)を統合するために、私は通常next-mdx-remoteremark/rehypeのペアのようなライブラリを使用します。この方法では、コンテンツを個別の.mdまたは.mdxファイルに書き、その後Next.jsが自動的にそれらを解析して表示用のHTMLに変換します。


npm install gray-matter next-mdx-remote

例えば、postsディレクトリを作成し、.mdxファイルを格納します。


---
title: 私の最初の投稿
date: '2023-10-26'
excerpt: これはブログ構築に関するサンプル記事です。
---

# MDXからこんにちは!

これがあなたの記事のコンテンツです。<strong>太字</strong>、<em>斜体</em>で書いたり、Reactコンポーネントを使用できます。

<Button variant="primary">続きを読む</Button>

そして、記事ページのgetStaticPropsで、このファイルを読み込んで解析します。


// pages/posts/[slug].tsx
import { serialize } from 'next-mdx-remote/serialize';
import { MDXRemote } from 'next-mdx-remote';
import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';

const POSTS_PATH = path.join(process.cwd(), 'posts');

export default function PostPage({ source, frontMatter }) {
  return (
    <div className="container mx-auto p-4">
      <h1 className="text-4xl font-bold mb-4">{frontMatter.title}</h1>
      <p className="text-gray-500 mb-6">{frontMatter.date}</p>
      <div className="prose lg:prose-xl">
        <MDXRemote {...source} />
      </div>
    </div>
  );
}

export async function getStaticProps({ params }) {
  const postFilePath = path.join(POSTS_PATH, `${params.slug}.mdx`);
  const source = fs.readFileSync(postFilePath);

  const { content, data } = matter(source);

  const mdxSource = await serialize(content, { scope: data });

  return {
    props: {
      source: mdxSource,
      frontMatter: data,
    },
  };
}

// 各記事のパスを生成するためにgetStaticPathsも必要です
export async function getStaticPaths() {
  const postFilePaths = fs
    .readdirSync(POSTS_PATH)
    .filter((path) => /\.mdx?$/.test(path));

  const paths = postFilePaths.map((filePath) => ({
    params: {
      slug: filePath.replace(/\.mdx?$/, ''),
    },
  }));

  return {
    paths,
    fallback: false,
  };
}

next/headを使ったSEO最適化

ブログがあっても誰にも見つけられないのであれば、ないのと同じです。Next.jsは、HTMLの<head>タグを簡単に管理できるHeadコンポーネント(next/headから)を提供しています。これには、タイトル、メタディスクリプション、そしてソーシャルメディアにとって重要なOpen Graphタグが含まれます。これらは検索エンジン最適化(SEO)のための非常に重要な要素です。


import Head from 'next/head';

export default function PostPage({ post }) {
  return (
    <>
      <Head>
        <title>{post.title} | 私のブログ</title>
        <meta name="description" content={post.excerpt} />
        <meta property="og:title" content={post.title} />
        <meta property="og:description" content={post.excerpt} />
        <meta property="og:image" content={post.image || '/default-og-image.jpg'} />
        <meta property="og:type" content="article" />
        <!-- Twitter Cardやcanonicalリンクなどの他のメタタグを追加 -->
      </Head>
      <!-- 記事コンテンツ -->
    </>
  );
}

next/imageを使った画像最適化

高品質な画像はどんなブログにも欠かせない要素ですが、ウェブサイトの読み込みを遅くする最大の要因でもあります。Next.jsのImageコンポーネント(next/imageライブラリ)は、以下の点を含め、画像を自動的に最適化します。

  • 画面サイズに合わせて画像を自動的にリサイズします。
  • WebPなどのモダンなフォーマットに変換します。
  • Lazy loading(画面に表示されたときにのみ画像を読み込みます)。

import Image from 'next/image';

export default function MyComponent() {
  return (
    <Image
      src="/images/my-blog-post-image.jpg"
      alt="記事の画像の説明"
      width={800} // 画像の元のサイズ
      height={450}
      layout="responsive" // 画像がコンテナの幅に合わせて自動的にスケーリングするように設定
      priority // 最初の画面に表示される主要な画像の場合はすぐに読み込む
    />
  );
}

Test Coverage:本番環境からの苦い教訓

私の経験に耳を傾けてください。私はかつて50,000行もの巨大なコードベースをリファクタリングしましたが、そこから得た最大の教訓は、最初から十分なテストカバレッジを持つべきだということです。個人ブログには「やりすぎ」に聞こえるかもしれませんが、

これは私があなたに理解してほしい考え方です。小さなブログであっても、データ処理関数(例:Markdownの解析、RSSフィードの生成)やコアコンポーネントのテストを書くことで、新機能を追加したりライブラリを変更したりする際に、はるかに自信を持つことができます。これは、午前2時まで小さなバグ修正で徹夜する代わりに、安眠できるお守りのようなものです。

ReactコンポーネントのテストにはJestとReact Testing Libraryの使用を検討できます。あるいは、よりシンプルに、ユーティリティ関数の基本的なユニットテストを書いてください。

実践的なヒント:ブログをさらに「魅力的に」する

基本的な要素が揃ったら、ここからは私が個人的にブログを次のレベルに引き上げ、普通のウェブサイトからより面白く、管理しやすい空間にするために適用しているいくつかの「ヒント」を紹介します。

フォントとアイコンのカスタマイズ

独自のフォントセットを使用すると、ウェブサイトのインターフェースに魂と個性が宿ります。Google Fontsは数千もの無料オプションがある巨大な宝庫です。globals.cssファイルに簡単にインポートするか、@next/fontを使用できます(Next.js 13+のApp Routerを使用している場合)。Pages Routerでは、手動でのインポートが依然として一般的な方法です。アイコンに関しては、HeroiconsまたはFont Awesomeが常に素晴らしい選択肢です。


/* styles/globals.css */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap');

html, body {
  font-family: 'Inter', sans-serif;
}

コメントシステム(Comments System)の統合

ブログを本当に生き生きとさせるには、読者からのインタラクションが不可欠です。私は通常、DisqusやUtterances(GitHub Issuesをバックエンドとして利用したい場合)のようなコメントシステムを統合します。これらをNext.jsに統合するのは非常に簡単です。


// components/Comments.tsx
import { useEffect, useRef } from 'react';

const Comments = () => {
  const commentBox = useRef(null);

  useEffect(() => {
    const scriptEl = document.createElement('script');
    scriptEl.setAttribute('src', 'https://utteranc.es/client.js');
    scriptEl.setAttribute('repo', 'YOUR_GITHUB_USERNAME/YOUR_REPO_NAME'); // あなたのリポジトリに置き換えてください
    scriptEl.setAttribute('issue-term', 'pathname');
    scriptEl.setAttribute('label', 'comment');
    scriptEl.setAttribute('theme', 'github-light');
    scriptEl.setAttribute('crossorigin', 'anonymous');
    scriptEl.async = true;

    commentBox.current.appendChild(scriptEl);
  }, []);

  return (
    <div className="mt-10 pt-10 border-t border-gray-200">
      <div ref={commentBox} />
    </div>
  );
};

export default Comments;

Lighthouseを使ったパフォーマンス分析

Chrome DevToolsを開き、Lighthouseタブに切り替えて、監査(audit)を実行してください。Next.jsとVercelはパフォーマンス最適化を非常によく行っていますが、それでも改善点を見つけることができます。典型的な例としては、next/imageを使用していない画像の最適化や、不要なCSS/JSファイルの削除が挙げられます。これにより、Lighthouseスコアを90点から98点以上に引き上げることができます。

高度なCI/CDのためのGitHub Actionsの使用(オプション)

Vercelはすでに非常に優れた自動CI/CD機能を提供しています。しかし、より詳細な制御が必要な場合(例えば、デプロイ前にテストを実行したり、コードスタイルをチェックしたりする場合)は、GitHub Actionsを設定できます。私の記事「ゼロから学ぶGitHub Actionsを使ったCI/CDガイド」を読んでいる方なら、これがそれほど複雑ではないことをご存知かもしれませんが、特殊な要件のない個人ブログにとっては「過剰なエンジニアリング」と見なされるかもしれません。しかし、実践したいのであれば、これは探求するのに素晴らしい遊び場です。

最後に、個人ブログの構築は楽しい旅です。あまり堅苦しく考えず、試行錯誤し、遭遇した「バグ」から学びましょう。あなたのブログが素晴らしいものになることを願っています!

Share: