or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

code-completion.mdevent-streaming.mdfile-system.mdhttp-client.mdindex.mdnetwork-utilities.mdpackage-management.mdsvelte-integration.mdworker-management.md
tile.json

svelte-integration.mddocs/

Svelte Integration

Svelte framework integration with context management and specialized components for WebAssembly worker integration. Provides seamless integration between Svelte applications and the @gradio/wasm worker system.

Capabilities

Context Management

Svelte context functions for sharing WorkerProxy instances across components.

/**
 * Set worker proxy in Svelte context for sharing across components
 * @param workerProxy - WorkerProxy instance to share
 */
function setWorkerProxyContext(workerProxy: WorkerProxy): void;

/**
 * Get worker proxy from Svelte context
 * @returns WorkerProxy instance or undefined if not set
 */
function getWorkerProxyContext(): WorkerProxy | undefined;

Usage Examples:

// App.svelte - Root component
<script lang="ts">
  import { onMount } from 'svelte';
  import { WorkerProxy } from '@gradio/wasm';
  import { setWorkerProxyContext } from '@gradio/wasm/svelte';
  import PythonExecutor from './PythonExecutor.svelte';
  import DataAnalyzer from './DataAnalyzer.svelte';

  let worker: WorkerProxy;
  let workerReady = false;

  onMount(async () => {
    // Create and initialize worker
    worker = new WorkerProxy({
      gradioWheelUrl: 'https://example.com/gradio.whl',
      gradioClientWheelUrl: 'https://example.com/gradio_client.whl',
      files: {},
      requirements: ['numpy', 'pandas', 'matplotlib'],
      sharedWorkerMode: false
    });

    // Set worker in context for child components
    setWorkerProxyContext(worker);

    worker.addEventListener('initialization-completed', () => {
      workerReady = true;
    });
  });
</script>

{#if workerReady}
  <div class="app">
    <h1>Python-powered Svelte App</h1>
    <PythonExecutor />
    <DataAnalyzer />
  </div>
{:else}
  <div class="loading">Initializing Python environment...</div>
{/if}
// PythonExecutor.svelte - Child component using context
<script lang="ts">
  import { getWorkerProxyContext } from '@gradio/wasm/svelte';
  
  const worker = getWorkerProxyContext();
  
  let code = 'print("Hello from Python!")';
  let output = '';
  let isExecuting = false;

  async function executeCode() {
    if (!worker) {
      console.error('Worker not available in context');
      return;
    }

    isExecuting = true;
    output = '';

    try {
      // Listen for output
      const handleStdout = (event: CustomEvent) => {
        output += event.detail.data + '\n';
      };

      worker.addEventListener('stdout', handleStdout);
      
      await worker.runPythonCode(code);
      
      worker.removeEventListener('stdout', handleStdout);
    } catch (error) {
      output += `Error: ${error}\n`;
    } finally {
      isExecuting = false;
    }
  }
</script>

<div class="python-executor">
  <h2>Python Code Executor</h2>
  
  <textarea 
    bind:value={code} 
    placeholder="Enter Python code..."
    disabled={isExecuting}
  ></textarea>
  
  <button on:click={executeCode} disabled={isExecuting || !worker}>
    {isExecuting ? 'Executing...' : 'Run Code'}
  </button>
  
  {#if output}
    <pre class="output">{output}</pre>
  {/if}
</div>

<style>
  .python-executor {
    margin: 20px 0;
    padding: 20px;
    border: 1px solid #ddd;
    border-radius: 8px;
  }
  
  textarea {
    width: 100%;
    height: 150px;
    font-family: monospace;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 4px;
  }
  
  button {
    margin-top: 10px;
    padding: 10px 20px;
    background: #007bff;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
  }
  
  button:disabled {
    background: #ccc;
    cursor: not-allowed;
  }
  
  .output {
    margin-top: 10px;
    padding: 10px;
    background: #f8f9fa;
    border: 1px solid #e9ecef;
    border-radius: 4px;
    font-family: monospace;
    white-space: pre-wrap;
  }
</style>

File URL Resolution

Functions for handling file URLs through the WebAssembly worker proxy.

/**
 * Check if source URL should be proxied through WASM worker
 * @param src - Source URL string to check
 * @returns true if URL should be proxied
 */
function should_proxy_wasm_src(src: string | undefined | null): boolean;

/**
 * Resolve source URL through WASM worker proxy
 * @param src - Source URL to resolve
 * @returns Promise resolving to proxied URL or original URL
 */
function resolve_wasm_src(src: string | undefined | null): Promise<string | undefined | null>;

Usage Examples:

// FileDownloader.svelte
<script lang="ts">
  import { getWorkerProxyContext } from '@gradio/wasm/svelte';
  import { should_proxy_wasm_src, resolve_wasm_src } from '@gradio/wasm/svelte';
  
  export let src: string;
  export let filename: string;
  
  const worker = getWorkerProxyContext();
  
  let resolvedSrc: string | null = null;
  let isResolving = false;
  
  $: if (src) {
    resolveSource(src);
  }
  
  async function resolveSource(source: string) {
    isResolving = true;
    
    try {
      if (should_proxy_wasm_src(source)) {
        console.log('Proxying URL through WASM worker:', source);
        resolvedSrc = await resolve_wasm_src(source);
      } else {
        console.log('Using direct URL:', source);
        resolvedSrc = source;
      }
    } catch (error) {
      console.error('Failed to resolve source:', error);
      resolvedSrc = source; // Fallback to original
    } finally {
      isResolving = false;
    }
  }
</script>

{#if isResolving}
  <div class="resolving">Resolving file URL...</div>
{:else if resolvedSrc}
  <a href={resolvedSrc} download={filename} class="download-link">
    Download {filename}
  </a>
{:else}
  <div class="error">Failed to resolve file URL</div>
{/if}

<style>
  .download-link {
    display: inline-block;
    padding: 8px 16px;
    background: #28a745;
    color: white;
    text-decoration: none;
    border-radius: 4px;
    font-weight: bold;
  }
  
  .download-link:hover {
    background: #218838;
  }
  
  .resolving, .error {
    padding: 8px 16px;
    border-radius: 4px;
  }
  
  .resolving {
    background: #fff3cd;
    color: #856404;
  }
  
  .error {
    background: #f8d7da;
    color: #721c24;
  }
</style>

DownloadLink Component

Specialized Svelte component for download links that work with the WASM worker.

/**
 * Download link component that works with WASM worker
 * Props:
 * - href: string | undefined - Download URL
 * - download: string - Download filename  
 * - ...$$restProps - Additional anchor attributes
 * 
 * Events:
 * - click - Dispatched on click
 * 
 * Slots:
 * - default - Link content
 */
// DownloadLink.svelte component interface

Usage Examples:

// Using DownloadLink component
<script lang="ts">
  import { DownloadLink } from '@gradio/wasm/svelte';
  import { getWorkerProxyContext } from '@gradio/wasm/svelte';
  
  const worker = getWorkerProxyContext();
  
  let fileUrl: string | undefined;
  let fileName = 'output.csv';
  
  async function generateFile() {
    if (!worker) return;
    
    // Generate data in Python
    await worker.runPythonCode(`
import pandas as pd
import json

# Create sample data
data = {
    'name': ['Alice', 'Bob', 'Charlie'],
    'age': [25, 30, 35],
    'city': ['New York', 'San Francisco', 'Boston']
}

df = pd.DataFrame(data)

# Save to CSV
df.to_csv('output.csv', index=False)
print('File generated: output.csv')
`);
    
    // In a real implementation, you'd get the file URL from the worker
    fileUrl = '/worker-files/output.csv';
  }
  
  function handleDownloadClick(event) {
    console.log('Download initiated:', event.detail);
  }
</script>

<div class="file-generator">
  <h3>Data File Generator</h3>
  
  <button on:click={generateFile} disabled={!worker}>
    Generate CSV File
  </button>
  
  {#if fileUrl}
    <div class="download-section">
      <p>File generated successfully!</p>
      <DownloadLink 
        href={fileUrl} 
        download={fileName}
        class="download-btn"
        on:click={handleDownloadClick}
      >
        πŸ“„ Download {fileName}
      </DownloadLink>
    </div>
  {/if}
</div>

<style>
  .file-generator {
    padding: 20px;
    border: 1px solid #ddd;
    border-radius: 8px;
    margin: 20px 0;
  }
  
  button {
    padding: 10px 20px;
    background: #007bff;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
  }
  
  button:disabled {
    background: #ccc;
    cursor: not-allowed;
  }
  
  .download-section {
    margin-top: 15px;
    padding: 15px;
    background: #d4edda;
    border: 1px solid #c3e6cb;
    border-radius: 4px;
  }
  
  :global(.download-btn) {
    display: inline-block;
    padding: 10px 20px;
    background: #28a745;
    color: white;
    text-decoration: none;
    border-radius: 4px;
    font-weight: bold;
    margin-top: 10px;
  }
  
  :global(.download-btn:hover) {
    background: #218838;
  }
</style>

Complete Svelte App Example

Full example of a Svelte application integrated with @gradio/wasm:

// main.js - Application entry point
import App from './App.svelte';

const app = new App({
  target: document.body,
  props: {
    name: 'Python-Powered Svelte App'
  }
});

export default app;
// App.svelte - Main application component
<script lang="ts">
  import { onMount, onDestroy } from 'svelte';
  import { WorkerProxy } from '@gradio/wasm';
  import { setWorkerProxyContext } from '@gradio/wasm/svelte';
  
  import Header from './components/Header.svelte';
  import PythonConsole from './components/PythonConsole.svelte';
  import DataVisualizer from './components/DataVisualizer.svelte';
  import FileManager from './components/FileManager.svelte';
  
  export let name: string;
  
  let worker: WorkerProxy;
  let workerStatus: 'initializing' | 'ready' | 'error' = 'initializing';
  let initializationError: string | null = null;

  onMount(async () => {
    try {
      worker = new WorkerProxy({
        gradioWheelUrl: 'https://cdn.jsdelivr.net/pyodide/gradio.whl',
        gradioClientWheelUrl: 'https://cdn.jsdelivr.net/pyodide/gradio_client.whl',
        files: {
          'sample_data.csv': {
            data: 'name,age,score\nAlice,25,95\nBob,30,87\nCharlie,35,92',
            opts: { encoding: 'utf8' }
          }
        },
        requirements: [
          'numpy>=1.21.0',
          'pandas>=1.3.0',
          'matplotlib>=3.4.0',
          'seaborn>=0.11.0'
        ],
        sharedWorkerMode: false
      });

      // Set worker in context
      setWorkerProxyContext(worker);

      worker.addEventListener('initialization-completed', () => {
        workerStatus = 'ready';
        console.log('Python environment ready!');
      });

      worker.addEventListener('initialization-error', (event) => {
        workerStatus = 'error';
        initializationError = event.detail?.error || 'Unknown initialization error';
        console.error('Worker initialization failed:', initializationError);
      });

      worker.addEventListener('python-error', (event) => {
        console.error('Python error:', event.detail);
      });

    } catch (error) {
      workerStatus = 'error';
      initializationError = error.toString();
      console.error('Failed to create worker:', error);
    }
  });

  onDestroy(() => {
    if (worker) {
      worker.terminate();
    }
  });
</script>

<main>
  <Header {name} status={workerStatus} />
  
  {#if workerStatus === 'initializing'}
    <div class="status-panel initializing">
      <div class="spinner"></div>
      <p>Initializing Python environment...</p>
      <small>This may take a minute on first load</small>
    </div>
  {:else if workerStatus === 'error'}
    <div class="status-panel error">
      <h3>❌ Initialization Failed</h3>
      <p>{initializationError}</p>
      <button on:click={() => location.reload()}>
        πŸ”„ Retry
      </button>
    </div>
  {:else if workerStatus === 'ready'}
    <div class="app-content">
      <div class="left-panel">
        <PythonConsole />
        <FileManager />
      </div>
      <div class="right-panel">
        <DataVisualizer />
      </div>
    </div>
  {/if}
</main>

<style>
  main {
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  }
  
  .status-panel {
    text-align: center;
    padding: 40px;
    border-radius: 8px;
    margin: 40px 0;
  }
  
  .status-panel.initializing {
    background: #fff3cd;
    border: 1px solid #ffeaa7;
    color: #856404;
  }
  
  .status-panel.error {
    background: #f8d7da;
    border: 1px solid #f5c6cb;
    color: #721c24;
  }
  
  .spinner {
    width: 40px;
    height: 40px;
    border: 4px solid #f3f3f3;
    border-top: 4px solid #007bff;
    border-radius: 50%;
    animation: spin 1s linear infinite;
    margin: 0 auto 20px;
  }
  
  @keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
  }
  
  .app-content {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
    margin-top: 20px;
  }
  
  .left-panel, .right-panel {
    display: flex;
    flex-direction: column;
    gap: 20px;
  }
  
  @media (max-width: 768px) {
    .app-content {
      grid-template-columns: 1fr;
    }
  }
</style>

Integration Best Practices

Key patterns and best practices for Svelte integration:

// WorkerStore.js - Reactive store for worker state
import { writable, derived } from 'svelte/store';
import { WorkerProxy } from '@gradio/wasm';

export const workerStore = writable(null);
export const workerStatus = writable('initializing');
export const pythonOutput = writable([]);

export const isWorkerReady = derived(
  workerStatus, 
  $status => $status === 'ready'
);

export async function initializeWorker(options) {
  const worker = new WorkerProxy(options);
  
  worker.addEventListener('initialization-completed', () => {
    workerStatus.set('ready');
  });
  
  worker.addEventListener('stdout', (event) => {
    pythonOutput.update(output => [...output, { type: 'stdout', data: event.detail.data }]);
  });
  
  worker.addEventListener('stderr', (event) => {
    pythonOutput.update(output => [...output, { type: 'stderr', data: event.detail.data }]);
  });
  
  workerStore.set(worker);
  return worker;
}
// Component using the store
<script lang="ts">
  import { workerStore, isWorkerReady, pythonOutput } from '../stores/WorkerStore.js';
  
  $: worker = $workerStore;
  $: ready = $isWorkerReady;
  $: output = $pythonOutput;
  
  async function runCode(code) {
    if (worker) {
      await worker.runPythonCode(code);
    }
  }
</script>

{#if ready}
  <button on:click={() => runCode('print("Hello from Svelte!")')}>
    Run Python Code
  </button>
  
  <div class="output">
    {#each output as line}
      <div class="output-line {line.type}">
        {line.data}
      </div>
    {/each}
  </div>
{:else}
  <div>Worker not ready</div>
{/if}