Help us understand the problem. What is going on with this article?

クライアントサイド(React)で日本語PDFを出力する。

More than 1 year has passed since last update.

前書き

Reactの案件の中で日本語のPDFを出力する必要があり、
そのためにクライアントサイド(React側)のみで日本語PDFを出力する方法をまとめたので記事にしました。

前準備

今回は、pdfmakeというクライアントサイドでPDFを出力するJavaScriptライブラリを利用します。
npmパッケージでも存在するのでコマンドでインストールできるのですが
日本語フォントを利用するため、Githubからjsファイルを落とします。

bpampuch/pdfmake

上記のリポジトリから以下のファイルを落とします。
- pdfmake.min.js
- vfs_fonts.js

日本語PDF出力の準備

pdfmakeは、そのまま利用すると日本語フォントが利用できません。
そのため、独自に日本語のフォントを利用できるようにする必要があります。
ダウンロードしてきた、vfs_fonts.jsに日本語フォントを登録します。

そのやり方に関しましては以下の記事を参考にしました。
その中で、すでに日本語フォントが適用されたvfs_fonts.jsがあるフォークのリポジトリがあるのでそちらを利用させて頂きます。

JavaScriptでクライアントサイドだけで日本語PDF出力する

React + Webpack上での利用

前準備、日本語PDF出力の準備の項目で以下の2ファイルが準備できましたら

  • pdfmake.min.js
  • vfs_fonts.js(日本語フォント適用)

React + Webpack上で利用するための設定を行います。

まず、pdfmakeはコンポーネントの中でインポートしての利用はできません。(vfs_fonts.jsが独自のため)
なので、pdfmake.min.jsとvfs_fonts.jsをindex.htmlの中でscriptタグで呼び出す必要があります。
CDN化しても可能かもしれませんが、今回はローカルにファイルを置いてwebpackでビルドはせず移動だけ、を試してみようと思います。

ローカルへのファイルの配置

とりあえず、フォルダ名はおいといて、src直下、assetsの中に配置しました。

└── localScript
    └── pdfmake
        ├── pdfmake.min.js
        └── vfs_fonts.js

ここからライブラリを直接呼び出すことはないので、位置は問題ないと思います。

Webpackの設定

ファイル移動のため、以下のプラグインを利用しますのでコマンドでインストールしてください。

npm install --save copy-webpack-plugin
yarn add copy-webpack-plugin

インストールが完了したら、Webpack.config.jsを編集します。

...
const CopyWebpackPlugin = require('copy-webpack-plugin');
...
  plugins: [
    new CopyWebpackPlugin([{
      from: './src/assets/localScript/pdfmake',
      to: './build/plugins/pdfmake',
    }]),
  ],
...

以上の設定で、CopyWebpackPluginを用いて、先ほど配置したpdfmakeのディレクトリをbuildフォルダのプラグインの中にコピーします。
もともとビルドフォルダに置いて置いてもいいかもしれませんが、少しスマートではない気がしますのできちんと、設定を行うことにしました。

index.htmlの編集

index.htmlの中で、pdfmake.min.jsとvfs_fonts.jsを呼び出します。
単純に、scriptタグを書くだけですので、ここは簡単です。

<!-- public/index.html -->
<script src="./build/plugins/pdfmake/pdfmake.min.js"></script>
<script src="./build/plugins/pdfmake/vfs_fonts.js"></script>

React内での利用

では、React内でpdfmakeを利用して日本語PDFを出力できるように行います。

JSX内は以下の感じになります。
PDF出力の関数です。
HTMLをオブジェクトのように書く形になります。

  GeneratePdfFromHtml() {
    pdfMake.fonts = {
      GenShin: {
        normal: 'GenShinGothic-Normal-Sub.ttf',
        bold: 'GenShinGothic-Normal-Sub.ttf',
        italics: 'GenShinGothic-Normal-Sub.ttf',
        bolditalics: 'GenShinGothic-Normal-Sub.ttf',
      },
    };
    const defaultStyle = 'GenShin';
    const docDefinition = {
        content: [
            {
                text: 'React Generate PDF Sample',
                style: 'header'
            },
            {
                text: 'Sentence',
                style: 'subheader'
            },
      `Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
      す以下、著作しられ性質を翻訳権フリーの採録状態でなるれるても従っます、最小限の条件は、
      一定しライセンスを発表さことについて著作重要であるているますた。
      または、条件の.物は、権利の掲載し明記必要で利用含む、その方針が満たすを陳述行っことに回避満たすられな。
      接触して、ここの受信は無いでも行うあるです。
      Aenean commodo ligula eget dolor. Aenean massa.
      sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
      eleifend tellus.`,
            {
                text: 'Styles',
                style: 'subheader'
            },
            {
                text: '文字',
                style: { fontSize:  15 },
            },
            {
                text: '赤文字',
                style: { color: 'red', fontSize: 30 },
            },
            {
                text: '青文字',
                style: { color: 'blue', fontSize: 40 },
            },
            {
                text: '黄文字',
                style: { color: 'yellow', fontSize: 50 },
            },
      ],
        defaultStyle: {
        font: defaultStyle,
        },
      styles: {
        header: {
          fontSize: 30,
        },
        subheader: {
          fontSize: 20,
        },
      },
    };

    pdfMake.createPdf(docDefinition).open();
  }

細かなドキュメントは、pdfmakeの公式ドキュメントをご参考ください。
主なコンテンツとスタイルをそれぞれ自由に設定できます。
Reactをしていれば、スタイルの書き方はご覧になったことがあるものだと思うので、とっつきやすいと思います。

以上の関数を用意して、呼び出せば、別タブで日本語のPDFが表示されます。

後書き

案件で、PDF出力が必要になったので、今回は調査しましたが
なかなか情報が出てきません....
PDFの出力は、他の件でも必要になるかもしれませんので
もっと調査して、ベストな実装を行えればと思います。

maecho
大阪のエンジニアです。 最近は、ReactNativeやFlutterでアプリ作ってます。 他、AWSや、GoでAPI作ってます。 インフラが好きです。
https://as-rule.io
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away