はじめに
最近Next.jsのウェブアプリでファイルの投稿機能を追加するときはnext-s3-uploadを使っているのですが、ファイルストレージサービスを実環境のS3を使っていたので、ローカル用のS3環境を立ててみたいと思って色々と調べてやってみました。
MinIOを使う
MinIO
を使うことでS3互換性のあるサービスをDockerで構築することができます。
以下はdocker-compose.yml
の例です。
services:
minio:
image: quay.io/minio/minio:latest
container_name: s3-minio
environment:
MINIO_ROOT_USER: admin123
MINIO_ROOT_PASSWORD: admin123
command: server --console-address ":9090" /data
volumes:
- ./docker/minio/data:/data
ports:
- 9000:9000
- 9090:9090
ここではユーザー名とパスワードをadmin123で設定しています。まずは以下のコマンドでDockerを起動します。
docker compose up -d
次にhttp://localhost:9090
にアクセスをしてコンソール画面にアクセスして、先ほど設定したユーザー名とパスワードでログインします。
左メニューからBuckets
を選択してCreate Bucket
でストレージを新規作成します。
左メニューからAccess Keys
を選択してCreate Access Key
でアクセスキーを新規作成します。
これでローカルのS3の準備ができたので、作成した以下の情報を記録しておきます。
- バケット名
- アクセスキー
- シークレットキー
next-s3-uploadでMinIOと繋ぎこみ
前提としてNext.js
とnext-s3-upload
は既にインストールされているものとします。今回はNext.jsのpage router
で実装するとして、src/pages/s3-upload.ts
で以下を実装します。
import { APIRoute } from 'next-s3-upload'
export default APIRoute.configure({
accessKeyId: process.env.S3_UPLOAD_KEY,
secretAccessKey: process.env.S3_UPLOAD_SECRET,
bucket: process.env.S3_UPLOAD_BUCKET,
region: process.env.S3_UPLOAD_REGION,
endpoint: process.env.S3_UPLOAD_ENDPOINT,
forcePathStyle: true,
})
forcePathStyle: true
という設定は、AWS S3以外を用いる場合は重要になるので必ずtrueで設定しておきます。.env
は以下のように設定します。
S3_UPLOAD_KEY=アクセスキー
S3_UPLOAD_SECRET=シークレットキー
S3_UPLOAD_BUCKET=バケット名
S3_UPLOAD_REGION=ap-northeast-1
S3_UPLOAD_ENDPOINT=http://localhost:9000
S3_UPLOAD_REGION
とS3_UPLOAD_ENDPOINT
については内容そのままコピペで大丈夫です。AWS以外の環境で実装する場合の詳細は公式ドキュメントのOther providersの項でまとめてあります。
あとはファイル投稿画面を実装するだけですが、アップロード機能のhooksはusePresignedUpload
を使います。以下はコード例です。
import { FC, useState } from 'react';
import { usePresignedUpload } from 'next-s3-upload'
export const Component: FC = ({ contents, handleSave }) => {
const { uploadToS3, FileInput, openFileDialog } = usePresignedUpload()
const [imageUrl, setImageUrl] = useState<string>('')
const handleFileChange = async (file: File) => {
const { url } = await uploadToS3(file)
setImageUrl(url)
}
return (
<>
{imageUrl ? (
<img src={imageUrl} />
) : (
<div>サムネイルをアップロードしてください</div>
)}
<FileInput
type="file"
onChange={handleFileChange}
/>
<button type="button" onClick={openFileDialog}>
ファイル選択
</button>
</>
)
}
さいごに
MinIOとnext-s3-uploadの連携方法について、書いている記事が見つからなかったので今回はそれについてまとめてみました。最初の導入は若干面倒ではありますが、一度構築してしまえば料金の心配なしに開発ができるので、結構便利だと思います。