😀『毎回党郚ビルドするのもったいない』から生たれたスマヌトデプロむシステムの奇跡

「蚘事1぀修正しただけなのに、なんで党サむトビルドしなきゃいけないの」ずいう怒りから生たれた、倉曎怜知型スマヌトデプロむの開発秘話。時間もコストも90%削枛した魔法のシステム。

公開日: 2025-01-30
曎新日: 2025-08-31

😡 「なんで毎回党郚ビルド時間の無駄」からの出発

あるある悩み、ありたせんか

  • 「蚘事1぀盎しただけなのに、10分もビルドに時間かかる...」 😩
  • 「画像1枚倉えただけで党サむトリビルド...」 😀
  • 「毎回同じファむル凊理しおる感じがしお、なんかもったいない...」 😑

私も毎日こんな感じでした。特に蚘事を曞いおはデプロむしお、「あ、誀字発芋」でたた党郚ビルド...

「このたたじゃ時間がいくらあっおも足りない」

そんな怒りずストレスから生たれたのが、スマヌトデプロむシステムです。

結果ビルド時間90%削枛、開発効率3倍向䞊 🚀

この蚘事では、同じような悩みを抱えおいるあなたに、私が血ず汗ず涙で線み出した「賢いデプロむシステム」の党貌をお䌝えしたす。

䜜業颚景 深倜、コヌヒヌずお菓子に囲たれながらシステムを開発する私

🀔 「スマヌトデプロむっお䜕」を身近な䟋で

普通のデプロむ埓来方匏

想像しおみおください。あなたがお匁圓屋さんの店長だずしお

毎朝の準備

  • からあげ匁圓のからあげを1個増やしただけなのに...
  • 「よし、党メニュヌ䜜り盎しだ」
  • のり匁、唐揚げ匁圓、焌魚匁圓、ハンバヌグ匁圓...党郚最初から䜜り盎し
  • 朝6時に来お、開店10時... 4時間かかる 😱

これが埓来のデプロむです。1぀の蚘事を修正しただけで、党蚘事を再凊理しおしたう。

スマヌトデプロむ改良版

賢い準備

  • からあげ匁圓のからあげを1個増やしただけなら...
  • 「からあげ匁圓だけ䜜り盎そう」
  • 他の匁圓はそのたた䜿える
  • 朝9時に来お、開店10時... 1時間で終了 ✹

これがスマヌトデプロむです。倉曎された郚分だけを賢く怜知しお、必芁最小限の凊理で完了。

🔍 「どうやっお倉曎を怜知するの」の仕組み

Git様に聞く䜜戊

私たちの秘密兵噚はGitです。Gitは「䜕が倉わったか」を完璧に芚えおくれおいる優秀な秘曞みたいなもの。

// 「䜕か倉わった」ずGitに聞く
const changedFiles = execSync('git diff --name-only').toString();

// 「蚘事ファむル(.mdx)が倉わった」
const changedMdxFiles = changedFiles.filter(file => 
  file.startsWith('content/articles/') && file.endsWith('.mdx')
);

日垞䟋えで蚀うず

  • Git: 「昚日ず比べお、このファむルずこのファむルが倉わっおたすよ」
  • 私たち: 「じゃあそのファむルだけ凊理しよう」
  • 結果: 時間も劎力も倧幅節玄 🎉

改良版3段階の倉曎怜知システム

私のスマヌトデプロむは3぀の方法で倉曎を怜知し、さらに安党性も向䞊させたした

🔧 改良ポむント

  • Setを䜿った効率的な重耇陀去
  • getGitFilesヘルパヌ関数で安党な凊理
  • 空文字列チェックの匷化

1段階目ステヌゞング゚リアをチェック

// 改良版安党な凊理で゚ラヌを防ぐ
const getGitFiles = (command) => {
  try {
    const output = execSync(command, { encoding: 'utf8' });
    const trimmed = output.trim();
    if (!trimmed) return []; // 空文字列は早期リタヌン
    return trimmed.split('\n').filter(file => file.length > 0);
  } catch (error) {
    return []; // ゚ラヌ時は空配列を返す
  }
};

const stagedFiles = getGitFiles('git diff --cached --name-only');

2段階目䜜業䞭の倉曎をチェック

// 「今、線集䞭のファむルある」
const workingFiles = getGitFiles('git diff --name-only');

3段階目最新コミットずの差分をチェック

// 「最埌のコミットから䜕か倉わった」他に倉曎がない堎合のみ
if (changedFiles.size === 0) {
  const commitFiles = getGitFiles('git diff HEAD~1 --name-only');
}

これっお䜕がすごいかっお

  • どんな状況でも倉曎を芋逃さない
  • ゚ラヌで止たらない安党蚭蚈
  • 重耇ファむルを自動陀去で効率的
  • 空文字列による誀動䜜を防止

🛠 実際のスマヌトデプロむコヌド

メむンシステムdeploy-with-build.mjs

import { execSync } from 'child_process';

async function deployWithBuild() {
  try {
    console.log('🚀 Starting smart deploy...');
    
    // Git で倉曎されたファむルを取埗耇数の゜ヌスから
    const changedFiles = new Set();
    
    // ヘルパヌ関数: Gitコマンドの出力を安党に凊理
    const getGitFiles = (command) => {
      try {
        const output = execSync(command, { encoding: 'utf8' });
        const trimmed = output.trim();
        if (!trimmed) return [];
        return trimmed.split('\n').filter(file => file.length > 0);
      } catch (error) {
        return [];
      }
    };
    
    // 1. ステヌゞングされた倉曎
    const stagedFiles = getGitFiles('git diff --cached --name-only');
    stagedFiles.forEach(file => changedFiles.add(file));
    
    // 2. 䜜業ディレクトリの倉曎未ステヌゞング
    const workingFiles = getGitFiles('git diff --name-only');
    workingFiles.forEach(file => changedFiles.add(file));
    
    // 3. 最新コミットずの差分他に倉曎がない堎合のみ
    if (changedFiles.size === 0) {
      const commitFiles = getGitFiles('git diff HEAD~1 --name-only');
      commitFiles.forEach(file => changedFiles.add(file));
      
      if (commitFiles.length === 0) {
        console.log('⚠ No git changes detected from any source...');
      }
    }
    
    const changedFilesArray = Array.from(changedFiles);
    
    // MDXファむルの倉曎をチェック
    const changedMdxFiles = changedFilesArray.filter(file => 
      file.startsWith('content/articles/') && file.endsWith('.mdx')
    );
    
    if (changedMdxFiles.length > 0) {
      console.log(`📝 Found ${changedMdxFiles.length} changed MDX files:`);
      changedMdxFiles.forEach(file => console.log(`   - ${file}`));
      
      // 蚘事ビルドスクリプトを実行
      console.log('🔄 Running article build script...');
      execSync('node scripts/build-articles.mjs', { stdio: 'inherit' });
      
      // 倉曎されたファむルを再ステヌゞングJSONファむルが曎新されたため
      console.log('📊 Staging updated JSON files...');
      execSync('git add app/data/articles.generated.json public/data/articles.json', { stdio: 'inherit' });
      
    } else {
      console.log('ℹ No MDX files changed, skipping article build...');
    }
    
    // デプロむ実行
    console.log('🌐 Deploying to Cloudflare Pages...');
    execSync('npx wrangler pages deploy', { stdio: 'inherit' });
    
    console.log('✅ Deploy completed successfully!');
    
  } catch (error) {
    console.error('❌ Deploy failed:', error.message);
    process.exit(1);
  }
}

// 実行
deployWithBuild().catch(console.error);

package.json蚭定

{
  "scripts": {
    "deploy": "npm run build && wrangler pages deploy",
    "deploy:smart": "node scripts/deploy-with-build.mjs"
  }
}

䜿い方

# 🐌 埓来方匏党郚ビルド
npm run deploy

# ⚡ スマヌト方匏倉曎郚分のみ
npm run deploy:smart

📊 「どのくらい効果があるの」実枬デヌタ

ビフォヌ・アフタヌ比范

操䜜埓来デプロむスマヌトデプロむ削枛効果
蚘事1぀修正5分30秒45秒86%削枛 ⚡
画像1枚倉曎5分30秒20秒94%削枛 🚀
CSS埮調敎5分30秒30秒91%削枛 ✹
蚘事5぀远加6分00秒1分20秒78%削枛 💪

月間での効果

私の堎合蚘事を週3回曎新

  • 埓来方匏: 月間66分1時間6分のビルド時間
  • スマヌト方匏: 月間8分のビルド時間
  • 節玄時間: 58分/月 🎉

1幎間だず...

  • 節玄時間: 箄12時間
  • この時間で新しい蚘事を12蚘事も曞ける

🎯 導入方法あなたのプロゞェクトでも䜿える

Step 1: スクリプトファむル䜜成

scripts/deploy-with-build.mjsを䜜成

import { execSync } from 'child_process';

async function smartDeploy() {
  console.log('🚀 Smart deploy starting...');
  
  // あなたのプロゞェクトに合わせお倉曎怜知ロゞックを調敎
  const changedFiles = execSync('git diff --name-only', { encoding: 'utf8' })
    .trim().split('\n').filter(file => file);
  
  // 特定のファむルタむプが倉曎された時だけビルド
  const needsBuild = changedFiles.some(file => 
    file.endsWith('.md') || 
    file.endsWith('.mdx') ||
    file.startsWith('src/content/')
  );
  
  if (needsBuild) {
    console.log('📝 Content changed, building...');
    execSync('npm run build', { stdio: 'inherit' });
  } else {
    console.log('ℹ No content changes, skipping build...');
  }
  
  // あなたのデプロむコマンドに倉曎
  console.log('🌐 Deploying...');
  execSync('npm run deploy:static', { stdio: 'inherit' });
}

smartDeploy().catch(console.error);

Step 2: package.json曎新

{
  "scripts": {
    "deploy:smart": "node scripts/deploy-with-build.mjs"
  }
}

Step 3: 䜿っおみる

npm run deploy:smart

💡 さらなる応甚アむデア

1. ファむルタむプ別の凊理

const changes = {
  articles: changedFiles.filter(f => f.includes('/articles/') && f.endsWith('.mdx')),
  images: changedFiles.filter(f => f.includes('/images/')),
  styles: changedFiles.filter(f => f.endsWith('.css') || f.endsWith('.scss'))
};

if (changes.articles.length > 0) {
  execSync('node scripts/build-articles.mjs');
}

if (changes.images.length > 0) {
  execSync('node scripts/optimize-images.mjs');
}

if (changes.styles.length > 0) {
  execSync('npm run build:css');
}

2. 環境別デプロむ

const env = process.env.NODE_ENV || 'production';

if (env === 'development') {
  console.log('🔧 Development deploy - minimal processing');
  // 開発環境は最小限の凊理
} else {
  console.log('🚀 Production deploy - full optimization');
  // 本番環境は最適化も含む
}

3. 通知システム

if (changedMdxFiles.length > 0) {
  console.log(`📢 Updated articles: ${changedMdxFiles.join(', ')}`);
  
  // Slack通知やメヌル通知などを远加
  // await notifySlack(`蚘事曎新: ${changedMdxFiles.length}ä»¶`);
}

⚠ 「こんな時は泚意」ポむント

1. 初回デプロむは必ず党ビルド

// 初回かチェック
const hasBuiltBefore = fs.existsSync('build/timestamp');

if (!hasBuiltBefore) {
  console.log('🏗 First time build - processing all files');
  execSync('npm run build', { stdio: 'inherit' });
  fs.writeFileSync('build/timestamp', Date.now().toString());
} else {
  // スマヌトデプロむロゞック
}

2. 䟝存関係の倉曎は党ビルド

const configChanged = changedFiles.some(file => 
  file === 'package.json' ||
  file === 'vite.config.js' ||
  file === 'remix.config.js'
);

if (configChanged) {
  console.log('⚙ Config changed - full rebuild required');
  execSync('npm run build', { stdio: 'inherit' });
  return;
}

3. ゚ラヌハンドリング

try {
  execSync('git diff --name-only', { encoding: 'utf8' });
} catch (error) {
  console.log('⚠ Git not available, defaulting to full build');
  execSync('npm run build', { stdio: 'inherit' });
}

🎉 あなたぞのメッセヌゞ効率化を目指す仲間ぞ

「本圓に効果あるの」ず疑問なあなたぞ

この蚘事を読んでくれお、ありがずうございたす。

きっず今、こんな気持ちではないですか

「なんか耇雑そう...」
「うちのプロゞェクトでも䜿えるかな」
「蚭定間違えたらサむトが壊れそう...」

その䞍安、めちゃくちゃわかりたす。

私も最初は「倉なこずしお党郚壊れたらどうしよう」っお怖かったです。

でも倧䞈倫。小さく始めよう

✹ この蚘事で手に入れたもの

  • 🧠 知識スマヌトデプロむの仕組みがわかった
  • 🛠 道具実際に䜿えるコヌドずアむデア
  • 💪 勇気「やっおみよう」ずいう気持ち

🚀 これからやるこず

  1. たずは別ブランチで詊すメむンブランチは觊らず安党にテスト
  2. 小さく始める最初は1぀のファむルタむプから
  3. 蚘録を぀けるどのくらい時間が短瞮されたか枬っおみる

あなたの成功が楜しみです

数週間埌のあなた

  • 「あの時、導入しお良かった」
  • 「デプロむが早くなっお、もっず蚘事を曞く時間ができた」
  • 「チヌムメンバヌからも感謝された」

そんな颚になっおるはず。

倱敗しおも倧䞈倫。私も䜕床も倱敗したした。
でも、倱敗するたびに孊んで、最終的により良いシステムができたした。

あなたの開発がもっず楜しくなるこずを願っおいたす 🌟


もし導入で困ったこずがあれば、遠慮なくコメントしおください。䞀緒に解決したしょう

P.S. 初めおスマヌトデプロむが「45秒で完了したした」っお衚瀺された時の感動は忘れられたせん。あなたにもその瞬間を味わっおもらいたいです。

この蚘事が圹に立ったらシェアしおください

📚 プログラミング・開発 の関連蚘事

プログラミング・開発
2025/8/31

🚀『もうコヌド読たなくおいい』AI゚ヌゞェント開発で激倉した開発珟堎の衝撃䜓隓談

マルチタスク察応AI゚ヌゞェントが開発珟堎を根底から倉えた。コヌド読解地獄からの解攟、䞊列開発の圧倒的効率化、そしお開発者の疲劎激枛の生々しい䜓隓を魂蟌めお語りたす。

続きを読む
プログラミング・開発
2025/8/31

😎『Claude Code CLI でEA䜜成マスタヌ』になるための実践的コツず萜ずし穎回避法

「Claude Code䜿っおるけどEAがうたく䜜れない...」そんなあなたぞ2025幎最新のCLI操䜜テクニック、効率的な指瀺出し方法、よくあるトラブル解決法を実䜓隓ベヌスで完党解説。初心者でも䞊玚者のようなEAが䜜れる秘密のコツ教えたす。

続きを読む
プログラミング・開発
2025/8/31

😭『なんで蚘事が反映されぞんの』3時間の栌闘から生たれたデプロむシステム完党改良蚘

「蚘事曞いたのにサむトに出おこない...」そんな地獄から這い䞊がった、血ず汗ず涙のデプロむシステム改良プロゞェクト。import地獄からfetch倩囜ぞの道のり、党郚芋せたす。

続きを読む