Strapiをcloud環境などに設置する場合、テキストや画像ファイルなどをその環境に置くことはないかと思います。
大体の場合、テキストはRDSやcloud SQLにsupabaseといった外部のデータベース、画像ファイルはs3やcloud storage, supabaseといった外部のストレージに吐き出すことになるのではないでしょうか。
そんな時、問題となってくるのがお値段です。
テキストは書けば書くほど、画像は置けば置くほどお金がかかります。
多くのクラウドサービスには無料枠がありますが、たいていの場合期限があったり上限が低かったりといったことが多いでしょう。
特に、DBはまあ仕方がないとしても、画像ファイルをどうにかして削減したいと考えるのは自然のことだと思います。
そんなわけで、これら節約術を考えていくというのが今回の記事となります。
なお、最終的な画像出力先、headlessCMSからブログなどの適当なアプリケーションに届けた段階で不都合はいろいろ何とかしてくれるだろという前提で話を進めるので、フロントエンド側で解決できそうなことはすべてフロントエンド側に丸投げする前提で話します。
そもそも現状はどうなのかを認識する
とりあえず初期設定でファイルをアップロードしてみましょう。
サンプルとして、私のある日の昼食の写真をStrapiにアップロードしてみます。
アップロードした画像をsupabase側から確認した結果がこちらです。
不思議なことに、一枚のアップロードで+4枚の画像が生成されています。
オリジナルの画像1枚で874.25KB、画像5枚合計のサイズは1138.12KB、オリジナルでない写真は名前からわかる通りリサイズしたものなのでシンプルに5枚分の負担がなされるというわけではないのですが、そうであっても無視できない負担です。
生成ファイルを可能な限り少なくする
というわけでまずファイルを減らします。
strapiでsettig
-> Media Library
と移動するとResponsive friendly upload
という項目を見つけることができます。
説明はこうです。
Enabling this option will generate multiple formats (small, medium and large) of the uploaded asset
はい消します。Boolean値でtrue/falseが指定できるのでfalseにしてしまいましょう。
ファイルを削除して、再度実行するとこうなります。
small, medium, largeの3枚が消えました。
現時点での合計が882.51KBなので、22%くらい削減できたことになります。
画像の形式を変える
ここからAVIFに変換することでさらに圧縮を図ります。
providerディレクトリを作成し、supabaseのuploadライブラリとして使用していたstrapi-provider-upload-supabase-strage
をgithubからクローンします。
その後、必要なライブラリを以下のコマンドで取得。ファイルを修正します。
npm i sharp
// ...
async uploadStream(file) {
// upload the file in the provider
// file content is accessible by `file.stream`
const blob = await fileStreamToBlob(file);
const blobArrayBuffer = await blob.arrayBuffer();
const data = await sharp(new Uint8Array(blobArrayBuffer))
.avif()
.toBuffer();
file.name = `${path.parse(file.name).name}.avif`;
let { error } = await supabaseClient.storage
.from(supabaseBucket)
.upload(`${supabaseBucketPrefix}${file.name}`, data, {
contentType: "image/avif",
});
if (error) throw error;
file.url = getFilePublicUrl(file);
// ...
以前はReadableStream -> Blobだったのを、ReadableStream -> Blob -> arrayBuffer -> Uint8Array -> buffer(avif)と延長しています。(もう少し短くできる気がする)
使用しているavifはロスレス変換をしていないので厳密には不可逆変換ですが、人間が気が付けるような差はないので写真ブログとかでない限りは気にしなくてよいです。
それでは結果をドン
合計519.84KB, 最初の約半分になりました。
変換に時間がかかることがネックですが、これでかなり延命ができるようになったのではないかと思います。