LoginSignup
3
0

NuxtでPDF.jsを動かす

Posted at

はじめに

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に以下のように値を設定しています。

image.png

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>

できました🎉
image.png

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0