ウェチャットミニプログラム大規模運用のための自動化パイプライン構築

背景と課題 特定のミニプログラムで一定数の日次アクティブユーザー(DAU)を獲得した後、収益拡大のために類似コンテンツを持つ複数のアプリケーションを並行して展開する「アプリマトリクス」戦略を検討することがあります。単一プロジェクトでは日活が数千規模に達する場合でも、これを数十あるいは百単位にスケールさせると考えると、広告収入の見込みは大幅に増加します。 しかし、この戦略を実現する上での最大のボトルネックは、リリースプロセスの人的コストです。通常、各アプリに対して以下の手順を手動で反復する必要があります。

新規アプリの登録と認証情報設定 コードビルドおよびアップロード 審査申請と公開操作 バグ修正時のパッチ配信

特に10以上のプロジェクトを同時に保守・更新する際には、微信管理后台へのログイン回数が増大し、設定ミスや作業効率の低下を招くリスクが高まります。

ステップ1:ローカルビルドツールの導入 まず、手動作業を減らすために、CLIベースのビルド&デプロイスクリプトを導入しました。ここでは Node.js の miniprogram-ci ライブラリを活用し、Git リポジトリからの自動チェックアウト、ビルド、そしてアップロードまでを一貫したフローで実行できるように設計しています。 従来のタスクランナー構成を簡略化し、環境変数に応じて動的に処理を分岐させるようにリファクタリングしました。

// deploy-toolkit.js
const fs = require('fs').promises;
const ci = require('miniprogram-ci');
const path = require('path');
const { execSync } = require('child_process');

// 環境設定オブジェクト
const PROJECT_CONFIG = {
  distDir: './dist',
  srcDir: './src',
  privateKeyDir: './certificates'
};

class MiniProgramDeployer {
  constructor(appId, env = 'dev') {
    this.appId = appId;
    this.env = env;
    this.projectPath = path.resolve(PROJECT_CONFIG.distDir);
    this.keyPath = path.join(PROJECT_CONFIG.privateKeyDir, `private.${appId}.key`);
  }

  // ビルド前のクリーン処理
  async cleanBuild() {
    await fs.rm(this.projectPath, { recursive: true, force: true });
    console.log(`[Clean] ${this.projectPath} removed.`);
  }

  // アップロード処理のエントリーポイント
  async uploadVersion(versionInfo, desc) {
    const privateKey = await fs.readFile(this.keyPath);
    const projectCtx = new ci.Project({
      appid: this.appId,
      type: 'miniProgram',
      projectPath: this.projectPath,
      privateKeyPath: this.keyPath
    });

    try {
      const setting = {
        es6: true,
        es7: true,
        minifyJS: true,
        minifyWXML: true,
        minifyWXSS: true,
        autoPrefixWXSS: true
      };

      // ロボット番号:環境別に割り当て
      const robotId = this.env === 'production' ? 2 : 1;

      const result = await ci.upload({
        project: projectCtx,
        version: versionInfo || '1.0.0',
        desc: desc,
        setting: setting,
        robot: robotId,
        onProgressUpdate: (progress) => {
          process.stdout.write(`\rUpload progress: ${progress}%`);
        }
      });

      console.log('\n[Success] Upload completed:', result.uuid);
      return result;
    } catch (error) {
      console.error('[Error] Upload failed:', error.message);
      throw error;
    }
  }
  
  // npm パッケージのセットアップ
  async installDependencies() {
    console.log('[NPM] Running npm install in project directory...');
    execSync('npm run build:npm', { cwd: this.projectPath, stdio: 'inherit' });
  }
}

module.exports = MiniProgramDeployer;

ステップ2:複数アプリへのバッチ処理 単一アプリのデプロイが可能になれば、今度は対象となる AppID のリストに対してバッチ処理を行う必要があります。当初は外部スクリプト(Python など)を使用してコマンドを実行していましたが、統一的な管理ツールとして同じ言語スタック内で処理できるよう改修しました。これにより、依存関係の維持コストを削減できます。

// batch-runner.js
const Deployer = require('./deploy-toolkit');
const dotenv = require('dotenv');
const { promisify } = require('util');

dotenv.config();

// 処理対象のアプリリスト(実際の運用では DB や CSV から読み込む想定)
const APP_TARGETS = [
  { id: 'wx123456789abcde', name: 'Product A' },
  { id: 'wx987654321edcba', name: 'Product B' },
  { id: 'wx555555555aaaaa', name: 'Product C' }
];

const delay = ms => new Promise(res => setTimeout(res, ms));

async function batchDeploy(targetList) {
  const results = [];
  
  for (const target of targetList) {
    console.log(`\n>>> Processing: ${target.name} (${target.id})`);
    const deployer = new Deployer(target.id, 'development');
    
    try {
      // 必要に応じて前処理
      await deployer.cleanBuild();
      
      // デプロイ実行
      const res = await deployer.uploadVersion(
        '1.2.3', 
        `Batch Auto Release - ${new Date().toISOString()}`
      );
      results.push({ appId: target.id, status: 'OK', detail: res });
    } catch (err) {
      results.push({ appId: target.id, status: 'FAILED', error: err.message });
    }

    // 制限回避のため少し待機(API レート制限等への配慮)
    await delay(2000);
  }

  console.table(results);
}

// 実行エントリ
batchDeploy(APP_TARGETS).catch(console.error);

ステップ3:オープンプラットフォームによる完全自動化 上記のローカル自動化のみでは、「テンプレート重複による審査拒否リスク」や「管理コンソールへのログイン頻度」という根本的な課題が残りました。ここに至り、微信公式が提供する「サードパーティプラットフォーム(サービス提供者)」モードの採用が決定的となりました。 この方式を利用することで、個々のミニプログラムアカウントにログインすることなく、以下の操作を API 経由で一元制御可能です。

ドメイン設定(ホワイトリスト登録) プライバシーポリシー設定 審査依頼の送信 全プロジェクトの一括公開

APIFox などの API 管理ツールを用いてワークフローを定義し、Webhook または CI/CD ジョブからトリガーすることで、開発者側の介入を最小限に抑えることが可能になります。具体的な設定には約半日程度かかりましたが、その後の運用負荷は約 9 割削減されました。

まとめ 小規模なアプリ運用では手動で十分ですが、規模が数百単位に拡大する場合は、インフラレベルでの自動化と公式インターフェースの有効利用が不可欠となります。 最初は複雑に見えるサードパーティ連携手順も、一度基盤を整えてしまえば、100 個のプロジェクトであっても 1 個と同じ感覚で管理が可能です。結果として、エンジニアは機能開発や品質向上に注力できる時間が大幅に確保され、ビジネス目標との整合性を取りやすくなります。

タグ: wechat-mini-program miniprogram-ci nodejs api-automation third-party-platform

6月30日 20:14 投稿