# Next.js Integration Guide

This guide explains how to integrate `@fe-daily/libimagequant-wasm` with Next.js applications.

## Problem

Next.js uses static analysis and bundling that doesn't work well with dynamic WASM imports using `import.meta.url`. You may encounter errors like:

```
Error: Cannot find module '/_next/static/media/libimagequant_wasm.a36650a2.js'
```

## Solutions

### Option 1: Pre-load WASM Module (Recommended)

Import the WASM module directly and pass it to the constructor:

```typescript
import LibImageQuant from '@fe-daily/libimagequant-wasm';
import wasmModule from '@fe-daily/libimagequant-wasm/wasm/libimagequant_wasm.js';

// Create quantizer with pre-loaded WASM module
const quantizer = new LibImageQuant({ wasmModule });

// Use normally
const result = await quantizer.quantizeImageData(imageData, {
  maxColors: 64,
  speed: 3
});
```

### Option 2: Use in Web Worker

Create a Web Worker to isolate the WASM loading:

```typescript
// worker.ts
import LibImageQuant from '@fe-daily/libimagequant-wasm';

let quantizer: LibImageQuant;

self.onmessage = async function(e) {
  const { type, data } = e.data;
  
  try {
    if (type === 'init') {
      quantizer = new LibImageQuant();
      self.postMessage({ type: 'ready' });
      return;
    }
    
    if (type === 'quantize') {
      const result = await quantizer.quantizeImageData(data.imageData, data.options);
      self.postMessage({ type: 'result', result });
    }
  } catch (error) {
    self.postMessage({ 
      type: 'error', 
      error: error instanceof Error ? error.message : String(error) 
    });
  }
};

// main component
import { useCallback, useEffect, useRef } from 'react';

export function useImageQuantizer() {
  const workerRef = useRef<Worker>();
  
  useEffect(() => {
    workerRef.current = new Worker(new URL('./worker.ts', import.meta.url));
    return () => workerRef.current?.terminate();
  }, []);
  
  const quantize = useCallback((imageData: ImageData, options: any) => {
    return new Promise((resolve, reject) => {
      if (!workerRef.current) {
        reject(new Error('Worker not initialized'));
        return;
      }
      
      const handleMessage = (e: MessageEvent) => {
        const { type, result, error } = e.data;
        if (type === 'result') {
          resolve(result);
        } else if (type === 'error') {
          reject(new Error(error));
        }
        workerRef.current?.removeEventListener('message', handleMessage);
      };
      
      workerRef.current.addEventListener('message', handleMessage);
      workerRef.current.postMessage({ type: 'quantize', data: { imageData, options } });
    });
  }, []);
  
  return { quantize };
}
```

### Option 3: Dynamic Import with Error Handling

Use dynamic imports with proper error handling:

```typescript
import { useCallback, useState } from 'react';

export function useImageQuantizer() {
  const [quantizer, setQuantizer] = useState<any>(null);
  const [loading, setLoading] = useState(false);
  
  const initialize = useCallback(async () => {
    if (quantizer) return quantizer;
    
    setLoading(true);
    try {
      const { default: LibImageQuant } = await import('@fe-daily/libimagequant-wasm');
      const wasmModule = await import('@fe-daily/libimagequant-wasm/wasm/libimagequant_wasm.js');
      
      const instance = new LibImageQuant({ wasmModule });
      setQuantizer(instance);
      return instance;
    } catch (error) {
      console.error('Failed to initialize quantizer:', error);
      throw error;
    } finally {
      setLoading(false);
    }
  }, [quantizer]);
  
  const quantize = useCallback(async (imageData: ImageData, options: any) => {
    const instance = await initialize();
    return instance.quantizeImageData(imageData, options);
  }, [initialize]);
  
  return { quantize, loading };
}
```

## Next.js Configuration

You may need to configure Next.js to handle WASM files properly:

```javascript
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config, { isServer }) => {
    // Handle WASM files
    config.experiments = {
      ...config.experiments,
      asyncWebAssembly: true,
    };
    
    // Handle .wasm files
    config.module.rules.push({
      test: /\.wasm$/,
      type: 'webassembly/async',
    });
    
    // Fallback for Node.js modules in client-side
    if (!isServer) {
      config.resolve.fallback = {
        ...config.resolve.fallback,
        fs: false,
        path: false,
        crypto: false,
      };
    }
    
    return config;
  },
};

module.exports = nextConfig;
```

## TypeScript Configuration

Update your `tsconfig.json` to handle WASM imports:

```json
{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "moduleResolution": "bundler"
  }
}
```

## Example Component

```typescript
'use client';

import { useCallback, useState } from 'react';
import LibImageQuant from '@fe-daily/libimagequant-wasm';
import wasmModule from '@fe-daily/libimagequant-wasm/wasm/libimagequant_wasm.js';

export default function ImageQuantizer() {
  const [result, setResult] = useState<any>(null);
  const [loading, setLoading] = useState(false);
  
  const handleFileUpload = useCallback(async (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (!file) return;
    
    setLoading(true);
    try {
      // Create canvas to get ImageData
      const img = new Image();
      img.onload = async () => {
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d')!;
        canvas.width = img.width;
        canvas.height = img.height;
        ctx.drawImage(img, 0, 0);
        
        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
        
        // Quantize with pre-loaded WASM module
        const quantizer = new LibImageQuant({ wasmModule });
        const quantResult = await quantizer.quantizeImageData(imageData, {
          maxColors: 32,
          speed: 3
        });
        
        setResult(quantResult);
      };
      
      img.src = URL.createObjectURL(file);
    } catch (error) {
      console.error('Quantization failed:', error);
    } finally {
      setLoading(false);
    }
  }, []);
  
  return (
    <div>
      <input type="file" accept="image/*" onChange={handleFileUpload} />
      {loading && <p>Processing...</p>}
      {result && (
        <div>
          <p>Quantized to {result.paletteLength} colors</p>
          <p>Quality: {Math.round(result.quality * 100)}%</p>
        </div>
      )}
    </div>
  );
}
```

## Troubleshooting

### Common Issues

1. **Module not found errors**: Ensure you're importing the WASM module correctly
2. **Build failures**: Check your Next.js configuration supports WASM
3. **Runtime errors**: Make sure you're running in a browser environment (use 'use client' directive)

### Tips

- Always use the pre-loaded WASM module approach for the most reliable Next.js integration
- Test your integration in both development and production builds
- Consider using Web Workers for heavy processing to avoid blocking the UI
- Make sure WASM files are properly served with correct MIME types in production
