Skip to content

ethanpv34/ez-web-worker

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

20 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ez-web-worker

A lightweight, type-safe React hook for seamlessly integrating Web Workers into your React applications. Run expensive computations off the main thread without managing worker files or dealing with complex worker setup.

Features

  • πŸš€ Simple API with a single hook
  • πŸ“¦ No separate worker files needed
  • πŸ’ͺ Full TypeScript support
  • πŸ”„ Automatic worker lifecycle management
  • ⚑ Support for transferable objects
  • βš›οΈ Optional React Suspense integration
  • πŸ›‘ Built-in cancellation support

Installation

npm install ez-web-worker

Basic Usage

import { useWorker } from 'ez-web-worker';

function MyComponent() {
  const { run, cancel, result, status, error } = useWorker((input: number) => {
    // This code runs in a Web Worker
    let total = 0;
    for (let i = 0; i < 1e8; i++) {
      total += (i * input) % 1234567;
    }
    return total;
  });

  return (
    <div>
      <button onClick={() => run(42)}>Start Calculation</button>
      <button onClick={cancel}>Cancel</button>
      {status === 'running' && <p>Calculating...</p>}
      {status === 'done' && <p>Result: {result}</p>}
      {status === 'error' && <p>Error: {error?.message}</p>}
    </div>
  );
}

Non-React Usage

You can also use the worker functionality without React using the createWorker function:

import { createWorker } from 'ez-web-worker';

// Create a worker instance
const worker = createWorker((input: number) => {
  // This code runs in a Web Worker
  let total = 0;
  for (let i = 0; i < 1e8; i++) {
    total += (i * input) % 1234567;
  }
  return total;
});

// Run the worker
worker.run(42)
  .then(result => console.log('Result:', result))
  .catch(error => console.error('Error:', error));

// Clean up when done
worker.terminate();

Usage with TanStack Query

import { createWorker } from 'ez-web-worker';
import { useQuery } from '@tanstack/react-query';

const computationWorker = createWorker((input: number) => {
  // Your heavy computation here
  return input * 2;
});

function MyComponent() {
  const { data, isLoading } = useQuery({
    queryKey: ['computation', 42],
    queryFn: () => computationWorker.run(42)
  });

  // Don't forget to clean up
  useEffect(() => {
    return () => computationWorker.terminate();
  }, []);

  return isLoading ? <div>Loading...</div> : <div>Result: {data}</div>;
}

API Reference

useWorker<TArgs, TResult>(workerFn: (args: TArgs) => TResult | Promise<TResult>, options?: WorkerOptions): UseWorkerReturn<TArgs, TResult>

Parameters

  • workerFn: The function to run in the Web Worker. Must be self-contained (no closure variables).
  • options: Optional configuration object
    • suspense?: boolean: Enable React Suspense integration
    • transferable?: boolean: Enable automatic transferable object handling

Returns

  • run: (args: TArgs) => void: Execute the worker function
  • cancel: () => void: Cancel the current execution
  • result: TResult | null: The result of the computation
  • status: 'idle' | 'running' | 'done' | 'error': Current worker status
  • error: Error | null: Error object if the computation failed

Advanced Usage

With Transferable Objects

function ProcessImageData() {
  const { run, result } = useWorker(
    (imageData: ArrayBuffer) => {
      // Process image data in worker
      return processedData;
    },
    { transferable: true }
  );

  const handleImageUpload = (e) => {
    const file = e.target.files[0];
    const reader = new FileReader();
    reader.onload = () => run(reader.result as ArrayBuffer);
    reader.readAsArrayBuffer(file);
  };

  return <input type="file" onChange={handleImageUpload} />;
}

With Suspense

function App() {
  return (
    <Suspense fallback={<LoadingSpinner />}>
      <ExpensiveComponent />
    </Suspense>
  );
}

function ExpensiveComponent() {
  const { run, result } = useWorker(
    expensiveFunction,
    { suspense: true }
  );
  
  // Component will suspend while worker is running
  return <div>{result}</div>;
}

Limitations

  • Worker functions must be self-contained and cannot reference variables from their outer scope
  • DOM APIs are not available inside worker functions
  • Limited SSR support (workers only run in browser environment)

License

MIT Β© ethanpv34