- バックエンド / リーダー候補
- PdM
- Webエンジニア(シニア)
- Other occupations (17)
- Development
- Business
Webpack 5でPDF.jsをいい感じに呼び出す
Photo by Markus Winkler on Unsplash
PDF.jsはブラウザでPDFを表示できるすごいライブラリです。PDF.jsはWeb Workersを使うため、Webpackなどのモジュールバンドラーと組み合わせるときは設定が必要な場合があります。これまでWebpackではworker-loaderを使うのが標準的な方法で、設定を簡単に済ませるためのモジュールも提供されていました。
import pdfjsLib from "pdfjs-dist/webpack";
Webpack 5でもworker-loaderは使えますが非推奨化されています。かわりにブラウザで使うときとよく似た構文でBackground workerを初期化できるようになりました。
new Worker(new URL('./worker.js', import.meta.url));
pdfjs-dist/webpackがやっていることは、worker-loaderをinline loader syntaxで呼び出してworkerPortにセットするというだけです。これを自分で行えばいいので、以下のようにすればworker-loaderを使わずにpdf.jsをセットアップできます。
import pdfjsLib from "pdfjs-dist";
pdfjsLib.GlobalWorkerOptions.workerPort =
new Worker(new URL("pdfjs-dist/build/pdf.worker.js", import.meta.url));
new URL()
の第一引数が相対パスではないので、Webpackの外では動かないでしょう。それが気になる場合は、同じディレクトリにワーカーをimportするだけのダミーモジュールを置くともう少し自然かもしれません。
Worker syntaxの詳細
新しいWorker用構文は本体同梱のWorkerPluginで実装されています。以下の4つの書き方がWorkerクラスとして検出されます。
// Worker グローバル変数
new Worker(...);
// SharedWorker グローバル変数
new SharedWorker(...);
// register関数 (newはつかない)
navigator.serviceWorker.register(...);
// worker_threads モジュールの Worker エクスポート
import { Worker } from 'worker_threads';
new Worker(...);
このとき第一引数がさらにチェックされ、以下のフォーマットであることがチェックされます。
new URL("...", "...");
// ^^^^^ arg2: 簡約後の式が文字列リテラル
// ^^^^^ arg1: 簡約後の式が文字列リテラル
// ^^^ callee: 簡約後の式がURLへの参照
上のcallee, arg1, arg2の位置でそれぞれ式の簡約が試みられるため、 import.meta.url
はこの時点で展開されます。フォーマットが一致していても arg2 の値は import.meta.url
の値と一致していないといけないので、実際には import.meta.url
以外に書きようはないでしょう。
ここまでの条件を満たすと、この new URL(...)
はWeb Workersのworker実装を要求する特殊なインポート命令として解釈されます。URLコンストラクタの第一引数をモジュールパスとみなして解決し、Web Workers用にあしらえたチャンクを生成します。 new URL(...)
全体がチャンクのURLに置き換えられます。
なお、似たような構文としてURLアセット構文があります。Web Workersの初期化以外の位置でこのようなURLオブジェクトを生成すると、ファイルがそのまま切り出され、そのアップロード予定のURLで置き換えられます。これは画像の取り込みで使うことができます。
いずれも条件を満たさないときはそのままの形で残される (ビルドエラーにはならない) ので、リファクタリングで意図せず壊してしまわないかは心配です。たとえば new URL()
部分を変数に切り出しても見た目上は同じ動作に見えますが、Webpackにとっては扱いが変わってしまいます。このような問題を防ぐために、意図をコメントに残しておくのがいいかもしれません。