【テクニカル・上級編】Notionで美しいポートフォリオ・Webサイトを作る方法:おすすめの公開ツールとデザインのコツ – プロジェクト・ナレッジ管理活用バイブル

Notionを究極のヘッドレスCMSとして狂わせる:超高速ポートフォリオ&Webサイト構築の全技術

エンジニアリング組織のベロシティを最大化するナレッジマネジメントにおいて、情報のサイロ化を防ぎ、かつ美しく構造化されたアウトプットを生成することは至上命題だ。ドキュメントツールとして認知されているNotionを、単なるメモ帳ではなく、「動的アジリティを備えた高密度なヘッドレスCMS」として再定義する。

「綺麗に整えられたNotionページをそのままWebに公開したい」——その素朴な要求を、エンタープライズレベルのパフォーマンス、堅牢なCI/CDパイプライン、そして圧倒的な美しさをもって実現する方法論をここに解き明かす。

—

1. アーキテクチャ選定:ネイティブ公開 vs 外部ホスティングの解剖学的比較

NotionのコンテンツをWebに露出させるアプローチは、主に3つのレイヤーに大別される。それぞれの内部アーキテクチャとボトルネックを把握せずして、モダンなWebサイトは作れない。

[Notion Database / Pages]
│
├── (A) Notion Native Publish ──> [Notion CDN (Edge)] ※最速・制限多
│
├── (B) Super / Potion ──> [Vercel / Edge Workers] ※デザイン特化・要コスト
│
└── (C) Custom SSG (Next.js) ──> [GitHub Actions ──> AWS S3 / CloudFront] ※完全制御

A. Notionネイティブ「Webとして公開」

  • アーキテクチャ: Notionのバックエンドが直接HTMLをレンダリングし、独自のCDN経由で配信。
  • メリット: 設定ゼロ。リアルタイム同期。
  • 致命的デメリット: 独自ドメインの制限(プラン依存)、SEO最適化(OGPやメタタグ)の制御不能、CSSハックによるレイアウト崩壊のリスク。エンジニアのプライドが許さないブラックボックス性。

B. Super / Potion等の外部ホスティングサービス

  • アーキテクチャ: Notion APIからデータをインジェストし、Vercel等のEdgeワーカー上で独自デザインシステムを適用してSSR/SSG配信。
  • メリット: 美しいカスタムドメイン、高度なSEO設定、ダークモード、独自CSS/JSインジェクション。
  • デメリット: サブスクリプションコスト。APIのレートリミットに起因するビルド遅延。

C. 【エキスパート推奨】完全自製SSGパイプライン(Notion API × Next.js × GitHub Actions)

  • アーキテクチャ: Notion APIでDBをクリーンなJSONとして取得し、静的サイトジェネレータ(Next.js App Router等)でビルド、CDN(Cloudflare Pages / AWS CloudFront)へデプロイ。
  • メリット: 完全な制御。ゼロランタイムコスト。無限のカスタマイズ性。

—

2. Super / Potionを極限までハックするデザイン構築の極意

もし迅速な立ち上げと美観を両立させるためにSuperやPotionを採用する場合、デフォルトのテンプレートをそのまま使う素人仕事をしてはならない。DOM構造をハックし、真のポートフォリオに昇華させる技術的アプローチを解説する。

CSSインジェクションによる「Notion臭」の完全消去

Notion製サイトが「それっぽく」見えてしまう最大の理由は、固有のブロッククラスや不要なUI要素(カバー画像のマージン、ホバー時のリンクアイコンなど)にある。これをカスタムCSSで完全に無力化する。

/ — Notion特有の冗長なUIを削ぎ落とすミニマリズムCSS — /

/ ページ全体のリセットとフォント最適化 /
body {
font-family: ‘Inter’, var(–font-sans), -apple-system, sans-serif !important;
background-color: #0a0a0c !important;
color: #ededef !important;
letter-spacing: -0.01em;
}

/ Notionの象徴的な不要アイコン・ホバーリンクの非表示 /
.notion-focusable-token,
.anchorjs-link,
.notion-collection-card-property-icon {
display: none !important;
}

/ データベースビュー(ギャラリー)のサイバーパンク風モダナイズ /
.notion-collection-card {
background: rgba(255, 255, 255, 0.03) !important;
border: 1px solid rgba(255, 255, 255, 0.08) !important;
border-radius: 12px !important;
transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1) !important;
}

.notion-collection-card:hover {
transform: translateY(-4px);
border-color: rgba(99, 102, 241, 0.5) !important; / Indigo accent /
box-shadow: 0 12px 30px -10px rgba(99, 102, 241, 0.3) !important;
}

—

3. 【実践】Notion API × GitHub Actions による完全自動ビルドパイプライン

「ポートフォリオの更新=Notionに書くだけ」を実現しつつ、ビルドの堅牢性を担保するカスタムCI/CDパイプラインの実装コードを公開する。Notionのデータベース構造を変更した際にも破綻しない、堅牢なTypeScriptスクリプトの断片だ。

データの整合性を担保する同期スクリプト (`scripts/sync-notion.ts`)

import { Client } from ‘@notionhq/client’;
import as fs from ‘fs’;
import as path from ‘path’;

// Notionクライアントの初期化(Envからセキュアに取得)
const notion = new Client({ auth: process.env.NOTION_API_KEY });
const DATABASE_ID = process.env.NOTION_DATABASE_ID as string;

async function fetchPortfolioData() {
try {
console.log(‘⚡ Fetching data from Notion Edge DB…’);
const response = await notion.databases.query({
database_id: DATABASE_ID,
filter: {
property: ‘Status’,
status: {
equals: ‘Published’, // ステータスがPublishedのものだけを抽出
},
},
sorts: [
{
property: ‘Date’,
direction: ‘descending’,
},
],
});

const parsedData = response.results.map((page: any) => ({
id: page.id,
title: page.properties.Name.title[0]?.plain_text || ‘Untitled’,
slug: page.properties.Slug.rich_text[0]?.plain_text || page.id,
tags: page.properties.Tags.multi_select.map((tag: any) => tag.name),
date: page.properties.Date.date?.start || page.created_time,
}));

const outputPath = path.join(process.cwd(), ‘data’, ‘portfolio.json’);
fs.writeFileSync(outputPath, JSON.stringify(parsedData, null, 2));
console.log(`✅ Successfully synced ${parsedData.length} records to ${outputPath}`);
} catch (error) {
console.error(‘❌ Failed to sync with Notion API:’, error);
process.exit(1);
}
}

fetchPortfolioData();

GitHub Actionsワークフロー (`.github/workflows/deploy.yml`)

Notion側でWebhooks(または定期実行cron)をトリガーし、常に最新のポートフォリオを静的ホスティングへ反映させる。

name: CI/CD – Notion Portfolio Sync & Deploy

on:
schedule:

  • cron: ‘0 /4 ‘ # 4時間ごとにNotionの変更をポーリング

workflow_dispatch: # 手動実行も許可

jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:

  • name: Checkout Repository

uses: actions/checkout@v4

  • name: Set up Node.js

uses: actions/setup-node@v4
with:
node-version: ’20’
cache: ‘npm’

  • name: Install Dependencies

run: npm ci

  • name: Run Notion Sync Script

env:
NOTION_API_KEY: ${{ secrets.NOTION_API_KEY }}
NOTION_DATABASE_ID: ${{ secrets.NOTION_DATABASE_ID }}
run: npx ts-node scripts/sync-notion.ts

  • name: Build Static Site

run: npm run build

  • name: Deploy to Cloudflare Pages / Vercel

uses: cloudflare/pages-action@1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: ‘notion-expert-portfolio’
directory: ‘.next’
gitHubToken: ${{ secrets.GITHUB_TOKEN }}

—

4. パフォーマンス最適化とエッジハック

Notion APIや外部サービスを利用する上で最も直面しやすいのが、「アセット(画像)の読み込み遅延」と「APIのレートリミット(3回/秒)」だ。これらを克服する実践的なエンジニアリング知見を共有する。

1. Notion画像URLの有効期限問題への対策:
Notionの画像ブロック(`block.image.file.url`)が発行するAWS S3の署名付きURLは、数時間で有効期限切れになる。これをそのままフロントエンドで描画すると、数時間後に画像がリンク切れを起こす。

  • 解決策: ビルド時(またはSSG生成時)に画像をキャプチャし、CloudinaryやAWS S3等の中間ストレージへアップロードし直すミドルウェア関数をパイプラインに組み込むこと。

2. インクリメンタル・静的再生成(ISR)の活用:
全ページを毎回ビルドするのではなく、Next.jsの `revalidate` プロパティを活用し、Notionからの変更リクエスト(Webhook経由)に応じてオンデマンドでキャッシュをパージする設計にせよ。これにより、Notionの編集からWeb反映までのレイテンシーを1秒以内に抑え込める。

—

5. 結び:ナレッジの生産性と表現の美しさは両立する

ドキュメントを書くスピード感、データベース構造の柔軟性、そしてエンジニアリングによるデザインとパフォーマンスの制御。これらを高次元で融合させたとき、Notionを用いたポートフォリオ/Webサイト構築は、単なる「お手軽ツール」の枠を超え、最も洗練されたモダンWeb開発のワークフローへと変貌する。

妥協のないコードとアーキテクチャで、あなたのキャリアと知見を世界へ最速でアウトプットせよ。

タイトルとURLをコピーしました