mcpField
I
integrate-uppy-transloadit-s3-uploading-to-nextjs

integrate-uppy-transloadit-s3-uploading-to-nextjs

github.com/transloadit開発590 回インストール4 日前に更新
リポジトリ

integrate-uppy-transloadit-s3-uploading-to-nextjs について

Next.js アプリに Uppy と Transloadit のアップロード機能を追加するスキルです。サーバー側の署名とブラウザーのアップロード画面を扱い、画像のリサイズと S3 への保存も任意で設定できます。

主な機能

  1. 01サーバー側での Assembly オプション署名
  2. 02Uppy Dashboard のアップロード画面
  3. 03Transloadit プラグインの連携
  4. 04任意の画像リサイズと S3 エクスポート
  5. 05Transloadit のシークレットをサーバー側に保持

活用シーン

  1. 01Next.js アプリへのファイルアップロード追加
  2. 02シークレットを公開せずにアップロード設定を署名
  3. 03アップロード画像をリサイズして S3 に保存

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/transloadit/skills --skill integrate-uppy-transloadit-s3-uploading-to-nextjs

インストール後、Claude Code で/integrate-uppy-transloadit-s3-uploading-to-nextjsを入力して読み込まれたか確認します。

詳細

入力

  • 必須の環境変数(サーバー専用):TRANSLOADIT_KEY、TRANSLOADIT_SECRET
  • 任意の環境変数:TRANSLOADIT_TEMPLATE_ID(テンプレート作成後に設定することを推奨)

ローカル開発では、これらを .env.local に設定します。TRANSLOADIT_SECRET をブラウザーに公開しないでください。

インストール

npm i @transloadit/utils @uppy/core @uppy/dashboard @uppy/transloadit

実装(推奨手順)

ルートを選択します。

  • プロジェクトに src/app がある場合は、src/app/... を使用します。
  • それ以外の場合は、app/... を使用します。

1) サーバー:署名済みの Assembly オプションをブラウザーに返す

app/api/transloadit/assembly-options/route.ts(または src/ を使用している場合は src/app/api/transloadit/assembly-options/route.ts)を作成します。

import { NextResponse } from 'next/server'
import { signParamsSync } from '@transloadit/utils/node'

export const runtime = 'nodejs'

function reqEnv(name: string): string {
  const v = process.env[name]
  if (!v) throw new Error(`Missing required env var: ${name}`)
  return v
}

function formatExpiresUtc(minutesFromNow: number): string {
  const ms = Date.now() + minutesFromNow * 60_000
  return new Date(ms).toISOString().replace(/\.\d{3}Z$/, 'Z')
}

export async function POST() {
  try {
    const authKey = reqEnv('TRANSLOADIT_KEY')
    const authSecret = reqEnv('TRANSLOADIT_SECRET')
    const templateId = process.env.TRANSLOADIT_TEMPLATE_ID

    const params: Record<string, unknown> = {
      auth: { key: authKey, expires: formatExpiresUtc(30) },
    }

    if (templateId) {
      params.template_id = templateId
    } else {
      // Minimal "known good" steps (works without pre-creating a template).
      params.steps = {
        resized: {
          robot: '/image/resize',
          use: ':original',
          width: 320,
        },
      }
    }

    const paramsString = JSON.stringify(params)
    const signature = signParamsSync(paramsString, authSecret)

    // Uppy expects `{ params: <string|object>, signature: <string> }`.
    return NextResponse.json({ params: paramsString, signature })
  } catch (err) {
    const message = err instanceof Error ? err.message : 'Unknown error'
    return NextResponse.json({ error: message }, { status: 500 })
  }
}

2) クライアント:Uppy Dashboard と Transloadit プラグインをマウントする

CSS を追加します(App Router の場合は、ルートレイアウトに追加します)。

import '@uppy/core/css/style.min.css'
import '@uppy/dashboard/css/style.min.css'

app/upload-demo.tsx のようなクライアントコンポーネントを作成します。

'use client'

import { useEffect, useMemo, useRef, useState } from 'react'
import Uppy from '@uppy/core'
import Dashboard from '@uppy/dashboard'
import Transloadit, { type AssemblyOptions } from '@uppy/transloadit'

export default function UploadDemo() {
  const dashboardEl = useRef<HTMLDivElement | null>(null)
  const [results, setResults] = useState<unknown>(null)
  const [uploadPct, setUploadPct] = useState<number>(0)

  const uppy = useMemo(() => {
    const instance = new Uppy({
      autoProceed: true,
      restrictions: { maxNumberOfFiles: 1 },
    })

    instance.use(Transloadit, {
      waitForEncoding: true,
      alwaysRunAssembly: true,
      assemblyOptions: async (): Promise<AssemblyOptions> => {
        const res = await fetch('/api/transloadit/assembly-options', { method: 'POST' })
        if (!res.ok) throw new Error(`Failed to get assembly options: ${res.status}`)
        return (await res.json()) as AssemblyOptions
      },
    })

    return instance
  }, [])

  useEffect(() => {
    if (!dashboardEl.current) return

    uppy.use(Dashboard, {
      target: dashboardEl.current,
      inline: true,
      proudlyDisplayPoweredByUppy: false,
      hideUploadButton: true,
      hideProgressDetails: false,
      height: 350,
    })

    const onResult = (stepName: string, result: unknown) =>
      setResults((prev: unknown) => {
        const base: Record<string, unknown> =
          typeof prev === 'object' && prev !== null ? { ...(prev as Record<string, unknown>) } : {}
        const existing = base[stepName]
        base[stepName] = Array.isArray(existing) ? existing.concat([result]) : [result]
        return base
      })

    const onUploadProgress = (_file: unknown, progress: { bytesUploaded: number; bytesTotal: number | null }) => {
      if (!progress?.bytesTotal) return
      setUploadPct(Math.round((progress.bytesUploaded / progress.bytesTotal) * 100))
    }

    uppy.on('transloadit:result', onResult)
    uppy.on('upload-progress', onUploadProgress)

    return () => {
      uppy.off('transloadit:result', onResult)
      uppy.off('upload-progress', onUploadProgress)
      uppy.getPlugin('Dashboard')?.uninstall()
      uppy.destroy()
    }
  }, [uppy])

  return (
    <section>
      <div ref={dashboardEl} />
      <div style={{ marginTop: 12 }}>{uploadPct}%</div>
      <pre style={{ marginTop: 12 }}>{results ? JSON.stringify(results, null, 2) : '(no results yet)'}</pre>
    </section>
  )
}

任意:/s3/store へのエクスポート

推奨される方法は、Transloadit でテンプレート認証情報を作成し(AWS キーをどこにも含めずに済みます)、/s3/store で参照することです。

手順の例:

{
  "resized": { "robot": "/image/resize", "use": ":original", "width": 320 },
  "exported": {
    "robot": "/s3/store",
    "use": "resized",
    "credentials": "YOUR_TRANSLOADIT_TEMPLATE_CREDENTIALS_NAME",
    "path": "uppy-nextjs/${unique_prefix}/${file.url_name}",
    "acl": "private"
  }
}

意図的にオブジェクトを公開する場合は、"acl" を "public-read" に変更します(バケットポリシー、アクセスログ、データ保持についても検討してください)。

次に、テンプレートを作成し、TRANSLOADIT_TEMPLATE_ID を設定します。

npx -y @transloadit/node templates create uppy-nextjs-resize-to-s3 ./steps.json -j

参考資料(内部)

  • 動作するリファレンス実装:https://github.com/transloadit/skills/tree/main/scenarios/integrate-uppy-transloadit-s3-uploading-to-nextjs
  • 実績のある steps JSON:https://github.com/transloadit/skills/blob/main/scenarios/integrate-uppy-transloadit-s3-uploading-to-nextjs/transloadit/steps/resize-only.json、https://github.com/transloadit/skills/blob/main/scenarios/integrate-uppy-transloadit-s3-uploading-to-nextjs/transloadit/steps/resize-to-s3.json

以下の環境でテスト済みです(正確なバージョンについては、シナリオのロックファイルを参照してください)。

  • Next.js 16.1.6(App Router)
  • React 19.2.3
  • @transloadit/utils 4.3.0(Assembly の署名)
  • @uppy/core 5.2.0、@uppy/dashboard 5.1.1、@uppy/transloadit 5.5.0

コメント