feat: Add VitePress docs, EPUB to PDF tool, Phosphor icons, and licensing updates
- Set up VitePress documentation site (docs:dev, docs:build, docs:preview) - Added Getting Started, Tools Reference, Contributing, and Commercial License pages - Created self-hosting guides for Docker, Vercel, Netlify, Cloudflare, AWS, Hostinger, Nginx, Apache - Updated README with documentation link, sponsors section, and docs contribution guide - Added EPUB to PDF converter using LibreOffice WASM - Migrated to Phosphor Icons for consistent iconography - Added donation ribbon banner on landing page - Removed 'Like My Work?' section (replaced by ribbon) - Updated licensing.html with delivery model, AGPL notice, invoicing, and no-refund policy - Added Commercial License documentation page - Updated translations table (Chinese added, marked non-English as In Progress) - Added sponsors.yml workflow for auto-generating sponsor avatars
This commit is contained in:
129
src/js/utils/wasm-preloader.ts
Normal file
129
src/js/utils/wasm-preloader.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { getLibreOfficeConverter } from './libreoffice-loader.js';
|
||||
import { PyMuPDF } from '@bentopdf/pymupdf-wasm';
|
||||
import loadGsWASM from '@bentopdf/gs-wasm';
|
||||
import { setCachedGsModule } from './ghostscript-loader.js';
|
||||
|
||||
export enum PreloadStatus {
|
||||
IDLE = 'idle',
|
||||
LOADING = 'loading',
|
||||
READY = 'ready',
|
||||
ERROR = 'error'
|
||||
}
|
||||
|
||||
interface PreloadState {
|
||||
libreoffice: PreloadStatus;
|
||||
pymupdf: PreloadStatus;
|
||||
ghostscript: PreloadStatus;
|
||||
}
|
||||
|
||||
const preloadState: PreloadState = {
|
||||
libreoffice: PreloadStatus.IDLE,
|
||||
pymupdf: PreloadStatus.IDLE,
|
||||
ghostscript: PreloadStatus.IDLE
|
||||
};
|
||||
|
||||
let pymupdfInstance: PyMuPDF | null = null;
|
||||
|
||||
export function getPreloadStatus(): Readonly<PreloadState> {
|
||||
return { ...preloadState };
|
||||
}
|
||||
|
||||
export function getPymupdfInstance(): PyMuPDF | null {
|
||||
return pymupdfInstance;
|
||||
}
|
||||
|
||||
async function preloadLibreOffice(): Promise<void> {
|
||||
if (preloadState.libreoffice !== PreloadStatus.IDLE) return;
|
||||
|
||||
preloadState.libreoffice = PreloadStatus.LOADING;
|
||||
console.log('[Preloader] Starting LibreOffice WASM preload...');
|
||||
|
||||
try {
|
||||
const converter = getLibreOfficeConverter();
|
||||
await converter.initialize();
|
||||
preloadState.libreoffice = PreloadStatus.READY;
|
||||
console.log('[Preloader] LibreOffice WASM ready');
|
||||
} catch (e) {
|
||||
preloadState.libreoffice = PreloadStatus.ERROR;
|
||||
console.warn('[Preloader] LibreOffice preload failed:', e);
|
||||
}
|
||||
}
|
||||
|
||||
async function preloadPyMuPDF(): Promise<void> {
|
||||
if (preloadState.pymupdf !== PreloadStatus.IDLE) return;
|
||||
|
||||
preloadState.pymupdf = PreloadStatus.LOADING;
|
||||
console.log('[Preloader] Starting PyMuPDF preload...');
|
||||
|
||||
try {
|
||||
pymupdfInstance = new PyMuPDF(import.meta.env.BASE_URL + 'pymupdf-wasm/');
|
||||
await pymupdfInstance.load();
|
||||
preloadState.pymupdf = PreloadStatus.READY;
|
||||
console.log('[Preloader] PyMuPDF ready');
|
||||
} catch (e) {
|
||||
preloadState.pymupdf = PreloadStatus.ERROR;
|
||||
console.warn('[Preloader] PyMuPDF preload failed:', e);
|
||||
}
|
||||
}
|
||||
|
||||
async function preloadGhostscript(): Promise<void> {
|
||||
if (preloadState.ghostscript !== PreloadStatus.IDLE) return;
|
||||
|
||||
preloadState.ghostscript = PreloadStatus.LOADING;
|
||||
console.log('[Preloader] Starting Ghostscript WASM preload...');
|
||||
|
||||
try {
|
||||
const gsModule = await loadGsWASM({
|
||||
locateFile: (path: string) => {
|
||||
if (path.endsWith('.wasm')) {
|
||||
return import.meta.env.BASE_URL + 'ghostscript-wasm/gs.wasm';
|
||||
}
|
||||
return path;
|
||||
},
|
||||
print: () => { },
|
||||
printErr: () => { },
|
||||
});
|
||||
setCachedGsModule(gsModule as any);
|
||||
preloadState.ghostscript = PreloadStatus.READY;
|
||||
console.log('[Preloader] Ghostscript WASM ready');
|
||||
} catch (e) {
|
||||
preloadState.ghostscript = PreloadStatus.ERROR;
|
||||
console.warn('[Preloader] Ghostscript preload failed:', e);
|
||||
}
|
||||
}
|
||||
|
||||
function scheduleIdleTask(task: () => Promise<void>): void {
|
||||
if ('requestIdleCallback' in window) {
|
||||
requestIdleCallback(() => task(), { timeout: 5000 });
|
||||
} else {
|
||||
setTimeout(() => task(), 1000);
|
||||
}
|
||||
}
|
||||
|
||||
export function startBackgroundPreload(): void {
|
||||
console.log('[Preloader] Scheduling background WASM preloads...');
|
||||
|
||||
const libreOfficePages = [
|
||||
'word-to-pdf', 'excel-to-pdf', 'ppt-to-pdf', 'powerpoint-to-pdf',
|
||||
'docx-to-pdf', 'xlsx-to-pdf', 'pptx-to-pdf', 'csv-to-pdf',
|
||||
'rtf-to-pdf', 'odt-to-pdf', 'ods-to-pdf', 'odp-to-pdf'
|
||||
];
|
||||
|
||||
const currentPath = window.location.pathname;
|
||||
const isLibreOfficePage = libreOfficePages.some(page => currentPath.includes(page));
|
||||
|
||||
if (isLibreOfficePage) {
|
||||
console.log('[Preloader] Skipping preloads on LibreOffice page to save memory');
|
||||
return;
|
||||
}
|
||||
|
||||
scheduleIdleTask(async () => {
|
||||
console.log('[Preloader] Starting sequential WASM preloads...');
|
||||
|
||||
await preloadPyMuPDF();
|
||||
await preloadGhostscript();
|
||||
|
||||
console.log('[Preloader] Sequential preloads complete (LibreOffice skipped - loaded on demand)');
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user