📁
Next.jsでExcelファイルを出力する方法
はじめに
在庫管理システムなどを開発している場合、Excelファイルを出力したい場面は多々あります。今回はNext.jsを利用して、Excelファイルを出力する方法について解説していきます。
使用ライブラリ
Excelファイルを出力するためのライブラリは複数ありますが、今回はその中からSheet.jsを選択しました。Sheet.jsとは、JavaScriptでExcelファイルを扱うためのライブラリで、Excelファイルの読み込み・編集・エクスポートを可能にします。
Sheet.jsを選定した理由としては以下の通りです。
- 定期的なメンテナンス
- ドキュメントが充実
- ダウンロード数の多さ
一方でデメリットもあります。Sheet.jsではExcelファイルをスタイリングすることができないため、Excelファイルを出力したい場合は他のライブラリ(ExcelJS / xlsx-populate)を検討する必要があります。
ライブラリの比較に関しては以下の記事にまとまっています。
実装方法
実装方法は至ってシンプルです。処理の流れとしては次の通りです。
- データの取得(今回はスタブデータで代用)
- Excel上のデータ配置設定
- ワークシート・ワークブック作成
- ワークシート・ワークブックに対してデータの割り当て
app/page.tsx
"use client";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { SummaryCards } from "@/components/delivery/SummaryCards";
import { DeliveryTable } from "@/components/delivery/DeliveryTable";
import { Download } from "lucide-react";
import { useCallback } from "react";
import { DeliveryData } from "@/lib/types/delivery";
import { downloadExcel, formatDataForExcel } from "@/lib/utils/excel";
export default function Home() {
// 表示するスタブデータの定義(適宜APIのレスポンスデータ等に置き換える)
const deliveryData: DeliveryData = {
totalWeight: 1000,
totalQuantity: 3000,
items: [
{
date: "2024/11/24",
productName: "パイプ",
quantity: 1500,
weight: 500,
},
{
date: "2024/11/24",
productName: "スチール",
quantity: 1500,
weight: 500,
},
],
};
// イベントハンドラー処理でExcelファイルをダウンロード(詳細はutils参照)
const handleDownload = useCallback(() => {
const excelData = formatDataForExcel(deliveryData);
downloadExcel(excelData, "delivery-data.xlsx");
}, [deliveryData]);
return (
<div className="min-h-screen bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
<div className="max-w-4xl mx-auto">
<Card className="p-6">
<div className="flex justify-between items-center mb-6">
<h1 className="text-2xl font-semibold text-gray-900">在庫データ</h1>
<Button
onClick={handleDownload}
className="flex items-center gap-2"
>
<Download className="h-4 w-4" />
Excelダウンロード
</Button>
</div>
<div className="space-y-6">
<SummaryCards
totalWeight={deliveryData.totalWeight}
totalQuantity={deliveryData.totalQuantity}
/>
<DeliveryTable items={deliveryData.items} />
</div>
</Card>
</div>
</div>
);
}
- 出力したいデータを
deliveryData
として定義します。APIのレスポンス値などをExcelデータで出力したい場合は、適宜こちらを書き換えてください。 -
handleDownload
関数を定義し、ボタンが押下されたら、utilsファイル内で定義したSheet.jsの機能を利用してExcelファイルをダウンロードします。
lib/utils/excel.ts
import * as XLSX from "xlsx";
import { DeliveryData, ExcelRow } from "../types/delivery";
// カラムの幅設定
const COLUMN_WIDTHS = [
{ wch: 12 }, // 納入日
{ wch: 15 }, // 商品名
{ wch: 10 }, // 数量
{ wch: 10 }, // 重量
];
// Excelシート内で表示したいデータを2次元配列上にマッピング
export const formatDataForExcel = (data: DeliveryData): ExcelRow[] => {
return [
["重量合計", data.totalWeight],
["数量合計", data.totalQuantity],
[],
["納入日", "商品名", "数量", "重量"],
...data.items.map((item) => [
item.date,
item.productName,
item.quantity,
item.weight,
]),
];
};
// ワークブック・ワークシートを作成し、データを割り当てる
export const downloadExcel = (data: ExcelRow[], filename: string) => {
// ワークブックの作成
const wb = XLSX.utils.book_new();
// ワークシートの作成とデータ適用
const ws = XLSX.utils.aoa_to_sheet(data);
// カラム幅の設定
ws["!cols"] = COLUMN_WIDTHS;
// アラインメントの設定
for (let i = 5; i < data.length + 1; i++) {
ws[`A${i}`].s = { alignment: { horizontal: "left" } };
ws[`B${i}`].s = { alignment: { horizontal: "left" } };
}
// ワークブックにワークシートを追加
XLSX.utils.book_append_sheet(wb, ws, "在庫データ");
// ファイルの書き込み
XLSX.writeFile(wb, filename);
};
-
formatDataForExcel
関数にてデータを2次元配列上にマッピングします。このインデックス位置がそのままExcelシートに反映されます。 -
downloadExcel
関数では以下の3点を行います。- ワークブック・シートの作成
- 2次元配列データの書き込み
- Excelの横幅適用
デモ
成果物は以下になります。
おわりに
今回はNext.js + Sheet.jsを用いたExcelファイル出力の方法について解説しました。上述した通り、デザイン面での制限があるため、興味がある方は別のライブラリで試してみることをお勧めします。一方で、Sheet.jsでも簡単にExcelファイル出力が実現できるため、要件に応じて選択するのが良いと思います。
参考資料
Discussion