feat: initialize Convert UI - browser-based file conversion app
- Add Next.js 16 with Turbopack and React 19 - Add Tailwind CSS 4 with OKLCH color system - Implement FFmpeg.wasm for video/audio conversion - Implement ImageMagick WASM for image conversion - Add file upload with drag-and-drop - Add format selector with fuzzy search - Add conversion preview and download - Add conversion history with localStorage - Add dark/light theme support - Support 22+ file formats across video, audio, and images 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
143
lib/wasm/wasmLoader.ts
Normal file
143
lib/wasm/wasmLoader.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
import type { FFmpeg } from '@ffmpeg/ffmpeg';
|
||||
import type { ConverterEngine, WASMModuleState } from '@/types/conversion';
|
||||
|
||||
/**
|
||||
* WASM module loading state
|
||||
*/
|
||||
const moduleState: WASMModuleState = {
|
||||
ffmpeg: false,
|
||||
imagemagick: false,
|
||||
pandoc: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* Cached WASM instances
|
||||
*/
|
||||
let ffmpegInstance: FFmpeg | null = null;
|
||||
let imagemagickInstance: any = null;
|
||||
let pandocInstance: any = null;
|
||||
|
||||
/**
|
||||
* Load FFmpeg WASM module
|
||||
*/
|
||||
export async function loadFFmpeg(): Promise<FFmpeg> {
|
||||
if (ffmpegInstance && moduleState.ffmpeg) {
|
||||
return ffmpegInstance;
|
||||
}
|
||||
|
||||
try {
|
||||
const { FFmpeg } = await import('@ffmpeg/ffmpeg');
|
||||
const { toBlobURL } = await import('@ffmpeg/util');
|
||||
|
||||
ffmpegInstance = new FFmpeg();
|
||||
|
||||
// Load core and dependencies
|
||||
const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/umd';
|
||||
|
||||
ffmpegInstance.on('log', ({ message }) => {
|
||||
console.log('[FFmpeg]', message);
|
||||
});
|
||||
|
||||
await ffmpegInstance.load({
|
||||
coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),
|
||||
wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),
|
||||
});
|
||||
|
||||
moduleState.ffmpeg = true;
|
||||
console.log('FFmpeg loaded successfully');
|
||||
|
||||
return ffmpegInstance;
|
||||
} catch (error) {
|
||||
console.error('Failed to load FFmpeg:', 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 {
|
||||
const ImageMagick = await import('@imagemagick/magick-wasm');
|
||||
|
||||
imagemagickInstance = ImageMagick;
|
||||
moduleState.imagemagick = true;
|
||||
console.log('ImageMagick loaded successfully');
|
||||
|
||||
return imagemagickInstance;
|
||||
} catch (error) {
|
||||
console.error('Failed to load ImageMagick:', error);
|
||||
throw new Error('Failed to load ImageMagick WASM module');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Pandoc WASM module (placeholder for future implementation)
|
||||
*/
|
||||
export async function loadPandoc(): Promise<any> {
|
||||
if (pandocInstance && moduleState.pandoc) {
|
||||
return pandocInstance;
|
||||
}
|
||||
|
||||
// TODO: Implement Pandoc WASM loading when available
|
||||
// For now, throw an error
|
||||
throw new Error('Pandoc WASM module is not yet implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
case 'pandoc':
|
||||
return loadPandoc();
|
||||
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;
|
||||
}
|
||||
|
||||
if (pandocInstance) {
|
||||
pandocInstance = null;
|
||||
moduleState.pandoc = false;
|
||||
}
|
||||
|
||||
console.log('All WASM modules unloaded');
|
||||
}
|
||||
Reference in New Issue
Block a user