
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、少し前からReact
の記事を公開してきていますが、現状で言いますとVue 3
よりReact
の方が好きになってきている今日この頃です。
そして、そんなReact
で今回つくってみたくなった機能は・・・・・・
JavaScript(ブラウザ)だけでPDFをつくる
というものです。
もちろんPHP
のようなサーバーサイドでつくるのもいいですが、JavaScript
だけで作成できるとなると、なんなら静的なHTML
だけで実装ができるちゃうわけですね。
そこで
今回は「React」で表示されているページをまるごとPDF
化してみたいと思います。
ぜひ何かの参考になりましたら嬉しいです。
「最寄り駅に
ストリートピアノが
設置されました」
開発環境: Laravel 9.x、React、Inertia.js、Vite、TailwindCSS
パッケージをインストールする
では、まずは今回の機能に必要になるパッケージをインストールしておきましょう。
以下のコマンドを実行してください。
npm install jspdf --save-dev
ルートをつくる
続いてルートです。
今回は1つだけでOKです。
routes/web.php
Route::get('pdf', fn() => Inertia::render('Pdf/Index'));
jsPDF を日本語化する
PDF
の作成部分を書いていく前に、jsPDF
を日本語化する準備をしておきましょう。
まずは、以下のページから「ipaexg00401.zip」をダウンロードします。
そして、ダウンロードしたらzip
ファイルを展開します。
すると、中に「ipaexg.ttf」というフォント用ファイルがあるので、これをjsPDF
で使えるように加工します。
では、以下の(本家が用意してくれている)ページへアクセスしてください。
すると、変換フォームが表示されるので以下を参考にして入力&選択し、「Create」ボタンをクリックしてください。
- fontName: ipaexg(※1)
- fontStyle: normal
- Module format: ES modules
- File: (先ほど展開した ipaexg.ttf をファイルで選択)
※1 好きな名前でOKですが、その場合はその他の部分もすべて変更してください。
すると、自動的に「ipaexg-normal.js」というファイルがダウンロードされますので、このファイルをLaravel
の「resources/js/Pages/Pdf/ipaexg-normal.js」へ移動します。
ビューをつくる
では、先ほど設置したファイルも使ってメインのコードを書いていきましょう
resources/js/Pages/Pdf/Index.jsx
import {useEffect, useRef} from "react";
import { jsPDF } from "jspdf";
import "./ipaexg-normal"; //
ダウンロードしたファイル
export default function Index() {
// PDF
const pdfRef = useRef(new jsPDF());
const getFileName = () => {
const timestamp = new Date().getTime();
return `download_${timestamp}.pdf`;
};
const savePdf = () => {
const target = document.querySelector('#pdf');
pdfRef.current.html(target, {
callback(doc) {
const fileName = getFileName();
doc.save(fileName); //
ここで PDF をダウンロード
},
x: 15,
y: 15,
width: 170,
windowWidth: 650
});
};
// Font
useEffect(() => {
pdfRef.current.setFont('ipaexg'); //
フォントを追加
}, []);
return (
<div className="p-5">
<div id="pdf" className="mb-5" style={{fontFamily: 'ipaexg', lineHeight: '2.5rem'}}>
<div>ここの内容が PDF 化されます</div>
<ul>
<li className="bg-red-500 p-3">List 1</li>
<li className="bg-blue-500 p-3">List 2</li>
<li className="bg-yellow-500 p-3">List 3</li>
</ul>
</div>
<button
type="button"
className="text-white bg-blue-700 font-medium rounded-full text-sm px-5 py-2.5 text-center mr-2 mb-2 blue-800"
onClick={() => savePdf()}>
保存する
</button>
</div>
);
}
この中で重要なのが、ページを読み込んだ時にフォントをセットしているuseEffect
の部分です。
useEffect(() => {
pdfRef.current.setFont('ipaexg');
}, []);
これは、「ipaexg-normal.js」の中でフォントは追加されていますが、適用はされていないので、setFont()
を実行する必要があるためです。
また、以下のようにPDF化するタグへのフォント指定も忘れないでください。
<div id="pdf" className="mb-5" style={{fontFamily: 'ipaexg', lineHeight: '2.5rem'}}>
※ なお、Virtual DOM
の中でstyle
を使うと処理スピードが遅くなるらしいので、本番環境ではCSS
内で指定することをおすすめします
作業はこれで終了です。
おつかれさまでした
テストしてみる
では、実際にテストしてみましょう
まずVite
を起動し、「http://******/pdf」へブラウザでアクセスします。
上のようなページが表示されるので、「保存する」ボタンをクリックしましょう。
すると、自動的にPDFがダウンロードされます。
ダウンロードしたファイルを開いてみると・・・・・・
はい
日本語にもなっていますし、(ちょっとずれている部分はありますが)うまくHTML
の内容がPDF
化されています。
成功です。
企業様へのご提案
今回はすべてブラウザ側でPDF
を作成しています。
もちろんサーバー側で作成することもできますが、ブラウザ単体でPDF
作成するメリットは「負荷の軽減」です。
つまり、サーバー内でPDF
を多く作成するとリソース(≒エネルギー)を多く使ってしまうため弱いサーバーですと、最悪ダウンすることも考えられます。
また、AWS
などでは転送料金が比較的高いと言われていますので、できるだけブラウザでできることはブラウザ内で完結させ、省コスト化するというのも戦略のひとつではないでしょうか。
もしそういったご相談がございましたら、いつでもお気軽にお問い合わせからご連絡ください。
お待ちしております
おわりに
ということで、今回は「React + jsPDF」でPDF
を作成してみました。
よりきれいに出力するためには、CSS
を調整する必要があるようでしたが、TailwindCSS
も使えるようでしたし、サイトの性質によっては選択肢のひとつになるんじゃないでしょうか。
ぜひみなさんも楽しんでやってみてくださいね。
ではでは〜
「名刺に書いてる
メアドにタイポ発見…
(教えてくださってありがとうございます)」