iPhone Safari での PDF 全ページ表示問題を解決するため、<iframe> を使った PDF 表示を廃止し、react-pdf を用いた全ページレンダリングに切り替えた。 iframe では、 iOS Safari において PDF が1ページ目しか表示されなかった。
使用パッケージとバージョン
| パッケージ | バージョン | 備考 |
|---|---|---|
react-pdf | ^10.4.1 | Document / Page コンポーネント提供 |
pdfjs-dist | ^5.4.296 | react-pdf が内部で使うバージョンに合わせる(重要) |
インストール
pnpm install react-pdf pdfjs-dist@5.4.296
pdfjs-dist のバージョンは必ず react-pdf が要求するものに揃えること。 バージョンが異なると後述のバージョン不一致エラーが発生する。
遭遇したエラーと解決
エラー 1: DOMMatrix is not defined(SSRエラー)
const SCALE_MATRIX = new DOMMatrix();digest: ‘534975899’
原因: pdfjs-dist のモジュール初期化時に DOMMatrix(ブラウザ専用API)を使用しているため、 Next.js の SSR フェーズ(Node.js 環境)でクラッシュする。'use client' を付けてもモジュールの初期化はサーバーで走るため回避できない。
解決策: react-pdf を使うコンポーネントを別ファイル(PdfViewer.tsx)に分離し、next/dynamic の ssr: false でクライアントのみ読み込む。
// IntroMediaOverlay.tsx
import dynamic from 'next/dynamic';
const PdfViewer = dynamic(
() => import('@/components/PdfViewer'),
{ ssr: false }
);
エラー 2: API version does not match Worker version
エラー内容:UnknownErrorException: The API version "5.4.296" does not match the Worker version "5.5.207".
原因: package.json に直接インストールされた pdfjs-dist が 5.5.207 だったのに対し、react-pdf 内部が使う pdfjs-dist は 5.4.296 だった。 Worker ファイルの解決に 5.5.207、API には 5.4.296 が使われバージョン不一致になった。
解決策: pdfjs-dist を react-pdf が要求するバージョンに固定する。
pnpm install pdfjs-dist@5.4.296
確認方法:
cat node_modules/react-pdf/package.json | grep pdfjs-dist
# → "pdfjs-dist": "5.4.296"
実装コード
PdfViewer.tsx(react-pdf 本体)
// src/components/PdfViewer.tsx
'use client';
import { useRef, useState, useCallback } from 'react';
import { Document, Page, pdfjs } from 'react-pdf';
import 'react-pdf/dist/Page/AnnotationLayer.css';
import 'react-pdf/dist/Page/TextLayer.css';
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.mjs',
import.meta.url,
).toString();
export default function PdfViewer({ url }: { url: string }) {
const [numPages, setNumPages] = useState<number>(0);
const containerRef = useRef<HTMLDivElement>(null);
const [containerWidth, setContainerWidth] = useState<number>(600);
const onDocumentLoadSuccess = useCallback(
({ numPages }: { numPages: number }) => {
setNumPages(numPages);
if (containerRef.current) {
setContainerWidth(containerRef.current.clientWidth);
}
},
[]
);
return (
<div ref={containerRef} className="overflow-y-auto max-h-[60vh] p-2">
<Document
file={url}
onLoadSuccess={onDocumentLoadSuccess}
loading={<span>PDF読み込み中...</span>}
>
{Array.from({ length: numPages }, (_, i) => (
<Page
key={i}
pageNumber={i + 1}
width={containerWidth - 16}
className="mb-2"
/>
))}
</Document>
</div>
);
}
Jsree
JsRee for Windows | JSONツリービューワー
無音カメラアプリ
無音ガメラ Web版

