NuxtでPDF.jsを動かす

## はじめに
Nuxt(v3.9.0)で[PDF.js](https://mozilla.github.io/pdf.js/)を使うときにちょいちょい躓いたので動作させるまでのメモです。

手順通りに進めばPDF.jsでPDFファイルをブラウザ上にレンダリングすることができます。
PDF.jsの細かい説明はしません。

## インストール

今回はyarnでインストールしました。
バージョンは '4.0.379'です。

```zsh
yarn add pdfjs-dist
```

## ライブラリ import

任意のコンポーネントでimportします。

```vue
<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に辿り着きました。

https://github.com/mozilla/pdf.js/issues/17245

optimizeDepsのesbuildOptionsを指定するか[vite-plugin-top-level-await](https://www.npmjs.com/package/vite-plugin-top-level-await)を使用することで最上位にawaitがあるコードでもビルドできるようになるそうです。

今回はお手軽そうなoptimizeDepsのesbuildOptionsを指定しました。
nuxt.config.tsにoptimizeDeps...を追加します。
```js
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](https://mozilla.github.io/pdf.js/examples/)をみるとworkerSrcに以下のように値を設定しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2527942/ca001350-7cf6-7018-34e4-716186234a77.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に指定してみます。
```js
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ページ目を表示するコードを書いてみます。

```vue
<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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2527942/83a63322-2c46-1b84-07c1-ef1af6af7336.png)