はじめに
Nuxt(v3.9.0)でPDF.jsを使うときにちょいちょい躓いたので動作させるまでのメモです。
手順通りに進めばPDF.jsでPDFファイルをブラウザ上にレンダリングすることができます。
PDF.jsの細かい説明はしません。
インストール
今回はyarnでインストールしました。
バージョンは '4.0.379'です。
yarn add pdfjs-dist
ライブラリ import
任意のコンポーネントでimportします。
<script setup>
import * as PDFJS from 'pdfjs-dist'
</script>
ERROR: Top-level await is not available
この時点で以下のエラーが発生しました。
error while updating dependencies:
Error: Build failed with 1 error:
node_modules/pdfjs-dist/build/pdf.mjs:18101:53: ERROR: Top-level await is not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari14" + 2 overrides)
最上位のawaitがあるコードのビルドでこけているようです
色々模索していたところ、pdf.jsの以下のissueに辿り着きました。
optimizeDepsのesbuildOptionsを指定するかvite-plugin-top-level-awaitを使用することで最上位にawaitがあるコードでもビルドできるようになるそうです。
今回はお手軽そうなoptimizeDepsのesbuildOptionsを指定しました。
nuxt.config.tsにoptimizeDeps...を追加します。
export default defineNuxtConfig({
vite: {
build: {
target: ['esnext', 'es2022']
},
esbuild: {
target: "es2022"
},
optimizeDeps:{
esbuildOptions: {
target: "es2022",
}
}
},
})
再度ビルドし直すとエラーが解消されていました🎉
Cannot set properties of undefined (setting 'workerSrc')
ビルドに成功したのでPDFを表示する処理を実装してページを開いたところ、以下のエラーに遭遇しました。
Cannot set properties of undefined (setting 'workerSrc')
ExamplesをみるとworkerSrcに以下のように値を設定しています。
workerファイルを指定してあげれば良さそうなので、yarn addした際のファイルを漁っていたら、それっぽいものを見つけました。
$ ls node_modules/pdfjs-dist/legacy/build
pdf.d.mts pdf.sandbox.min.mjs pdf.worker.mjs
pdf.min.mjs pdf.sandbox.mjs pdf.worker.mjs.map
pdf.mjs pdf.sandbox.mjs.map
pdf.mjs.map pdf.worker.min.mjs
pdf.worker.min.mjsをworkerSrcに指定してみます。
import * as PDFJS from 'pdfjs-dist'
import * as pdfjsWorker from 'pdfjs-dist/legacy/build/pdf.worker.min.mjs'
PDFJS.GlobalWorkerOptions.workerSrc = pdfjsWorker
ページを再描画したところ、Cannot set properties of undefined (setting 'workerSrc')が発生しなくなりました🎉
PDF表示
エラーは潰せたようなので動作確認としてPDFの1ページ目を表示するコードを書いてみます。
<template>
<div class="Container">
<div ref="renderPdfSpace"></div>
</div>
</template>
<script setup>
import * as PDFJS from 'pdfjs-dist'
import * as pdfjsWorker from 'pdfjs-dist/legacy/build/pdf.worker.min.mjs'
PDFJS.GlobalWorkerOptions.workerSrc = pdfjsWorker
const renderPdfSpace = ref(null)
onMounted(() => {
const loadingTask = PDFJS.getDocument('https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf')
loadingTask.promise.then((pdf) => {
console.log('PDF loaded')
// PDFのページ数を取得
const numPages = pdf.numPages
console.log('numPages', numPages)
// 1ページ目を取得
pdf.getPage(1).then((page) => {
console.log('Page loaded')
const scale = 1.5
const viewport = page.getViewport({ scale: scale })
// Canvasを作成してPDFをレンダリング
const canvas = document.createElement('canvas')
const context = canvas.getContext('2d')
canvas.height = viewport.height
canvas.width = viewport.width
// CanvasをDOMに追加
renderPdfSpace.value.appendChild(canvas)
// PDFページをCanvasにレンダリング
const renderContext = {
canvasContext: context,
viewport: viewport
}
page.render(renderContext)
})
}, (reason) => {
// PDFのロードに失敗した場合
console.error(reason)
})
})
</script>