PDF.js не отображается в Tauri: Полное решение для разработчиков
Исправьте проблемы с отображением PDF.js в приложениях Tauri: настройте протоколы ресурсов, CSP и доступ к файлам, чтобы PDF корректно отображался на настольных.
PDF отображается в браузере, но не в приложении Tauri
Я разрабатываю приложение Tauri + Vite + React с просмотрщиком PDF, использующим PDF.js. В браузере, когда я открываю http://localhost:5173/sample.pdf, PDF отображается без ошибок, но внутри настольного приложения Tauri PDF не рендерится. Элемент <canvas> появляется, но страница PDF не отрисовывается, оставаясь пустой. В пользовательском интерфейсе и в терминале нет видимых ошибок.
Детали проблемы
- PDF-файл находится в
lonefoxpdf/public/sample.pdfи корректно загружается в браузере. - Я пробовал использовать абсолютный URL файла:
file:///C:/Users/getsu/OneDrive/Desktop/lonefoxpdf/public/sample.pdf.
Браузер всё равно загружает его, но приложение Tauri продолжает показывать пустой<canvas>.
Реализация кода
Настройка воркера PDF.js (PdfViewer.jsx)
import * as pdfjsLib from "pdfjs-dist/legacy/build/pdf";
pdfjsLib.GlobalWorkerOptions.workerSrc =
new URL('pdfjs-dist/build/pdf.worker.entry', import.meta.url).href;
Загрузка PDF в useEffect
useEffect(() => {
let cancelled = false;
const loadPdf = async () => {
try {
const pdf = await pdfjsLib.getDocument("/sample.pdf").promise;
if (cancelled) return;
const page = await pdf.getPage(1);
const viewport = page.getViewport({ scale: 1.2 });
const canvas = canvasRef.current;
canvas.width = viewport.width;
canvas.height = viewport.height;
const ctx = canvas.getContext("2d");
await page.render({ canvasContext: ctx, viewport }).promise;
setLoading(false);
} catch (error) {
console.error("Error loading PDF:", error);
setLoading(false);
}
};
loadPdf();
return () => { cancelled = true };
}, []);
Отрисовка компонента (App.jsx)
<PdfViewer url="/sample.pdf" />
Конфигурация allowlist в Tauri
"allowlist": {
"fs": {
"readFile": true,
"scope": ["$RESOURCE/*", "$APP/*"]
}
}
Вопрос
Что может вызывать корректную отрисовку PDF в браузере, но отсутствие рендеринга в приложении Tauri, и как я могу решить эту проблему? Есть ли какие‑то специфические нюансы загрузки PDF в Tauri, которые отличаются от поведения обычного веб‑браузера?
Проблема, с которой вы столкнулись, является распространённой при работе с PDF.js в приложениях Tauri. Обычно её корень лежит в ограничениях безопасности Tauri, которые запрещают прямой доступ к файлам через обычные веб‑протоколы, в отличие от обычных браузеров. В изолированной среде WebView Tauri не может обращаться к локальным файлам по путям /sample.pdf или URL‑у file://, потому что WebView работает под другими правилами безопасности.
Содержание
- Понимание модели безопасности Tauri
- Доступ к файлам и настройка путей
- Проблемы конфигурации воркера PDF.js
- CSP и требования к протоколам
- Пошаговые решения
- Альтернативные подходы
- Отладка и проверка
Понимание модели безопасности Tauri
Tauri работает с приоритетом безопасности, который существенно отличается от браузерной среды. Когда вы запускаете приложение в браузере, политика безопасности более гибкая и позволяет доступ к локальным файлам, но WebView в Tauri строго изолирован, чтобы сохранить безопасность.
Согласно документации Tauri по файловой системе, для доступа к файлам необходимо использовать специальные протоколы и настройки. WebView в Tauri разрешает пути относительно tauri://localhost, а не напрямую к файловой системе. Это означает, что путь /sample.pdf работает в браузере, потому что он разрешается относительно веб‑сервера, но в Tauri он не найден.
Ключевое различие: браузеры позволяют использовать протокол file:// при работе с локальными файлами, тогда как модель безопасности Tauri блокирует это по умолчанию, чтобы предотвратить несанкционированный доступ к файловой системе пользователя.
Доступ к файлам и настройка путей
Ваш текущий подход с использованием /sample.pdf или абсолютных путей к файлам не будет работать в Tauri из‑за песочницы безопасности. Необходимо использовать протокол ресурсов Tauri и правильные методы доступа к файлам.
Текущие проблемы:
- Разрешение путей: Путь
/sample.pdfработает в браузере, потому что сервер Vite его обслуживает, но в Tauri такого веб‑сервера по умолчанию нет. - Абсолютные пути к файлам: Использование
file:///C:/Users/...блокируется политиками безопасности Tauri. - Конфигурация области: Ваш список разрешений
["$RESOURCE/*", "$APP/*"]корректен, но может потребовать дополнительной настройки.
Решение:
Нужно использовать функцию convertFileSrc из Tauri для преобразования путей к файлам в протокол asset:. Согласно обсуждениям Tauri, файлы следует загружать через протокол ресурсов.
import { convertFileSrc } from '@tauri-apps/api/tauri';
// Вместо "/sample.pdf" преобразуйте путь
const assetPath = convertFileSrc('/path/to/your/sample.pdf');
Проблемы конфигурации воркера PDF.js
PDF.js требует воркер‑файл для обработки PDF‑парсинга и рендеринга. В Tauri загрузка воркера часто завершается неудачей, потому что воркер не может получить доступ к тем же ресурсам, что и основной поток.
Текущая настройка воркера:
pdfjsLib.GlobalWorkerOptions.workerSrc =
new URL('pdfjs-dist/build/pdf.worker.entry', import.meta.url).href;
Этот подход работает в браузере, но может не сработать в Tauri, потому что воркер не может корректно разрешить URL в изолированной среде.
Решения для воркера:
- Использовать другой способ загрузки воркера:
import * as pdfjsLib from "pdfjs-dist/legacy/build/pdf";
import { convertFileSrc } from '@tauri-apps/api/tauri';
// Загрузить воркер из публичной директории
pdfjsLib.GlobalWorkerOptions.workerSrc =
convertFileSrc('/pdfjs-dist/build/pdf.worker.min.js');
- Встроить воркер, если доступ к файлам продолжает не работать.
CSP и требования к протоколам
По умолчанию Content Security Policy (CSP) в Tauri не разрешает протокол asset:, который необходим для доступа к файлам в PDF.js. Нужно настроить CSP в конфигурации Tauri, чтобы включить этот протокол.
Конфигурация CSP:
В файле tauri.conf.json добавьте протокол ресурсов в CSP:
"security": {
"csp": "default-src 'self'; img-src 'self' asset: data:; connect-src 'self' asset:; font-src 'self' asset:; script-src 'self' 'unsafe-inline' 'unsafe-eval' asset:; style-src 'self' 'unsafe-inline' asset:; worker-src 'self' asset: blob:;"
}
Согласно обсуждению Tauri, необходимо явно включить протокол asset: в CSP, чтобы разрешить доступ к файлам.
Пошаговые решения
Решение 1: Использование протокола ресурсов Tauri
- Обновите код загрузки PDF:
import * as pdfjsLib from "pdfjs-dist/legacy/build/pdf";
import { convertFileSrc } from '@tauri-apps/api/tauri';
// Настроить воркер
pdfjsLib.GlobalWorkerOptions.workerSrc = convertFileSrc('/pdfjs-dist/build/pdf.worker.min.js');
useEffect(() => {
let cancelled = false;
const loadPdf = async () => {
try {
// Преобразовать путь к файлу в протокол asset
const assetPath = convertFileSrc('/sample.pdf');
const pdf = await pdfjsLib.getDocument(assetPath).promise;
if (cancelled) return;
const page = await pdf.getPage(1);
const viewport = page.getViewport({ scale: 1.2 });
const canvas = canvasRef.current;
canvas.width = viewport.width;
canvas.height = viewport.height;
const ctx = canvas.getContext("2d");
await page.render({ canvasContext: ctx, viewport }).promise;
setLoading(false);
} catch (error) {
console.error("Error loading PDF:", error);
setLoading(false);
}
};
loadPdf();
return () => { cancelled = true };
}, []);
Решение 2: Использование API файловой системы Tauri
Если протокол ресурсов не работает, можно прочитать файл через API файловой системы Tauri и загрузить его как data URL:
import { readBinaryFile } from '@tauri-apps/api/fs';
import { convertFileSrc } from '@tauri-apps/api/tauri';
useEffect(() => {
let cancelled = false;
const loadPdf = async () => {
try {
// Прочитать файл через API Tauri
const fileData = await readBinaryFile('/sample.pdf');
// Преобразовать в Uint8Array
const pdfData = new Uint8Array(fileData);
// Загрузить PDF из данных
const pdf = await pdfjsLib.getDocument({ data: pdfData }).promise;
if (cancelled) return;
const page = await pdf.getPage(1);
const viewport = page.getViewport({ scale: 1.2 });
const canvas = canvasRef.current;
canvas.width = viewport.width;
canvas.height = viewport.height;
const ctx = canvas.getContext("2d");
await page.render({ canvasContext: ctx, viewport }).promise;
setLoading(false);
} catch (error) {
console.error("Error loading PDF:", error);
setLoading(false);
}
};
loadPdf();
return () => { cancelled = true };
}, []);
Решение 3: Конфигурация области файлов
Убедитесь, что в tauri.conf.json правильно настроена область доступа к файлам:
"allowlist": {
"fs": {
"readFile": true,
"scope": ["$RESOURCE/*", "$APP/*", "$APPCONFIG/*"]
},
"shell": {
"open": true
}
}
Альтернативные подходы
1. Использовать пакет react-pdf-viewer
Если PDF.js продолжает вызывать проблемы, рассмотрите использование специализированного React‑пакета для просмотра PDF, например react-pdf-viewer. Эти пакеты разработаны с учётом специфики Tauri.
npm install react-pdf-viewer
2. Использовать пакет react-pdf
Другой вариант – react-pdf, который имеет лучшую совместимость с Tauri:
npm install react-pdf
3. Служить PDF через локальный сервер
Если необходимо сохранить использование PDF.js, можно создать локальный сервер внутри приложения Tauri, который будет обслуживать PDF‑файлы, тем самым имитируя браузерную среду.
Отладка и проверка
Шаг 1: Включить подробный лог
Добавьте подробный лог, чтобы определить, где возникает проблема:
const loadPdf = async () => {
try {
console.log("Attempting to load PDF...");
const assetPath = convertFileSrc('/sample.pdf');
console.log("Asset path:", assetPath);
const loadingTask = pdfjsLib.getDocument(assetPath);
console.log("Loading task created");
pdf = await loadingTask.promise;
console.log("PDF loaded successfully");
// Продолжить с рендерингом...
} catch (error) {
console.error("Detailed error:", error);
console.error("Error stack:", error.stack);
}
};
Шаг 2: Проверить доступ к файлу
Убедитесь, что PDF‑файл находится в правильном месте и доступен:
import { exists } from '@tauri-apps/api/fs';
const checkFileExists = async () => {
const exists = await exists('/sample.pdf');
console.log("File exists:", exists);
};
Шаг 3: Тестировать с разными PDF
Попробуйте загрузить разные PDF‑файлы, чтобы изолировать, является ли проблема специфической для конкретного файла или общей.
Источники
- Документация Tauri по файловой системе
- Обсуждение Tauri – проблемы доступа к файлам
- Конфигурация CSP в Tauri
- Stack Overflow – Рендеринг PDF в Tauri
- Документация react-pdf-viewer
- Справочник API файловой системы Tauri
Заключение
Проблема рендеринга PDF в вашем приложении Tauri связана с ограничениями безопасности платформы, которые существенно отличаются от поведения браузера. Ключевые выводы:
- Используйте протокол ресурсов Tauri с
convertFileSrcвместо прямых путей к файлам. - Настройте CSP, чтобы включить протокол
asset:. - Рассмотрите альтернативные PDF‑просмотрщики, такие как react-pdf-viewer, если PDF.js продолжает вызывать проблемы.
- Включайте подробный лог, чтобы точно определить, где происходит сбой.
- Проверяйте доступ к файлам через API файловой системы Tauri перед попыткой рендеринга.
Самый надёжный способ – использовать API файловой системы Tauri для чтения PDF как бинарных данных и загружать их напрямую в PDF.js, обходя ограничения доступа к файлам. Это гарантирует, что ваш просмотрщик PDF будет работать одинаково в браузере и в среде Tauri.