⛳
viteでpdf.jsを使おうとしたら意外に手間取った
経緯
私は普段LINEのliffを使ったシステムを構築しているのですが、liffでpdfを表示させるとiPhoneでは綺麗に表示されるがAndroidだとダウンロードされてしまう事態が発生。
しぶしぶ、代わりにブラウザ上でpdfをレンダリングする方法がないか調べているとpdf.jsというライブラリを発見!
日本語記事ではstableなファイルをそのままダウンロードしてサーバー内に配置している方法がよく紹介されているが、gitで管理しているので、ディレクトリを汚したくない!ということでnpmでinstallすることに。
Laravel + vite を使っているので、 @viteでjsを読み込ませ、
import * as pdfjsLib from "pdfjs-dist";
をすると、
エラーが発生
Top-level await is not available in the configured target environment
というエラーがvite上で発生。
そのままGoogleで検索してみると下記issueがHit
解決方法
とりあえずvite.config.jsに下記コードを埋め込めば大丈夫みたい
vite.config
optimizeDeps:{
esbuildOptions: {
target: "es2022",
}
}
おまけ
pdf全ページ表示するコード全文載せておきます。
地味に全ページ表示させる方法がfor文で回す必要があり、面倒くさかったです。
preview-pdf.js
import * as pdfjsLib from "pdfjs-dist";
import * as pdfWorker from "pdfjs-dist/build/pdf.worker.mjs";
const pdfPath = "/assets/hoge.pdf";
// 非同期でPDFファイルを読み込み
const loadingTask = pdfjsLib.getDocument(pdfPath);
(async () => {
const pdf = await loadingTask.promise;
// 全てのページを取得
for (let i = 1; i <= pdf.numPages; i++) {
const page = await pdf.getPage(i);
const scale = 1.0;
const viewport = page.getViewport({ scale });
// 高DPIをサポート
const outputScale = window.devicePixelRatio || 1;
// PDFのページ寸法を使用してキャンバスを準備
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
canvas.width = Math.floor(viewport.width * outputScale);
canvas.height = Math.floor(viewport.height * outputScale);
canvas.style.width = Math.floor(viewport.width) + "px";
canvas.style.height = Math.floor(viewport.height) + "px";
// 縦並びにするためにblock要素を追加
canvas.style.display = "block";
const transform = outputScale !== 1
? [outputScale, 0, 0, outputScale, 0, 0]
: null;
// PDFのページをキャンバスにレンダリング
const renderContext = {
canvasContext: context,
transform,
viewport,
};
page.render(renderContext);
// キャンバスをDOMに追加
pdfElement.appendChild(canvas);
}
})();
追記
上記の方法で npm run dev しているときは良かったのですが、いざbuildしようとするとまた同じエラーが出ました。そのためもう一つの方法である、vite-plugin-top-level-awaitのプラグインを使うことにしました。
terminal
npm i vite-plugin-top-level-await
vite configに追記、また、謎にpath2dのエラーもで始めたので、追記してます。
vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import topLevelAwait from "vite-plugin-top-level-await";
export default defineConfig({
plugins: [
topLevelAwait({
// The export name of top-level await promise for each chunk module
promiseExportName: "__tla",
// The function to generate import names of top-level await promise in each chunk module
promiseImportName: i => `__tla_${i}`
}),
laravel({
input: [
'resources/css/app.css',
],
refresh: true,
}),
],
optimizeDeps: {
esbuildOptions: {
target: "es2022",
}
},
build: {
rollupOptions: {
// ライブラリーにバンドルされるべきではない依存関係を
// 外部化するようにします
external: ['path2d-polyfill']
},
},
});
これで解決したが、buildした際に以下の残念な忠告が出るようになってしまいました。
ただ、ここは原因探している暇もないので、無視することに。
terminal
(!) Some chunks are larger than 500 kBs after minification. Consider:
- Using dynamic import() to code-split the application
- Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/configuration-options/#output-manualchunks
- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.
Discussion