Skip to content

feat: Adding workers automatically as Svelte compiles #14490

@shahul01

Description

@shahul01

Describe the problem

Svelte should use workers as more and more system have multi core.
A developer may add worker to use multi threading manually but it could be complicated and its better to move this process to compilation as more and more web apps / web sites will use workers.

Describe the proposed solution

As Svelte compiles, it can add worker automatically to some / all function via wrapper .

opt out -
if in beta, or facing error or just wanting to disable workers, Svelte can have an option in a config to disable(and enable) auto worker mode.

// overview
// general
button → function

// svelte + auto worker mode via wrapper
button → worker → function

Example of how different functions can be used via worker wrapper

// src/lib/workers/workerWrapper.ts
export class WorkerWrapper {
  private worker: Worker;
  private taskCallbacks: Map<string, (data: any) => void>;

  constructor() {
    this.worker = new Worker(
      new URL('./worker.ts', import.meta.url),
      { type: 'module' }
    );
    this.taskCallbacks = new Map();

    this.worker.onmessage = (event) => {
      const { type, data, error } = event.data;
      const callback = this.taskCallbacks.get(type);
      
      if (callback) {
        callback(error || data);
        this.taskCallbacks.delete(type);
      }
    };
  }

  processChartData(data: any[]): Promise<any> {
    return this.postTask('PROCESS_CHART_DATA', data, 'CHART_DATA_PROCESSED');
  }

  validateForm(formData: Record<string, any>): Promise<any> {
    return this.postTask('VALIDATE_FORM', formData, 'FORM_VALIDATED');
  }

  checkPassword(password: string): Promise<any> {
    return this.postTask('CHECK_PASSWORD', password, 'PASSWORD_CHECKED');
  }

  search(query: string, items: any[]): Promise<any> {
    return this.postTask('SEARCH', { query, items }, 'SEARCH_COMPLETED');
  }

  private postTask(type: string, payload: any, responseType: string): Promise<any> {
    return new Promise((resolve, reject) => {
      this.taskCallbacks.set(responseType, (result) => {
        if (result.error) {
          reject(result.error);
        } else {
          resolve(result);
        }
      });

      this.worker.postMessage({ type, payload });
    });
  }

  terminate() {
    this.worker.terminate();
    this.taskCallbacks.clear();
  }
}
// src/lib/workers/worker.ts
type WorkerTask = {
  type: 'PROCESS_CHART_DATA' | 'VALIDATE_FORM' | 'CHECK_PASSWORD' | 'SEARCH';
  payload: any;
};

type WorkerResponse = {
  type: string;
  data: any;
  error?: string;
};

// Chart data processing
function processChartData(data: any[]) {
  try {
    // Example processing
    const processed = data.map(item => ({
      ...item,
      value: Number(item.value),
      timestamp: new Date(item.timestamp).getTime()
    })).sort((a, b) => a.timestamp - b.timestamp);

    return { success: true, data: processed };
  } catch (error) {
    return { success: false, error: (error as Error).message };
  }
}

// Form validation
function validateForm(formData: Record<string, any>) {
  const errors: Record<string, string> = {};
  
  Object.entries(formData).forEach(([field, value]) => {
    if (!value) {
      errors[field] = 'Field is required';
    }
    // Add more validation rules as needed
  });

  return { success: Object.keys(errors).length === 0, errors };
}

// Password strength checker
function checkPasswordStrength(password: string) {
  const checks = {
    length: password.length >= 8,
    hasUpper: /[A-Z]/.test(password),
    hasLower: /[a-z]/.test(password),
    hasNumber: /\d/.test(password),
    hasSpecial: /[!@#$%^&*(),.?":{}|<>]/.test(password),
  };

  const strength = Object.values(checks).filter(Boolean).length;
  let result = 'weak';
  if (strength >= 4) result = 'strong';
  else if (strength >= 3) result = 'medium';

  return { 
    strength: result, 
    checks,
    score: (strength / 5) * 100 
  };
}

// Instant search
function performSearch(query: string, items: any[]) {
  const searchTerm = query.toLowerCase();
  return items.filter(item => 
    Object.values(item).some(value => 
      String(value).toLowerCase().includes(searchTerm)
    )
  );
}

// Main message handler
self.onmessage = async (event: MessageEvent<WorkerTask>) => {
  const { type, payload } = event.data;
  let response: WorkerResponse;

  try {
    switch (type) {
      case 'PROCESS_CHART_DATA':
        response = {
          type: 'CHART_DATA_PROCESSED',
          data: processChartData(payload)
        };
        break;

      case 'VALIDATE_FORM':
        response = {
          type: 'FORM_VALIDATED',
          data: validateForm(payload)
        };
        break;

      case 'CHECK_PASSWORD':
        response = {
          type: 'PASSWORD_CHECKED',
          data: checkPasswordStrength(payload)
        };
        break;

      case 'SEARCH':
        response = {
          type: 'SEARCH_COMPLETED',
          data: performSearch(payload.query, payload.items)
        };
        break;

      default:
        throw new Error(`Unknown task type: ${type}`);
    }

    self.postMessage(response);
  } catch (error) {
    self.postMessage({
      type: 'ERROR',
      error: (error as Error).message,
      data: null
    });
  }
};

export {};

Importance

nice to have

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions