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.
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>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>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 interfaceUsage 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>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>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}