Runtime Compatibility
taglib-wasm is designed to work seamlessly across all major JavaScript runtimes. This document outlines the specific features and considerations for each runtime.
🟢 Supported Runtimes
✅ Deno 2.0+
- Status: Fully supported via npm specifier
- Installation:
import { TagLib } from "npm:taglib-wasm" - Features:
- Native TypeScript support
- Built-in Web APIs
- Excellent Wasm performance
- Security sandbox
- File Loading:
Deno.readFile()
import { TagLib } from "npm:taglib-wasm";
const taglib = await TagLib.initialize();
const audioData = await Deno.readFile("song.mp3");
const file = taglib.openFile(audioData);✅ Bun 1.0+
- Status: Fully supported
- Installation:
bun add taglib-wasm - Features:
- Native TypeScript support
- Fast startup and execution
- Excellent Wasm performance
- Node.js compatibility
- File Loading:
Bun.file().arrayBuffer()
import { TagLib } from "taglib-wasm";
const taglib = await TagLib.initialize();
const audioData = await Bun.file("song.mp3").arrayBuffer();
const file = taglib.openFile(new Uint8Array(audioData));✅ Node.js 22.6.0+
- Status: Fully supported
- Installation:
npm install taglib-wasm - Features:
- Mature ecosystem
- Extensive package support
- Good Wasm performance
- File Loading:
fs.readFile()orfs.promises.readFile()
import { TagLib } from "taglib-wasm";
import { readFile } from "fs/promises";
const taglib = await TagLib.initialize();
const audioData = await readFile("song.mp3");
const file = taglib.openFile(audioData);✅ Browsers (Chrome 57+, Firefox 52+, Safari 11+)
- Status: Fully supported
- Installation: Via CDN or bundler
- Features:
- Wide compatibility
- Web APIs
- Service Worker support
- File Loading:
File API,fetch(), orFileReader
import { TagLib } from "taglib-wasm";
const taglib = await TagLib.initialize();
// From file input
const fileInput = document.querySelector('input[type="file"]');
const file = fileInput.files[0];
const audioData = new Uint8Array(await file.arrayBuffer());
const tagFile = taglib.openFile(audioData);
// From fetch
const response = await fetch("song.mp3");
const audioData = new Uint8Array(await response.arrayBuffer());
const tagFile = taglib.openFile(audioData);✅ Cloudflare Workers
- Status: Fully supported
- Installation:
npm install taglib-wasm - Features:
- Edge computing
- Automatic scaling
- Global deployment
- KV/R2/D1 integration
- File Loading: Request body or fetch from storage
- Documentation: See Cloudflare Workers Guide
export default {
async fetch(request: Request): Promise<Response> {
const taglib = await TagLib.initialize();
const audioData = new Uint8Array(await request.arrayBuffer());
const file = taglib.openFile(audioData);
// Process metadata...
file.dispose();
return new Response(JSON.stringify(metadata));
},
};🔄 WebAssembly Runtime Selection
taglib-wasm includes two WebAssembly implementations and automatically selects the optimal one for your environment:
| Environment | Implementation | Reason |
|---|---|---|
| Deno | WASI | Native filesystem, best performance |
| Node.js 16+ | WASI | Native filesystem, MessagePack serialization |
| Browsers | Emscripten | Required for web compatibility |
| Cloudflare Workers | Emscripten | WASI not available |
| Bun | Emscripten | Better compatibility |
Checking the Active Implementation
const taglib = await TagLib.initialize();
console.log(taglib.isWasi); // true for Deno/Node.js
console.log(taglib.isEmscripten); // true for browsers/WorkersPerformance Benefits
WASI mode provides:
- 10x faster serialization via MessagePack (vs JSON in Emscripten)
- Native memory management with RAII patterns
- Smaller binary size (~28KB vs ~2MB)
Advanced: Manual Override
In rare cases, you may want to force a specific implementation:
import { loadUnifiedTagLibModule } from "taglib-wasm";
const module = await loadUnifiedTagLibModule({
forceWasmType: "emscripten", // or "wasi"
debug: true, // Enable loader debug output
});TIP
Most users never need to configure this. The automatic selection provides optimal performance for each environment.
High-Performance Mode: Wasmtime Sidecar
For server-side batch operations, enable the Wasmtime sidecar for true direct filesystem access. This bypasses buffer copying overhead for significantly faster processing of large file collections.
Prerequisites
Install Wasmtime:
curl https://wasmtime.dev/install.sh -sSf | bashUsage with Full API
import { TagLib } from "taglib-wasm";
await TagLib.initialize({
useSidecar: true,
sidecarConfig: {
preopens: {
"/music": "/home/user/Music",
},
},
});
// Now path-based calls use direct WASI filesystem access
const tags = await readTags("/music/song.mp3");Usage with Simple API
import { readTags, setSidecarConfig } from "taglib-wasm/simple";
// Enable sidecar mode
await setSidecarConfig({
preopens: { "/music": "/Users/me/Music" },
});
// Now path-based calls use the sidecar
const tags = await readTags("/music/song.mp3");
// Disable sidecar when done
await setSidecarConfig(null);When to Use
| Scenario | Recommended Mode |
|---|---|
| Browser | Buffer-based (default) |
| Single file CLI | Buffer-based |
| Batch processing (100+ files) | Sidecar |
| Electron app with large library | Sidecar |
Key Details
- Requires Wasmtime CLI: The sidecar spawns a Wasmtime process to execute the WASI binary
- Sandboxed filesystem: Preopens define which directories the sidecar can access (security feature)
- Virtual paths: The keys in preopens become the virtual paths you use in API calls (e.g.,
/music/song.mp3maps to/home/user/Music/song.mp3) - Server-side only: Node.js, Deno, and Bun only (requires process spawning)
🔧 Runtime-Specific Features
Memory Management
All runtimes use the same memory management approach:
- Emscripten's
allocate()for JS↔Wasm data transfer - Automatic garbage collection for JavaScript objects
- Manual disposal required for C++ objects:
file.dispose()
File System Access
Each runtime has different file system capabilities:
| Runtime | File System | Security | Best For |
|---|---|---|---|
| Deno | Sandboxed, permission-based | High | Server-side, CLI tools |
| Bun | Full access | Medium | Server-side, build tools |
| Node.js | Full access | Medium | Server-side, classic apps |
| Browser | Limited (File API only) | High | Client-side, web apps |
| Workers | None (Request/KV/R2 only) | High | Edge computing, APIs |
Performance Characteristics
| Runtime | Startup | Wasm Performance | Memory Usage | TypeScript |
|---|---|---|---|---|
| Bun | Very Fast | Excellent | Low | Native |
| Deno | Fast | Excellent | Medium | Native |
| Workers | Very Fast | Excellent | Low | Native |
| Node.js | Medium | Good | Medium | Via loader |
| Browser | Fast | Good | Medium | Via build |
📦 Installation Matrix
| Runtime | Package Manager | Command |
|---|---|---|
| Deno | npm specifier | import { TagLib } from "npm:taglib-wasm" |
| Bun | bun | bun add taglib-wasm |
| Node.js | npm | npm install taglib-wasm |
| Node.js | yarn | yarn add taglib-wasm |
| Node.js | pnpm | pnpm add taglib-wasm |
| Workers | npm | npm install taglib-wasm |
| Browser | CDN | <script type="module" src="..."> |
🧪 Testing Across Runtimes
The project includes comprehensive tests that run on all supported runtimes:
# Test with Deno (recommended)
deno run --allow-read test-systematic.ts
# Test with Bun
bun run test-systematic.ts
# Test with Node.js
npm test
# Test in browser
# Open examples/browser/index.html🚧 Known Limitations
General Limitations
- File Writing: Changes only affect in-memory representation
- Large Files: Memory usage scales with file size
- Thread Safety: Single-threaded execution (JavaScript limitation)
Runtime-Specific Limitations
Deno
- Requires
--allow-readpermission for file access - Some Node.js modules may not be compatible
- Offline Support: Compiled binaries can embed WASM for offline usage (see Deno Compile Guide)
Bun
- Relatively new runtime, ecosystem still developing
- Some npm packages may have compatibility issues
Node.js
- Requires TypeScript loader for direct .ts execution
- Older versions (<18) may have limited Wasm support
Browser
- No direct file system access (security limitation)
- Wasm files must be served with correct MIME type
- May require additional build configuration
Cloudflare Workers
- 128MB memory limit per request
- 50ms CPU time (free tier) or 30s (paid tier)
- No file system access
- Request/response size limited to 100MB
🎯 Deno Compiled Binaries
taglib-wasm includes special support for creating offline-capable Deno compiled binaries:
Automatic Offline Support
import { initializeForDenoCompile } from "taglib-wasm";
// Automatically uses embedded WASM in compiled binaries
// Falls back to network fetch in development
const taglib = await initializeForDenoCompile();Manual WASM Embedding
Prepare the WASM file:
typescriptimport { prepareWasmForEmbedding } from "taglib-wasm"; await prepareWasmForEmbedding("./taglib.wasm");Initialize with embedded WASM:
typescriptimport { TagLib } from "taglib-wasm"; const wasmBinary = await Deno.readFile("./taglib.wasm"); const taglib = await TagLib.initialize({ wasmBinary });Compile with embedded assets:
bashdeno compile --allow-read --include taglib.wasm your-app.ts
Benefits
- ✅ No network access required
- ✅ Single executable file
- ✅ Faster startup (no WASM fetch)
- ✅ Works in air-gapped environments
Example
See the complete example in examples/deno/offline-compile.ts.
💡 Best Practices
Universal Code
Write code that works across all runtimes:
// Good: Runtime-agnostic
import { TagLib } from "taglib-wasm";
const taglib = await TagLib.initialize();
// Avoid: Runtime-specific APIs in shared code
// const audioData = await Deno.readFile("file.mp3"); // Deno only
// const audioData = await Bun.file("file.mp3").arrayBuffer(); // Bun onlyError Handling
Account for different runtime capabilities:
async function loadAudioFile(path: string): Promise<Uint8Array> {
// Runtime detection
if (typeof Deno !== "undefined") {
return await Deno.readFile(path);
} else if (typeof Bun !== "undefined") {
return new Uint8Array(await Bun.file(path).arrayBuffer());
} else {
// Node.js or browser
const fs = await import("fs/promises");
return await fs.readFile(path);
}
}Configuration
Use runtime-appropriate configuration:
const config = {
memory: {
// Adjust based on runtime capabilities
initial: typeof Bun !== "undefined" ? 32 * 1024 * 1024 : 16 * 1024 * 1024,
maximum: 256 * 1024 * 1024,
},
debug: process.env.NODE_ENV === "development",
};
const taglib = await TagLib.initialize(config);📚 Additional Resources
This universal compatibility ensures taglib-wasm can be used in any modern JavaScript environment, from servers to browsers to edge computing platforms.