GAミント至上主義

Web Monomaniacal Developer.

NestJS + NuxtでShift JIS形式に変換したCSVをダウンロードさせる

NestJS + NuxtでひさびさにCSVでかつエクセルでもそのまま開けるようにShift_JIS形式にエンコードする必要があり、ハマったのでメモ。

いろいろ試してbase64形式で返す形に落ち着いた。

NestJSのバージョン

    "@nestjs/common": "10.3.8",
    "@nestjs/config": "3.2.2",
    "@nestjs/core": "10.3.8",

Nuxtのバージョン

 "nuxt": "3.11.2",

NestJS側にはencoding-japaneseをインストールします

www.npmjs.com

以下コードは必要なところだけ抜粋で動作未確認です

NestJSコントローラ

import * as Encoding from 'encoding-japanese'
// 略

export class CsvController {

  @Get()
  async getJobCsvSjis() {
    // CSVのutf-8文字列を返す架空メソッド
    const csv = await getCsvString(id)
    return this.encodeToSjisBase64(csv)
  }

  private encodeToSjisBase64(csv: string) {
    const unicodeArray = Encoding.stringToCode(csv)
    const sjisArray = Encoding.convert(unicodeArray, {
      from: 'UNICODE',
      to: 'SJIS',
    })
    const base64str = Encoding.base64Encode(sjisArray)
    return 'data:text/csv;base64,' + base64str
  }
}

Nuxt側ではdowload属性つけたaタグクリック形式。 NestJS側で返したbase64文字列をそのままhrefにぶっこみます。

Nuxt

<template>
  <button c@click="downloadCsv()">SJIS CSV</button>
</template>
<script setup>
const downloadCsv = async () => {
  isLoading.value = true
  const res = await $fetch(`/csv/${job}`, {
    method: 'GET',
  })
  const link = document.createElement('a')
  link.href = res
  link.download = `sjis.csv`
  link.click()
  link.remove()
}
</script>