発生した問題
Nuxt 3プロジェクトでIIIFマニフェストの画像を表示するために、Universal Viewer(UV)をiframeで埋め込んでいました。従来は外部の https://universalviewer.io/uv.html を参照していましたが、ある時点からビューアが表示されなくなりました。
ブラウザのコンソールには以下のエラーが出力されます。
SES Removing unpermitted intrinsics
UV.js:2 Unknown content type
原因の調査
universalviewer.ioのリダイレクト
まず確認したところ、universalviewer.io は universalviewer.dev にリダイレクトされるようになっていました。
<meta http-equiv="refresh" content="0; url=https://universalviewer.dev/uv.html">
リダイレクト先の universalviewer.dev/uv.html でも同じ「Unknown content type」エラーが発生します。公式サイト自体で問題が再現する状態でした。
埋め込み用HTMLの初期化方式の違い
UV 4.xには2つのHTMLファイルが同梱されています。
uv.html:iframe埋め込み用。IIIFURLAdapter(true)(embeddedモード)で初期化index.html:デモページ。IIIFURLAdapter()(通常モード)で初期化し、iiifManifestIdを明示的に渡す
uv.htmlの埋め込みモードでは、IIIF Presentation API 2.0のマニフェストを読み込んだ際にコンテンツタイプの判定に失敗し、「Unknown content type」が発生するようです。
一方、デモページ(index.html)と同じ初期化方式を使うと正常に動作します。Netlifyにデプロイされた uv-v4.netlify.app で確認できました。
https://uv-v4.netlify.app/#?manifest=https://kokusho.nijl.ac.jp/biblio/200017711/manifest&cv=80
URLパラメータの形式
もうひとつの違いは、URLパラメータの渡し方です。
uv.html(埋め込み用):?manifest=...#?cv=...(クエリパラメータ+ハッシュ)index.html(デモ用):#?manifest=...&cv=...(ハッシュパラメータのみ)
動作する方式はハッシュパラメータのみで完結する形式でした。
対処方法
1. UV 4.2.1をローカルに配置
npmパッケージからUV 4.2.1の必要ファイルを public/uv/ に配置しました。
npm pack universalviewer@4.2.1
tar xzf universalviewer-4.2.1.tgz
最終的に必要なファイルは以下の4点です。
public/uv/
├── umd/ # UV本体 + チャンクJS(約190ファイル)
├── uv.css # スタイルシート
├── uv.html # 埋め込みページ(カスタム版)
└── uv-iiif-config.json # IIIF設定
cjs/、esm/、デモ用のindex.htmlやコレクションJSONは不要です。
2. 埋め込みページのカスタマイズ
uv.htmlを、デモページと同じ初期化方式に書き換えました。
<script>
document.addEventListener("DOMContentLoaded", function () {
var urlAdapter = new UV.IIIFURLAdapter();
var iiifManifestId =
urlAdapter.get("iiif-content") ||
urlAdapter.get("manifest") ||
urlAdapter.get("iiifManifestId");
var canvasIndex = urlAdapter.get("cv") || 0;
var data = urlAdapter.getInitialData({
iiifManifestId: iiifManifestId,
canvasIndex: Number(canvasIndex),
});
var uv = UV.init("uv", data);
urlAdapter.bindTo(uv);
uv.on("configure", function ({ config, cb }) {
cb(
fetch("uv-iiif-config.json").then(function (response) {
return response.json();
})
);
});
var $UV = document.getElementById("uv");
function resize() {
var w = window.innerWidth;
var h = window.innerHeight;
$UV.style.width = w + "px";
$UV.style.height = h + "px";
if (uv && uv.resize) {
uv.resize();
}
}
addEventListener("resize", resize);
resize();
});
</script>
変更点は以下の通りです。
IIIFURLAdapter(true)→IIIFURLAdapter()(embeddedモードを無効化)getInitialData({embedded: true})→getInitialData({iiifManifestId, canvasIndex})(マニフェストを明示的に渡す)uv-iiif-config.jsonを読み込むconfigureハンドラを追加- リサイズ時に
uv.resize()を呼び出し
3. iframe側のURL形式を変更
Vueコンポーネント側で、URLをハッシュパラメータ形式に変更しました。
// 変更前
`https://universalviewer.io/uv.html?manifest=${field.manifest}#?cv=${cv}`
// 変更後
`/uv/uv.html#?manifest=${field.manifest}&cv=${cv}`
補足
- 「SES Removing unpermitted intrinsics」はUV内部のセキュリティ機構(SES/Hardened JavaScript)による警告で、動作には影響しません
- UV 4.xの
umd/ディレクトリには約190のチャンクJSファイルが含まれます。UV.js単体では動作しません - 今回テストしたマニフェストはIIIF Presentation API 2.0形式(
sc:Manifest)です。API 3.0形式での動作は未確認です