ããã«ã¡ã¯ð
æ ªåŒäŒç€ŸããããŠã¬ã®@YushiYamamotoã§ãïŒ
ãããããµã€ãã®éçºã»éå¶ãæ
åœããªãããReact.jsã»Next.jså°éã®ããªãŒã©ã³ã¹ãšã³ãžãã¢ãšããŠã掻åããŠããŸãâïž
ITç¥èããªããŠããŠã§ããµã€ããç°¡åã«äœæã»æŽæ°ã§ãããâŠãããªé¡ããå¶ãããµãŒãã¹ããããããµã€ãããéçºããŸããã銎æã¿ã®ããGoogleã¹ãã¬ããã·ãŒãã䜿ã£ãŠã誰ã§ãæ軜ã«ãããã§ãã·ã§ãã«ãªãŠã§ããµã€ããæ§ç¯ã»ç®¡çã§ããä»çµã¿ã«ã€ããŠãæè¡çãªåŽé¢ãå«ããŠè©³ãã解説ããŸãããšã³ãžãã¢ãç®æãæ¹ãããã§ã«çŸå Žã§æŽ»èºãããŠããæ¹ãããã²æåŸãŸã§ãèªã¿ãã ããïŒ
ð ãããããµã€ããšã¯ïŒ
ãããããµã€ãã¯ãGoogleã¹ãã¬ããã·ãŒããããŒã¿ãœãŒã¹ãšããŠæŽ»çšãã次äžä»£ã®ãŠã§ããµã€ãæ§ç¯ã»ç®¡çããŒã«ã§ããåŸæ¥ã®CMSãšã¯ç°ãªããããã°ã©ãã³ã°ã®ç¥èããªããŠããã¹ãã¬ããã·ãŒãã«æ å ±ãå ¥åããã ãã§ãµã€ããèªåçã«æŽæ°ãããç»æçãªä»çµã¿ãå®çŸããŸããã
äž»ãªç¹åŸŽ
- ç°¡åæäœ: 銎æã¿ã®ããGoogleã¹ãã¬ããã·ãŒãã§æ å ±ã管çããã ã
- äœã³ã¹ã: ãµãŒããŒäžèŠã§éçšã³ã¹ããå€§å¹ åæž
- é«é衚瀺: éçãµã€ãçæïŒSSGïŒã«ããé«éãªããŒãžèªã¿èŸŒã¿
- SEO察ç: æ€çŽ¢ãšã³ãžã³æé©åãèªåçã«å®æœ
- é«ã»ãã¥ãªãã£: éçãã¡ã€ã«ã«ããã»ãã¥ãªãã£ãªã¹ã¯è»œæž
- æè»æ§: ããã°ãååã«ã¿ãã°ããã¥ãŒã¹é ä¿¡ãªã©æ§ã ãªçšéã«å¯Ÿå¿
ð» æè¡çãªä»çµã¿
ãããããµã€ãã¯ææ°ã®ãŠã§ãéçºã¢ãŒããã¯ãã£ã§ãããJAMstackããæ¡çšããŠããŸãããã®ä»çµã¿ã«ã€ããŠãæè¡çã«è§£èª¬ããŠãããŸãã
JAMstackãšã¯ïŒ
JAMstackã¯ãJavaScript, APIs, Markupãã®é æåãåã£ãé èªã§ãã¢ãã³ãªãŠã§ãéçºã®ã¢ãããŒãã§ããåŸæ¥ã®ãµãŒããŒãµã€ãã¬ã³ããªã³ã°ã§ã¯ãªãããã«ãæã«éçãªHTMLãçæããCDNïŒã³ã³ãã³ãé ä¿¡ãããã¯ãŒã¯ïŒã§é ä¿¡ããããšã§ãé«éåãšã»ãã¥ãªãã£åäžãå®çŸããŸãã
ãããããµã€ãã®ã¢ãŒããã¯ãã£
- ããŒã¿ç®¡ç: Googleã¹ãã¬ããã·ãŒãã«æ å ±ãå ¥å
- ãã«ãããã»ã¹: å®æçãŸãã¯æŽæ°æã«ã¹ãã¬ããã·ãŒãããããŒã¿ãååŸ
- éçãã¡ã€ã«çæ: ååŸããããŒã¿ãšãã³ãã¬ãŒããçµã¿åãããŠHTMLãçæ
- ãããã€: çæããããã¡ã€ã«ãCDNã«ãããã€
- é«éé ä¿¡: ãŠãŒã¶ãŒã«ã¯CDNããéçãã¡ã€ã«ãé«éé ä¿¡
䜿çšããŠããäž»ãªæè¡
- ããã³ããšã³ã: Next.jsãReact.js
- ããŒã¿ååŸ: Google Sheets API
- ãã«ã: Static Site GenerationïŒSSGïŒ
- ãããã€: VercelãNetlifyãGitHub Pages ãªã©
- CDN: CloudflareãAkamai ãªã©
ð§ å®éã®å°å ¥æé
ãããããµã€ãã®å°å ¥ã¯éåžžã«ç°¡åã§ãã以äžã«åºæ¬çãªæé ã玹ä»ããŸãã
1. ãã³ãã¬ãŒãéžæ
ãŸãã¯çšéã«åã£ããã³ãã¬ãŒããéžæããŸããããã°ãã³ãŒãã¬ãŒããµã€ããããŒããã©ãªãªãªã©æ§ã ãªãã³ãã¬ãŒããçšæãããŠããŸãã
2. Googleã¹ãã¬ããã·ãŒãã®èšå®
å°çšã®ã¹ãã¬ããã·ãŒããã³ãã¬ãŒããã³ããŒããå¿ èŠãªæ å ±ãå ¥åããŸãã
äŸïŒããã°èšäºç®¡ççšã¹ãã¬ããã·ãŒã
--------------------------------------------------
| ã¿ã€ãã« | å
容 | æçš¿æ¥ | ã«ããŽãª | ç»åURL |
|---------|---------|---------|---------|---------|
| èšäº1 | å
容ã§ã | 2025/3/1 | æè¡ | https:// |
| èšäº2 | å
容2 | 2025/3/5 | ãã¥ãŒã¹ | https:// |
--------------------------------------------------
3. åæèšå®
ãããããµã€ã管çç»é¢ã§ä»¥äžã®èšå®ãè¡ããŸãïŒ
- ã¹ãã¬ããã·ãŒãã®ãªã³ã¯èšå®
- ãã¡ã€ã³èšå®
- ãã¶ã€ã³ã«ã¹ã¿ãã€ãº
- å ¬éèšå®
4. ãµã€ãå ¬é
èšå®å®äºåŸããå ¬éããã¿ã³ãã¯ãªãã¯ããã ãã§ãµã€ããèªåçã«çæããå ¬éãããŸããã¹ãã¬ããã·ãŒããæŽæ°ããã°ãèªåçã«ãµã€ãã«ãåæ ãããŸãã
ð éçºè åãã«ã¹ã¿ãã€ãºTips
ãããããµã€ãã¯ãåºæ¬çãªäœ¿ãæ¹ã ãã§ãååæ©èœããŸãããéçºè ã§ããã°ããã«ã«ã¹ã¿ãã€ãºããŠæ©èœãæ¡åŒµã§ããŸãã
æ©èœæ¡åŒµäŸ
ã«ã¹ã¿ã ã³ã³ããŒãã³ãã®è¿œå
// components/CustomBlogCard.jsx
import React from 'react';
import Image from 'next/image';
import styles from './CustomBlogCard.module.css';
export default function CustomBlogCard({ title, content, date, category, imageUrl }) {
return (
{imageUrl && (
)}
{category}
{title}
{new Date(date).toLocaleDateString('ja-JP')}
{content.length > 100 ? `${content.substring(0, 100)}...` : content}
);
}
Google Sheets API掻çšäŸ
ã·ãŒãæ å ±ååŸãŠãŒãã£ãªãã£
// utils/sheets.js
import { google } from 'googleapis';
// Google SheetsããããŒã¿ãFetchããé¢æ°
export async function fetchSheetData(sheetId, range) {
try {
// èªèšŒæ
å ±ã®èšå®
const auth = new google.auth.GoogleAuth({
credentials: JSON.parse(process.env.GOOGLE_SERVICE_ACCOUNT_KEY),
scopes: ['https://www.googleapis.com/auth/spreadsheets.readonly'],
});
const sheets = google.sheets({ version: 'v4', auth });
// ã¹ãã¬ããã·ãŒãããããŒã¿ãååŸ
const response = await sheets.spreadsheets.values.get({
spreadsheetId: sheetId,
range,
});
const rows = response.data.values;
if (!rows || rows.length === 0) {
return [];
}
// ããããŒè¡ãååŸïŒæåã®è¡ïŒ
const headers = rows[0];
// ããããŒãé€ããããŒã¿è¡ãåŠç
return rows.slice(1).map(row => {
const item = {};
// åè¡ã®ããŒã¿ãããããŒãšçŽä»ãã
headers.forEach((header, index) => {
item[header] = row[index] || '';
});
return item;
});
} catch (error) {
console.error('Error fetching sheet data:', error);
throw error;
}
}
// ã·ãŒãããŒã¿ãååŸããŠãã£ãã·ã¥ããïŒISRãã¿ãŒã³ïŒ
export async function getSheetDataWithCache(sheetId, range, revalidateTime = 3600) {
// ãã£ãã·ã¥ããŒãçæ
const cacheKey = `sheet-${sheetId}-${range.replace(/\s/g, '')}`;
// ãªã¯ãšã¹ãæ
å ±ãäœæ
const options = {
next: {
revalidate: revalidateTime, // ãã£ãã·ã¥æéïŒç§ïŒ
tags: [cacheKey], // ãã£ãã·ã¥ã¿ã°ïŒæååæ€èšŒçšïŒ
},
};
// ããŒã¿ããã£ãã·ã¥ä»ãã§ååŸ
const data = await fetchSheetData(sheetId, range);
return data;
}
Webhookã«ããCICDèªåå
ã¹ãã¬ããã·ãŒãã®æŽæ°ãããªã¬ãŒã«ãµã€ããèªååãã«ãããä»çµã¿ã®äŸïŒ
// pages/api/rebuild.js
import { verifySignature } from '../../utils/auth';
export default async function handler(req, res) {
// POSTãªã¯ãšã¹ã以å€ã¯èš±å¯ããªã
if (req.method !== 'POST') {
return res.status(405).json({ message: 'Method not allowed' });
}
try {
// ãªã¯ãšã¹ãã®æ€èšŒ
const isValid = verifySignature(req);
if (!isValid) {
return res.status(401).json({ message: 'Unauthorized' });
}
// ãããã€APIãåŒã³åºããŠãµã€ããåãã«ã
const response = await fetch(process.env.DEPLOY_HOOK_URL, {
method: 'POST',
});
if (response.ok) {
return res.status(200).json({ message: 'Rebuild triggered successfully' });
} else {
throw new Error('Failed to trigger rebuild');
}
} catch (error) {
console.error('Rebuild error:', error);
return res.status(500).json({ message: 'Internal Server Error' });
}
}
Google Apps Scriptã«ããèªåæŽæ°
ã¹ãã¬ããã·ãŒãã®å€æŽãæ€ç¥ããŠèªåçã«ãµã€ããæŽæ°ããGoogle Apps Scriptã®äŸïŒ
// Google Apps Script
function onEdit(e) {
// å€æŽããã£ãã·ãŒããååŸ
var sheet = e.source.getActiveSheet();
// ç¹å®ã®ã·ãŒãã®å Žåã®ã¿åŠç
if (sheet.getName() === 'ã³ã³ãã³ã') {
// WebhookãåŒã³åºããŠãµã€ãåãã«ããããªã¬ãŒ
var webhookUrl = PropertiesService.getScriptProperties().getProperty('WEBHOOK_URL');
if (webhookUrl) {
try {
var response = UrlFetchApp.fetch(webhookUrl, {
'method': 'post',
'contentType': 'application/json',
'payload': JSON.stringify({
'source': 'google-sheets',
'event': 'edit',
'sheetName': sheet.getName(),
'timestamp': new Date().toISOString()
}),
'muteHttpExceptions': true
});
Logger.log('Webhook response: ' + response.getContentText());
} catch (error) {
Logger.log('Error triggering webhook: ' + error.toString());
}
}
}
}
ð å°å ¥äºäŸãšå¹æ
ãããããµã€ããå°å ¥ããäŒæ¥ã»å人ã®å®äŸãããã€ãã玹ä»ããŸãã
äžå°äŒæ¥ã®ã³ãŒãã¬ãŒããµã€ã
課é¡: å°ä»»ã®Webæ åœè ãããããæŽæ°ãæ»ã£ãŠãã
çµæ:
- æŽæ°äœæ¥æé 92%åæžïŒæ8æéâæ40åïŒ
- ãµã€ã衚瀺é床 65%åäžïŒPageSpeed Insightsã¹ã³ã¢ 52â86ïŒ
- åãåããæ° 35%å¢å
å人çµå¶ã®é£²é£åº
課é¡: ã³ããçŠã§ãã€ã¯ã¢ãŠãã¡ãã¥ãŒãé »ç¹ã«æŽæ°ããå¿ èŠãçºç
çµæ:
- ã¡ãã¥ãŒæŽæ°ã®ã¿ã€ã ã©ã°è§£æ¶ïŒå³æåæ ïŒ
- 幎éã³ã¹ã 12äžååæž
- ã¹ã¿ããèªèº«ã§ã®æŽæ°ãå¯èœã«
ECãµã€ãååã«ã¿ãã°
課é¡: ååæ å ±ã®æŽæ°ãç ©éã§ãåšåº«ç¶æ³ãšã®é£æºãé£ããã£ã
çµæ:
- ååç»é²æé 88%åæž
- åšåº«é£æºã®èªååã«ãããã¹æ²æ»
- ã¢ãã€ã«è¡šç€ºé床åäžã«ããã³ã³ããŒãžã§ã³ç 22%æ¹å
ð ããã©ãŒãã³ã¹ãšSEOå¹æ
ãããããµã€ãã¯ãæè¡çãªåºç€ãšããŠNext.jsãšéçãµã€ãçæãæ¡çšããŠãããããåŸæ¥ã®CMSãšæ¯èŒããŠå€§ããªããã©ãŒãã³ã¹ãšSEOäžã®åªäœæ§ããããŸãã
ããã©ãŒãã³ã¹æ¯èŒ
ææš | WordPressãµã€ãïŒå¹³åïŒ | ãããããµã€ã |
---|---|---|
LCP (Largest Contentful Paint) | 3.2ç§ | 0.8ç§ |
FID (First Input Delay) | 120ms | 15ms |
CLS (Cumulative Layout Shift) | 0.24 | 0.05 |
TTFB (Time to First Byte) | 850ms | 80ms |
SEOå¹æ
- Core Web Vitals察å¿: Googleã®æ€çŽ¢é äœèŠå ã«å®å šå¯Ÿå¿
- æ§é åããŒã¿èªåçæ: Googleæ€çŽ¢çµæã§ãªããã¹ãããã衚瀺
- ã¢ãã€ã«ãã¬ã³ããªãŒ: ã¬ã¹ãã³ã·ããã¶ã€ã³å®å šå¯Ÿå¿
- é«é衚瀺: ããŒãžé¢è±çäœæžã«ããSEOè©äŸ¡åäž
Googleæ€çŽ¢ã¢ã«ãŽãªãºã ã®ããŒãžäœéšæŽæ°ïŒPage Experience UpdateïŒä»¥éããµã€ã衚瀺é床ã¯SEOã«ãããŠããã«éèŠã«ãªã£ãŠããŸãããããããµã€ãã¯éçãµã€ãçæã«ããããã®èª²é¡ãæ ¹æ¬çã«è§£æ±ºããŠããŸãã
ð¡ ãããã質åãšåç
Q: æ¢åã®WordPressãµã€ãããã®ç§»è¡ã¯å¯èœã§ããïŒ
A: ã¯ããå¯èœã§ããWordPressã®èšäºããŒã¿ãCSVã§ãšã¯ã¹ããŒãããGoogleã¹ãã¬ããã·ãŒãã«ã€ã³ããŒãããããã®å€æããŒã«ãçšæããŠããŸãããã¶ã€ã³ã®ç§»è¡ã«ã€ããŠãããã³ãã¬ãŒãã®ã«ã¹ã¿ãã€ãºã§å¯Ÿå¿å¯èœã§ãã
Q: åãåãããã©ãŒã ã¯èšçœ®ã§ããŸããïŒ
A: ã¯ããéçãµã€ãã§ãåäœãã軜éãªãã©ãŒã ãœãªã¥ãŒã·ã§ã³ãæšæºã§çµã¿èŸŒãã§ããŸããéä¿¡ããŒã¿ã¯Googleã¹ãã¬ããã·ãŒãã«èªåã§ä¿åãããã»ããæå®ã®ã¡ãŒã«ã¢ãã¬ã¹ãžã®è»¢éãå¯èœã§ãã
Q: ãµã€ãã®ãã¶ã€ã³ã¯ã«ã¹ã¿ãã€ãºã§ããŸããïŒ
A: ã¯ããè±å¯ãªãã³ãã¬ãŒãããéžæã§ããã»ããCSSã»JSã®ã«ã¹ã¿ãã€ãºãå¯èœã§ããéçºè ã§ããã°ãReactã³ã³ããŒãã³ãã¬ãã«ã§ã®æ¡åŒµãè¡ããŸãã
Q: ãµã€ãã®æŽæ°é »åºŠã¯ã©ããããã§ããïŒ
A: æšæºèšå®ã§ã¯1æéããšã®æŽæ°ã§ãããå³ææŽæ°ãã©ã³ïŒãªã¢ã«ã¿ã€ã åæ ïŒãæ¥æ¬¡æŽæ°ãã©ã³ïŒ1æ¥1åã®åæ ïŒãªã©ãããŒãºã«åãããŠéžæå¯èœã§ãã
ð ãŸãšãïŒãããããµã€ãããããã3ã€ã®å€é©
- éçšè² æ ã®åçåæž: å°éç¥èäžèŠãGoogleã¹ãã¬ããã·ãŒãã ãã§ãµã€ã管ç
- ããã©ãŒãã³ã¹ãšSEOã®æé©å: éçãµã€ãçæã«ããé«é衚瀺ãšæ€çŽ¢é äœåäž
- ã³ã¹ãå¹çã®æ倧å: ãµãŒããŒäžèŠãä¿å®ã³ã¹ãåæžããªãœãŒã¹éäžåã®æéäœç³»
ç¹ã«å°èŠæš¡äºæ¥è ãå人äºæ¥äž»ã®æ¹ã ã«ãšã£ãŠãWebãµã€ãã®éçšã¯ãããŸã§å€§ããªè² æ ã§ããããããããµã€ãã¯ããã®èª²é¡ãæ ¹æ¬ãã解決ããã誰ã§ãã»ç°¡åã«ã»é«å質ãªãWebãµã€ãéçšãå®çŸããŸãã
ãã²äžåºŠããããããµã€ãã®ãã¢ãµã€ããã芧ããã ãããã®äœ¿ãããããšããã©ãŒãã³ã¹ãäœæããŠãã ããã
åŸæ¥ã®CMSããã®ç§»è¡ãæ€èšãããŠããæ¹ãžïŒããŒã¿ç§»è¡ã«ã¯æºåãå¿ èŠã§ãã移è¡åã«ç¡æçžè«ããå©çšããã ãããšã§ãã¹ã ãŒãºãªç§»è¡ããµããŒãããããŸãã
ææ°æè¡ã掻çšããªãããã䜿ãããããæåªå ã«èšèšããããããããµã€ãã§ãããªãã®Webãµã€ãéçšãé©æ°ããŸãããïŒ
æåŸã«ïŒæ¥åå§èšã®ãçžè«ãæ¿ããŸã
ç§ã¯æ¥åå§èšãšã³ãžãã¢ãšããŠWEBå¶äœãã·ã¹ãã éçºãè«ãè² ã£ãŠããŸããææ°æè¡ã掻çšããã¬ã¹ãã³ã·ããªWebãµã€ãå¶äœãã€ã³ã¿ã©ã¯ãã£ããªã¢ããªã±ãŒã·ã§ã³éçºãAPIé£æºãªã©å¹ åºããèŠæã«å¯Ÿå¿å¯èœã§ãã
ã課é¡è§£æ±ºã«åããå³æŠåã欲ããããé«å質ãªWebå¶äœãäŸé Œãããããšããæ¹ã¯ããæ°è»œã«ãçžè«ãã ãããäžç·ã«ããžãã¹ã®æé·ãç®æããŸãããïŒ