先日こんな記事やこんな記事を投稿したので、今度はファイルのアップロード先もsupabaseにお任せしてしまおうかと思います。
Supabaseにバケットを作成する
strapi
という名前のバケットを作成し、Publicにしておきます。
作成後、Policyで画像拡張子のファイルがアップロードできるように設定をします。
わたしの環境では、SELECT, INSERT, DELETEができる権限を設定しておきました。SELECTなしでも行けるんじゃないかと思いましたが、removeの実行はDELETEだけでは権限不足なようです。
Providerのインストール
StrapiとSupabaseのバケットをつなぐproviderをインストールします。
ただ、それっぽいパッケージはあったのですがissueにstrapi v4に対応してないみたいなことが書いてあったのと、もう一つのv4に対応してそうなパッケージの方は存在自体が怪しすぎたので自作しました。
……記事書いてる途中に気が付いたんですが、パッケージ名がtypoしてますね。strageでなくてstorageです。strapiってずっと書いてたからかもしれません。
まあtypoはともかく、以下のコマンドでパッケージを取って来ます。
npm i strapi-provider-upload-supabase-strage
その後、プラグインファイルを追加してreadmeの内容をコピペ、環境変数に必要事項を追加します。
module.exports = ({ env }) => ({
upload: {
config: {
provider: 'strapi-provider-upload-supabase-strage', // For community providers pass the full package name (e.g. provider: 'strapi-provider-upload-google-cloud-storage')
providerOptions: {
url: env("SUPABASE_URL"),
apiKey: env("SUPABASE_KEY"),
bucket: env("SUPABASE_BUCKET"),
bucketPrefix: env("SUPABASE_BUCKET_PREFIX")
},
},
},
});
SUPABASE_URL=<supabase API URL>
SUPABASE_KEY=<supabase API Key>
SUPABASE_BUCKET_PREFIX=hoge
SUPABASE_BUCKET_PREFIXはなくても良いですが、 SUPABASE_BUCKET_PREFIX == バケット内のディレクトリなので、ここを設定しておくといざという時にディレクトリごとファイルを一気に消し飛ばせるため楽です。
ひとまずこれでアップロードは可能になりました。
ただ、これだと上げた画像をstrapi上から閲覧できないので設定を修正する必要があります。
config/middlewares.ts
を以下の内容に書き換えます。
export default [
"strapi::errors",
{
name: "strapi::security",
config: {
contentSecurityPolicy: {
useDefaults: true,
directives: {
"connect-src": ["'self'", "https:"],
"img-src": ["'self'", "data:", "blob:", process.env.SUPABASE_URL],
"media-src": ["'self'", "data:", "blob:", process.env.SUPABASE_URL],
upgradeInsecureRequests: null,
},
},
},
},
"strapi::poweredBy",
{
name: "strapi::cors",
config: {
enabled: true,
headers: "*",
origin: [
`http://localhost:${process.env.PORT}`,
process.env.SUPABASE_URL,
],
},
},
"strapi::logger",
"strapi::query",
"strapi::body",
"strapi::session",
"strapi::favicon",
"strapi::public",
];
これで、<img src="https://...supabase.io/hogehoge.png" />
みたいな要素で画像を閲覧できるようになります。
おまけ: strapiのuppload-providerのつくりかた
もしこちらの内容が古かった場合は、こちらのstrapi公式ドキュメントを参考にしてください。
https://docs.strapi.io/developer-docs/latest/development/providers.html
というか古くなくても一読しておくとよいです。
置き場を作る
provider/strapi-provider-<plugin>-<provider>
ディレクトリを作成します。
例えばsupabaseのファイルアップロードプラグインの場合は、strapi-provider-upload-supabase
です。
その中でnpm init
したのち、main
に指定したファイルに書き込んでいきます。
処理を記載する
strapiの公式に土台となるテンプレートがあるのでこちらをmain
で指定したファイルに転記して使用します。
module.exports = {
init(providerOptions) {
// init your provider if necessary
return {
upload(file) {
// upload the file in the provider
// file content is accessible by `file.buffer`
},
uploadStream(file) {
// upload the file in the provider
// file content is accessible by `file.stream`
},
delete(file) {
// delete the file in the provider
},
};
},
};
providerOptionsは、config/plugins.ts
のproviderOptionsで指定した値です。
記載する内容は基本的に少なく、中の処理では該当のStorageにファイルを投げる処理と、Strapiのユーザー側から閲覧できる画像のURLをfile.urlに渡してあげるだけです。
イメージとしては以下のような感じですね。
module.exports = {
init(providerOptions) {
return {
upload(file) {
const { publickImageFileURL } = somethingStorage
.upload(
'bucketname',
new Blob([file.buffer], { type: file.mime })
);
file.url = publickImageFileURL;
},
uploadStream(file) {
const { publickImageFileURL } = somethingStorage
.upload(
'bucketname',
streamToBlob(file.stream)
);
file.url = publickImageFileURL; },
delete(file) {
somethingStorage.bucket("bucketname").remove(file.name)
},
};
},
};
こうして書き終わったら、strapi側にあるpackage.jsonに以下を追記します。
{
...
"dependencies": {
...
"strapi-provider-<plugin>-<provider>": "file:providers/strapi-provider-<plugin>-<provider>",
...
}
}
これにて追加完了です。npm i
しましょう。