Manual WebAssembly initialization for advanced use cases and custom deployments.
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 };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");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");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);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");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();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);
}
});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
});// 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
});
}
}
};// 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");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);
}
}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");
}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");