はじめに
「サーバーを経由せずに、ブラウザの中だけで生成したデータをファイルとしてダウンロードさせたい」——JSONのエクスポート、Canvasで描いた画像の保存、CSVレポートの出力など、こうした要望は意外とよくあります。しかし <a download> タグは文字列の内容が長くなると扱いづらく、Blobから生成したURLの後始末も自分で書く必要があり、地味に面倒です。
FileSaver.jsは、この「クライアント側だけでファイルを保存する」という処理を saveAs() という1つの関数に集約してくれるライブラリです。HTML5の saveAs() インターフェースを、対応していないブラウザでも動くようにポリフィルした実装で、Blobを渡すだけでOSの保存ダイアログを呼び出せます。
とはいえ、読むより触った方が早いと思います。実際にボタン1つでテキストファイルがダウンロードされる様子を、先に見てみましょう。
FileSaver.jsとは
FileSaver.jsは、Eli Greyによって開発されたJavaScriptライブラリで、ブラウザ上で生成したBlobやFileオブジェクトを、サーバーを介さずにローカルファイルとして保存するための saveAs(blob, filename) というAPIを提供します。2011年から続く古参のライブラリですが、今もGitHubで2万スター超を集める定番として使われ続けています。
主な特徴
- APIがシンプル -
saveAs(blob, filename)の1行で、Blob・File・URL文字列をダウンロードファイルとして保存できる - 依存関係なし - フレームワークに依存せず、素のJavaScriptだけで動く
- 主要ブラウザに幅広く対応 - Chrome、Firefox、Safari、Edgeなど、モダンブラウザで一貫した挙動を得られる
- バイナリ・テキストの両方を扱える -
Blobを作れるものなら画像・PDF・ZIP・CSVなど何でも保存対象にできる - TypeScript向けの型定義が公式に提供されている -
@types/file-saverを入れれば型安全に使える
インストール
npmからインストールする場合は以下のコマンドを実行します。
npm install file-saver
TypeScriptで使う場合は、型定義もあわせてインストールしておくと安心です。
npm install --save-dev @types/file-saver
ES modules環境であれば、以下のようにimportして使い始められます。
import { saveAs } from 'file-saver'
FileSaver.jsのサンプルを動かす
FileSaver.jsの中心的な使い方は、保存したい内容を Blob に変換し、それを saveAs(blob, filename) に渡すことです。以下のサンプルでは、入力欄に書いたテキストを .txt ファイルとしてダウンロードします。要点をまとめると次のようになります。
import { saveAs } from 'file-saver'
// テキストからBlobを作り、ファイル名を指定して保存する
const text = 'Hello, FileSaver.js!'
const blob = new Blob([text], { type: 'text/plain;charset=utf-8' })
saveAs(blob, 'greeting.txt')
実際に動かせるものが下です。入力欄の内容を書き換えてからボタンを押すと、その内容のテキストファイルがダウンロードされます。
テキストエリアの内容を書き換えてから「テキストファイルを保存」を押すと、その時点の文字数に応じて blob.size が変わることが確認できます。saveAs() の第2引数を memo.txt から report.csv のような別の拡張子に変えれば、そのままファイル種別を切り替えて保存できます。
基本的な使い方
最もシンプルな使い方は、文字列から Blob を作って saveAs() に渡すだけです。MIMEタイプを正しく指定しておくと、OSがファイル種別を認識しやすくなります。
import { saveAs } from 'file-saver'
const jsonData = JSON.stringify({ name: 'FileSaver.js', version: '2.0.5' }, null, 2)
const blob = new Blob([jsonData], { type: 'application/json;charset=utf-8' })
saveAs(blob, 'data.json')
saveAs() は第1引数にBlobだけでなく、既存の File オブジェクトやURL文字列も受け取れます。サーバーから取得済みの画像URLをそのまま保存したい場合などに使えます。
import { saveAs } from 'file-saver'
saveAs('https://example.com/image.png', 'downloaded-image.png')
実践的なユースケース
Canvasで描いた画像を保存する
<canvas> に描画した内容を画像ファイルとして保存したい場面は多くあります。canvas.toBlob() でCanvasの内容をBlob化し、それをそのまま saveAs() に渡せば、PNGとしてダウンロードできます。
「ランダムな図形を描く」で表示を変えてから「PNGとして保存」を押すと、その時点のCanvasの見た目そのままの画像がダウンロードされます。canvas.toBlob() の第2引数を 'image/jpeg' に変えれば、JPEG形式での保存にも切り替えられます。
JSZipと組み合わせて複数ファイルをまとめて保存する
FileSaver.jsは単体のファイルしか保存できませんが、JSZipと組み合わせることで、複数のファイルを1つのZIPにまとめてダウンロードさせることができます。JSZipでZIPデータのBlobを作り、それを saveAs() に渡すだけです。
ボタンを押すと、readme.txt ・data.json ・サブフォルダ内の note.txt の3ファイルが1つの archive.zip にまとまってダウンロードされます。zip.file() の呼び出しを増やせば、その分だけファイルを追加できます。CSVレポートと画像をまとめてエクスポートするような場面でも、この組み合わせが役立ちます。
まとめ
FileSaver.jsは、saveAs(blob, filename) というシンプルなAPIひとつで、ブラウザ上のデータをサーバーを介さずにローカル保存できるライブラリです。テキストやJSONのエクスポートはもちろん、canvas.toBlob() と組み合わせれば画像の保存に、JSZipと組み合わせれば複数ファイルのZIP保存にも対応できます。
「クライアント側で生成したデータをダウンロードさせたい」という場面に出会ったら、まずは Blob を作って saveAs() に渡すところから試してみてはいかがでしょうか。
