JavaScriptでCSVエクスポートを実装してみた。

# 前書き
CSVのエクスポートは、WEBアプリでは結構利用する機能だと思います。
できる限り、フロント側で完結したい内容ではありますので、JavaScriptで実装してみました。
# 実装
利用するのは以下二つのライブラリです。

```bash
# JsonをCSV文字列に変換してくれるライブラリ
$ npm install papaparse
$ yarn add papaparse

# 文字コード変換をしてくれるライブラリ
$ npm install encoding-japanese
$ yarn add encoding-japanese
```

Papaparseは、他にもできることが多く、ドキュメントが素晴らしいのでぜひご覧ください。

[Papaparse](http://papaparse.com/)

## JSONをCSV形式に変換する処理

Papaparseにオブジェクト配列を渡すことで、簡単にCSV文字列(区切り文字列)に変換してくれます。

```js
import Papa from 'papaparse';
import encoding from 'encoding-japanese';

...

// configの初期値
const config = {
  delimiter: ',', // 区切り文字
  header: true, // キーをヘッダーとして扱う
  newline: '\r\n', // 改行
};

// 区切り文字へ変換
const delimiterString = Papa.unparse(json, config);

// blobUrlへの変換
const strArray = encoding.stringToCode(delimiterString);
const convertedArray = encoding.convert(strArray,'SJIS', 'UNICODE');
const UintArray = new Uint8Array(convertedArray);
const blobUrl = new Blob([UintArray], {type: 'text/csv'});
```

ソースとしては以上です。
のちにダウンロードを行うため、blobへ変換しています。
その変換過程でencoding(encoding-japanese)のconvertで第２引数の文字コードに変換しています。

## ダウンロード処理

ダウンロードでは、擬似的にaタグを利用して、blobを叩いてダウンロードさせるようにします。

```js
const blob = blobUrl;
const aTag = document.createElement('a');

aTag.download = fileName;

// 各ブラウザに合わせ、CSVをダウンロード
if (window.navigator.msSaveBlob) {
  // for IE
  window.navigator.msSaveBlob(blob, aTag.download);
} else if (window.URL && window.URL.createObjectURL) {
  // for Firefox
  aTag.href = window.URL.createObjectURL(blob);

  document.body.appendChild(aTag);

  aTag.click();

  document.body.removeChild(aTag);
} else if (window.webkitURL && window.webkitURL.createObject) {
  // for Chrome
  aTag.href = (window.URL || window.webkitURL).createObjectURL(blob);

  aTag.click();
} else {
  // for Safari
  window.open(
    `data:type/csv;base64,${window.Base64.encode(this.state.content)}`,
    '_blank'
  );
}
```

ダウンロードの処理には、ほとんどPapaparseもencoding-japaneseも利用しません。
各ブラウザで保存方法が違うので、制御式を書いています。
(aタグ使わずにもっといい書き方あるのかな。。。)

# まとめ

まとめとして、一連のソースを記述します。

```js
const config = {
  delimiter: ',', // 区切り文字
  header: true, // キーをヘッダーとして扱う
  newline: '\r\n', // 改行
};

// 区切り文字へ変換
const delimiterString = Papa.unparse(json, config);

// blobUrlへの変換
const strArray = encoding.stringToCode(delimiterString);
const convertedArray = encoding.convert(strArray,'SJIS', 'UNICODE');
const UintArray = new Uint8Array(convertedArray);
const blobUrl = new Blob([UintArray], {type: 'text/csv'});
const blob = blobUrl;
const aTag = document.createElement('a');

aTag.download = fileName;

// 各ブラウザに合わせ、CSVをダウンロード
if (window.navigator.msSaveBlob) {
  // for IE
  window.navigator.msSaveBlob(blob, aTag.download);
} else if (window.URL && window.URL.createObjectURL) {
  // for Firefox
  aTag.href = window.URL.createObjectURL(blob);

  document.body.appendChild(aTag);

  aTag.click();

  document.body.removeChild(aTag);
} else if (window.webkitURL && window.webkitURL.createObject) {
  // for Chrome
  aTag.href = (window.URL || window.webkitURL).createObjectURL(blob);

  aTag.click();
} else {
  // for Safari
  window.open(
    `data:type/csv;base64,${window.Base64.encode(this.state.content)}`,
    '_blank'
  );
}
```

# 後書き

フロント側でも簡単にCSVエクスポートが実装できました。
Papaparseを使えば、インポート処理も実装できるので、なかなか重宝します。