or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

configuration.mdcore-element.mdevents.mdindex.mdplugin-development.mdwasm-init.md
tile.json

wasm-init.mddocs/

WebAssembly Initialization

Manual WebAssembly initialization for advanced use cases and custom deployments.

Capabilities

Manual Initialization

Initialize the perspective-viewer WebAssembly module manually when automatic initialization is not suitable.

/**
 * Initialize the perspective-viewer WebAssembly client
 * @param wasm_binary - WebAssembly binary data in various formats
 */
function init_client(
  wasm_binary: Promise<Response | ArrayBuffer | Uint8Array> 
    | Response 
    | ArrayBuffer 
    | Uint8Array
): Promise<void>;

/**
 * Default export providing init_client function
 */
export default { init_client };

Initialization Examples

Basic Manual Initialization

import { init_client } from "@finos/perspective-viewer";

// Initialize with WebAssembly binary URL
const wasmResponse = fetch("/path/to/perspective-viewer.wasm");
await init_client(wasmResponse);

// Now the custom elements are available
const viewer = document.createElement("perspective-viewer");

Initialize with ArrayBuffer

import { init_client } from "@finos/perspective-viewer";

// Load WASM binary as ArrayBuffer
const wasmBinary = await fetch("/path/to/perspective-viewer.wasm")
  .then(response => response.arrayBuffer());

await init_client(wasmBinary);

// Custom elements are now registered
const viewer = document.createElement("perspective-viewer");

Initialize with Uint8Array

import { init_client } from "@finos/perspective-viewer";

// Example: Load from base64 or other encoded format
const base64Wasm = "AGFzbQEAAAABhQEYY..."; // Base64 encoded WASM
const wasmBytes = Uint8Array.from(atob(base64Wasm), c => c.charCodeAt(0));

await init_client(wasmBytes);

Using Default Export

import perspectiveViewer from "@finos/perspective-viewer";

// Alternative import pattern using default export
const wasmResponse = fetch("/path/to/perspective-viewer.wasm");
await perspectiveViewer.init_client(wasmResponse);

// Custom elements are now registered
const viewer = document.createElement("perspective-viewer");

Advanced Initialization Patterns

Conditional Initialization

import { init_client } from "@finos/perspective-viewer";

class PerspectiveManager {
  private initialized = false;
  
  async ensureInitialized() {
    if (!this.initialized) {
      await this.initializePerspective();
      this.initialized = true;
    }
  }
  
  private async initializePerspective() {
    try {
      // Try CDN first
      const cdnWasm = fetch("https://cdn.jsdelivr.net/npm/@finos/perspective-viewer/dist/cdn/perspective-viewer.wasm");
      await init_client(cdnWasm);
    } catch (error) {
      console.warn("CDN initialization failed, trying local:", error);
      
      // Fallback to local WASM
      const localWasm = fetch("/assets/perspective-viewer.wasm");
      await init_client(localWasm);
    }
  }
  
  async createViewer(): Promise<HTMLPerspectiveViewerElement> {
    await this.ensureInitialized();
    return document.createElement("perspective-viewer");
  }
}

// Usage
const manager = new PerspectiveManager();
const viewer = await manager.createViewer();

Lazy Loading with Error Handling

import { init_client } from "@finos/perspective-viewer";

class LazyPerspectiveLoader {
  private initPromise: Promise<void> | null = null;
  
  async loadPerspective(): Promise<void> {
    if (!this.initPromise) {
      this.initPromise = this.performInitialization();
    }
    return this.initPromise;
  }
  
  private async performInitialization(): Promise<void> {
    const startTime = performance.now();
    
    try {
      // Show loading indicator
      this.showLoadingIndicator();
      
      // Load WASM with timeout
      const wasmPromise = fetch("/wasm/perspective-viewer.wasm");
      const timeoutPromise = new Promise<never>((_, reject) => {
        setTimeout(() => reject(new Error("WASM load timeout")), 10000);
      });
      
      const wasmResponse = await Promise.race([wasmPromise, timeoutPromise]);
      
      if (!wasmResponse.ok) {
        throw new Error(`Failed to load WASM: ${wasmResponse.status}`);
      }
      
      await init_client(wasmResponse);
      
      const loadTime = performance.now() - startTime;
      console.log(`Perspective initialized in ${loadTime.toFixed(2)}ms`);
      
    } catch (error) {
      console.error("Failed to initialize Perspective:", error);
      this.showErrorState(error);
      throw error;
    } finally {
      this.hideLoadingIndicator();
    }
  }
  
  private showLoadingIndicator() {
    const indicator = document.createElement("div");
    indicator.id = "perspective-loading";
    indicator.textContent = "Loading Perspective Viewer...";
    indicator.style.cssText = `
      position: fixed;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      padding: 20px;
      background: rgba(0,0,0,0.8);
      color: white;
      border-radius: 5px;
      z-index: 10000;
    `;
    document.body.appendChild(indicator);
  }
  
  private hideLoadingIndicator() {
    const indicator = document.getElementById("perspective-loading");
    if (indicator) {
      indicator.remove();
    }
  }
  
  private showErrorState(error: Error) {
    const errorDiv = document.createElement("div");
    errorDiv.textContent = `Failed to load Perspective: ${error.message}`;
    errorDiv.style.cssText = `
      color: red;
      padding: 10px;
      border: 1px solid red;
      background: #ffe6e6;
      margin: 10px;
    `;
    document.body.appendChild(errorDiv);
    
    // Provide retry button
    const retryBtn = document.createElement("button");
    retryBtn.textContent = "Retry";
    retryBtn.onclick = () => {
      errorDiv.remove();
      this.initPromise = null; // Reset for retry
      this.loadPerspective();
    };
    errorDiv.appendChild(retryBtn);
  }
}

// Usage
const loader = new LazyPerspectiveLoader();

document.getElementById("load-perspective")?.addEventListener("click", async () => {
  try {
    await loader.loadPerspective();
    
    // Create viewer after successful initialization
    const viewer = document.createElement("perspective-viewer");
    document.body.appendChild(viewer);
  } catch (error) {
    console.error("Could not load Perspective:", error);
  }
});

Progressive Web App (PWA) Integration

import { init_client } from "@finos/perspective-viewer";

class PWAPerspectiveLoader {
  private readonly CACHE_NAME = "perspective-wasm-v1";
  private readonly WASM_URL = "/wasm/perspective-viewer.wasm";
  
  async initializeWithCaching(): Promise<void> {
    try {
      // Try to get from cache first
      const cachedWasm = await this.getCachedWasm();
      if (cachedWasm) {
        console.log("Using cached WASM");
        await init_client(cachedWasm);
        return;
      }
      
      // Download and cache
      console.log("Downloading WASM");
      const wasmResponse = await fetch(this.WASM_URL);
      
      if (!wasmResponse.ok) {
        throw new Error(`HTTP ${wasmResponse.status}: ${wasmResponse.statusText}`);
      }
      
      // Cache for future use
      await this.cacheWasm(wasmResponse.clone());
      
      // Initialize
      await init_client(wasmResponse);
      
    } catch (error) {
      console.error("WASM initialization failed:", error);
      throw error;
    }
  }
  
  private async getCachedWasm(): Promise<Response | null> {
    if (!("caches" in window)) {
      return null;
    }
    
    const cache = await caches.open(this.CACHE_NAME);
    return await cache.match(this.WASM_URL);
  }
  
  private async cacheWasm(response: Response): Promise<void> {
    if (!("caches" in window)) {
      return;
    }
    
    const cache = await caches.open(this.CACHE_NAME);
    await cache.put(this.WASM_URL, response);
  }
  
  async clearCache(): Promise<void> {
    if ("caches" in window) {
      await caches.delete(this.CACHE_NAME);
    }
  }
}

// Usage in PWA
const pwaLoader = new PWAPerspectiveLoader();

// Initialize on app startup
pwaLoader.initializeWithCaching()
  .then(() => {
    console.log("Perspective ready");
    // App is ready to create viewers
  })
  .catch(error => {
    console.error("Perspective initialization failed:", error);
    // Show fallback UI
  });

Worker Thread Initialization

// main.ts
import { init_client } from "@finos/perspective-viewer";

class WorkerPerspectiveLoader {
  async initializeWithWorker(): Promise<void> {
    return new Promise((resolve, reject) => {
      const worker = new Worker("/js/wasm-loader-worker.js");
      
      worker.postMessage({ action: "loadWasm", url: "/wasm/perspective-viewer.wasm" });
      
      worker.onmessage = async (event) => {
        const { action, data, error } = event.data;
        
        if (action === "wasmLoaded") {
          try {
            await init_client(data);
            resolve();
          } catch (err) {
            reject(err);
          } finally {
            worker.terminate();
          }
        } else if (action === "error") {
          reject(new Error(error));
          worker.terminate();
        }
      };
      
      worker.onerror = (error) => {
        reject(error);
        worker.terminate();
      };
      
      // Timeout after 30 seconds
      setTimeout(() => {
        reject(new Error("Worker timeout"));
        worker.terminate();
      }, 30000);
    });
  }
}
// wasm-loader-worker.js (Web Worker)
self.onmessage = async function(event) {
  const { action, url } = event.data;
  
  if (action === "loadWasm") {
    try {
      const response = await fetch(url);
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }
      
      const arrayBuffer = await response.arrayBuffer();
      
      self.postMessage({
        action: "wasmLoaded",
        data: arrayBuffer
      });
    } catch (error) {
      self.postMessage({
        action: "error",
        error: error.message
      });
    }
  }
};

Initialization Options

Bundle Size Optimization

// Use specific entry points to reduce bundle size
import { init_client } from "@finos/perspective-viewer/dist/esm/bootstrap";

// Initialize without side effects
await init_client(wasmBinary);

// Only then import the components you need
const { PerspectiveViewerElement } = await import("@finos/perspective-viewer/dist/esm/perspective-viewer");

Development vs Production

import { init_client } from "@finos/perspective-viewer";

async function initializePerspective() {
  const isDevelopment = process.env.NODE_ENV === "development";
  
  if (isDevelopment) {
    // Development: Use local file with source maps
    const wasmResponse = fetch("/dev/perspective-viewer.wasm");
    await init_client(wasmResponse);
  } else {
    // Production: Use CDN with compression
    const wasmResponse = fetch("https://cdn.jsdelivr.net/npm/@finos/perspective-viewer/dist/cdn/perspective-viewer.wasm");
    await init_client(wasmResponse);
  }
}

Error Handling

import { init_client } from "@finos/perspective-viewer";

async function robustInitialization() {
  const wasmSources = [
    "https://cdn.jsdelivr.net/npm/@finos/perspective-viewer/dist/cdn/perspective-viewer.wasm",
    "https://unpkg.com/@finos/perspective-viewer/dist/cdn/perspective-viewer.wasm",
    "/local/perspective-viewer.wasm"
  ];
  
  for (const source of wasmSources) {
    try {
      console.log(`Attempting to load WASM from: ${source}`);
      const response = await fetch(source);
      
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }
      
      await init_client(response);
      console.log(`Successfully initialized from: ${source}`);
      return;
      
    } catch (error) {
      console.warn(`Failed to load from ${source}:`, error);
      continue;
    }
  }
  
  throw new Error("All WASM sources failed to load");
}

Initialization States

enum InitializationState {
  NotStarted = "not-started",
  Loading = "loading", 
  Ready = "ready",
  Failed = "failed"
}

class PerspectiveInitializer {
  private state = InitializationState.NotStarted;
  private initPromise: Promise<void> | null = null;
  private error: Error | null = null;
  
  getState(): InitializationState {
    return this.state;
  }
  
  getError(): Error | null {
    return this.error;
  }
  
  async initialize(): Promise<void> {
    if (this.state === InitializationState.Ready) {
      return;
    }
    
    if (this.state === InitializationState.Loading) {
      return this.initPromise!;
    }
    
    this.state = InitializationState.Loading;
    this.error = null;
    
    this.initPromise = this.performInitialization();
    
    try {
      await this.initPromise;
      this.state = InitializationState.Ready;
    } catch (error) {
      this.state = InitializationState.Failed;
      this.error = error as Error;
      throw error;
    }
  }
  
  private async performInitialization(): Promise<void> {
    const wasmResponse = await fetch("/wasm/perspective-viewer.wasm");
    await init_client(wasmResponse);
  }
}

// Usage with state management
const initializer = new PerspectiveInitializer();

// Check state before using
if (initializer.getState() !== InitializationState.Ready) {
  await initializer.initialize();
}

const viewer = document.createElement("perspective-viewer");