最小Vercel Blob体験
とりあえず、npmが使える状態にする。
コンテナの中で作業するなら、イメージはnode:22
を使うのが良いだろう(VercelのNode.jsバージョンがデフォルトで22.xなので)。
ガワを作る
npm create vite@latest vercel-blob-demo -- --template react-ts
cd vercel-blob-demo
git init
git switch -c dev
git add .
git commit -m "Initial commit"
GitHubリポジトリをVercelと結びつける
GitHubリポジトリを適当に作る。
Vercelアカウントを作り、GitHubアカウントと関連付ける。
Settingsで、Vercelからリポジトリが見えるようにする。
Vercel側でインポートする。
viteを使うのでビルドコマンドと出力先ディレクトリを変更する。
Deployするとエラーになるが、インポートはできている。
手元のReactプロジェクトをpushする
手元の作業ディレクトリと結びつけ、とりあえずそのままpush。
git remote add origin https://github.com/js4000all/vercel-blob-demo.git
git fetch
git rebase -X theirs origin/main
git push --set-upstream origin dev
Vercel側でデプロイされる。
Vercel Blobストアを作る
当該プロジェクトのStorageから。hobbyプランだとアカウントあたり1個しか作れないので、作成済みのストアがあるならconnectする。
これで、Vercel Function内でVercel Blob SDKを使えば、Vercel Blobにアクセスできるようになった(アクセストークンは環境変数として設定されており、SDKが勝手に参照する)。
試してないが、Next.jsのAPI Routes内でSDKを使うことができるようだ。Vercel Functionもその類型。
Vercel Blob SDKをインストール
npm install @vercel/blob @vercel/node
Vercel Functionを実装
put関数で保存するAPI。
import { put } from '@vercel/blob';
import { VercelRequest, VercelResponse } from '@vercel/node';
export default async function handler(req: VercelRequest, res: VercelResponse) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
const { key, content } = req.body;
if (!key || !content) {
return res.status(400).json({ error: 'Key and value are required' });
}
const result = await put(key, content, {
access: "public",
addRandomSuffix: false,
cacheControlMaxAge: 0,
});
return res.status(200).json(result);
}
head関数でメタ情報を取得するAPI。
import { head } from '@vercel/blob';
import { VercelRequest, VercelResponse } from '@vercel/node';
export default async function handler(req: VercelRequest, res: VercelResponse) {
const { key } = req.query as { key: string };
if (!key) {
return res.status(400).json({ error: 'Key is required' });
}
const blob = await head(key);
return res.status(200).json(blob);
}
これらのAPIをVercel Functionのランタイムで動作させるには、ESMとしてコンパイルされないといけない。そのためのTypeScriptコンパイラへの指示を追加する。
"compilerOptions": {
"module": "ESNext"
}
アプリ本体を実装
Vercel Functionをfetchでコールすることでアップロードとダウンロードを行うUIを実装。
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
export default function App() {
const [key, setKey] = useState('');
const [content, setContent] = useState('');
const [fetched, setFetched] = useState('');
const [message, setMessage] = useState('');
const handleUpload = async () => {
setMessage('Uploading...');
try {
const res = await fetch('/api/save-blob', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key, content }),
});
const data = await res.json();
setMessage(`✅ Uploaded: ${data.url}`);
} catch (err) {
setMessage('❌ Upload failed');
}
};
const handleDownload = async () => {
setMessage('Downloading...');
try {
const res = await fetch(`/api/head-blob?key=${encodeURIComponent(key)}`);
const data = await res.json();
const fileRes = await fetch(data.url);
const text = await fileRes.text();
setFetched(text);
setMessage('✅ Download complete');
} catch (err) {
setMessage('❌ Download failed');
}
};
return (
<>
<div>
<a href="https://vite.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>🗂 Vercel Blob Demo</h1>
<div className="card">
<label>
ファイル名(key): <br />
<input
value={key}
onChange={(e) => setKey(e.target.value)}
placeholder="example.txt"
style={{ width: '100%', padding: 8 }}
/>
</label>
<br /><br />
<label>
ファイル内容(content): <br />
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
rows={5}
style={{ width: '100%', padding: 8 }}
/>
</label>
<br /><br />
<button onClick={handleUpload} style={{ marginRight: 10 }}>
⬆️ アップロード
</button>
<button onClick={handleDownload}>
⬇️ 読み取り
</button>
<p>{message}</p>
{fetched && (
<>
<h3>📄 読み取った内容:</h3>
<pre style={{ background: '#f4f4f4', padding: 10 }}>{fetched}</pre>
</>
)}
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
)
}
ビルドできればとりあえずOK。pushすると、vercelでビルド&デプロイされる。
yarn build
git push