Files
kit-ui/lib/media/wasm/wasmLoader.ts
Sebastian Krüger 6d4426037c Fix FFmpeg import: use direct import like ImageMagick
Import FFmpeg at module level instead of dynamic import. The build now
compiles cleanly without Turbopack bundler warnings.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-02-25 20:29:55 +01:00

141 lines
3.6 KiB
TypeScript

import type { ConverterEngine, WASMModuleState } from '@/types/media';
import type { FFmpeg as FFmpegType } from '@ffmpeg/ffmpeg';
import { FFmpeg } from '@ffmpeg/ffmpeg';
import { initializeImageMagick } from '@imagemagick/magick-wasm';
/**
* WASM module loading state
*/
const moduleState: WASMModuleState = {
ffmpeg: false,
imagemagick: false,
};
/**
* Cached WASM instances
*/
let ffmpegInstance: FFmpegType | null = null;
let imagemagickInstance: any = null;
/**
* Load FFmpeg WASM module
*/
export async function loadFFmpeg(): Promise<FFmpegType> {
if (ffmpegInstance && moduleState.ffmpeg) {
return ffmpegInstance;
}
try {
if (!FFmpeg) {
throw new Error('FFmpeg class not available');
}
ffmpegInstance = new FFmpeg();
if (!ffmpegInstance) {
throw new Error('Failed to create FFmpeg instance');
}
ffmpegInstance.on('log', ({ message }: { message: string }) => {
console.log('[FFmpeg]', message);
});
// Files are guaranteed to exist in /wasm/ by the postinstall script
const coreURL = '/wasm/ffmpeg-core.js';
const wasmURL = '/wasm/ffmpeg-core.wasm';
await ffmpegInstance.load({ coreURL, wasmURL });
moduleState.ffmpeg = true;
console.log('[FFmpeg] Loaded successfully from local assets');
return ffmpegInstance;
} catch (error) {
console.error('[FFmpeg] Failed to load:', error);
throw new Error('Failed to load FFmpeg WASM module');
}
}
/**
* Load ImageMagick WASM module
*/
export async function loadImageMagick(): Promise<any> {
if (imagemagickInstance && moduleState.imagemagick) {
return imagemagickInstance;
}
try {
// File is guaranteed to exist in /wasm/ by the postinstall script
const wasmUrl = '/wasm/magick.wasm';
console.log('[ImageMagick] Loading local WASM:', wasmUrl);
const response = await fetch(wasmUrl);
if (!response.ok) {
throw new Error(`Failed to fetch WASM file: ${response.status} ${response.statusText}`);
}
const arrayBuffer = await response.arrayBuffer();
console.log('[ImageMagick] WASM file size:', arrayBuffer.byteLength, 'bytes');
await initializeImageMagick(arrayBuffer);
// Store the module for later use
imagemagickInstance = { initialized: true };
moduleState.imagemagick = true;
console.log('[ImageMagick] Loaded and initialized successfully from local asset');
return imagemagickInstance;
} catch (error) {
console.error('[ImageMagick] Failed to load:', error);
throw new Error(`Failed to load ImageMagick WASM module: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Get loaded module state
*/
export function getModuleState(): WASMModuleState {
return { ...moduleState };
}
/**
* Check if a specific module is loaded
*/
export function isModuleLoaded(engine: ConverterEngine): boolean {
return moduleState[engine];
}
/**
* Load appropriate WASM module for converter engine
*/
export async function loadModule(engine: ConverterEngine): Promise<any> {
switch (engine) {
case 'ffmpeg':
return loadFFmpeg();
case 'imagemagick':
return loadImageMagick();
default:
throw new Error(`Unknown converter engine: ${engine}`);
}
}
/**
* Unload all WASM modules and free memory
*/
export function unloadAll(): void {
if (ffmpegInstance) {
// FFmpeg doesn't have an explicit unload method
// Just null the instance
ffmpegInstance = null;
moduleState.ffmpeg = false;
}
if (imagemagickInstance) {
imagemagickInstance = null;
moduleState.imagemagick = false;
}
console.log('All WASM modules unloaded');
}