browser-code-runner
v1.0.5
Published
A unified API for executing different programming language code in the browser
Downloads
38
Maintainers
Readme
Browser Code Runner
A unified API to execute different programming languages in the browser using web workers. This package provides a seamless way to run JavaScript, Python, and Lua code directly in the browser without blocking the main thread.
✨ What's New in v1.0.2
- 🚀 Full Python Support: Python execution now works out-of-the-box with Pyodide
- 🎯 Full Lua Support: Lua execution now works out-of-the-box with Fengari
- 🔧 Self-Contained: No need to manually load libraries - everything is handled automatically
- ⚡ Dynamic Loading: Libraries are loaded only when needed and cached for performance
- 🛡️ Better Error Handling: Comprehensive error messages and fallback mechanisms
Features
- 🚀 Web Worker Support: All code execution runs in separate threads to keep your main thread responsive
- 🐍 Python Support: Execute Python code using Pyodide (CPython compiled to WebAssembly) - Now fully working!
- 🔧 JavaScript Support: Execute JavaScript/TypeScript code in a sandboxed environment
- 🎯 Lua Support: Execute Lua code using Fengari (Lua VM in JavaScript) - Now fully working!
- ⏱️ Timeout Protection: Configurable timeouts to prevent infinite loops
- 📦 TypeScript Support: Full TypeScript definitions included
- 🧪 Comprehensive Testing: Thorough test coverage for all features
- 🔄 Automatic Library Loading: Pyodide and Fengari are loaded automatically when needed
- 💾 Smart Caching: Libraries are cached after first use for faster subsequent executions
Installation
npm install browser-code-runnerQuick Start
import { runCode } from 'browser-code-runner';
// Execute Python code (now works out-of-the-box!)
const pythonResult = await runCode({
language: 'python',
code: 'print("Hello from Python!")\nprint("2 + 2 =", 2 + 2)',
timeout: 5000
});
console.log(pythonResult.stdout); // "Hello from Python!\n2 + 2 = 4\n"
// Execute Lua code (now works out-of-the-box!)
const luaResult = await runCode({
language: 'lua',
code: 'print("Hello from Lua!")\nprint("2 + 2 =", 2 + 2)',
timeout: 3000
});
console.log(luaResult.stdout); // "Hello from Lua!\n2 + 2 = 4\n"
// Execute JavaScript code (always worked)
const jsResult = await runCode({
language: 'javascript',
code: 'console.log("Hello from JavaScript!")\nconsole.log("2 + 2 =", 2 + 2)',
timeout: 2000
});
console.log(jsResult.stdout); // "Hello from JavaScript!\n2 + 2 = 4\n"🎮 Try the Demo
Experience the Browser Code Runner in action with our interactive demo:
- 🌐 Live Demo: View Demo
- 📱 Mobile Responsive: Works perfectly on all devices
- 🎨 Monaco Editor: Professional code editing experience
- 🚀 Real-time Execution: See results immediately
- 🐍 Python Support: Full Python execution with Pyodide
- 🎯 Lua Support: Full Lua execution with Fengari
Run locally:
npm install
npm run demoSupported Languages
Phase 1 (Fully Supported ✅)
JavaScript/TypeScript
- Runs natively in the browser
- Sandboxed execution environment
- Full access to JavaScript APIs
- Status: ✅ Fully Working
Python
- Powered by Pyodide (CPython → WebAssembly)
- Status: ✅ Fully Working (v1.0.2+)
- Automatically loads Pyodide when needed
- Full Python standard library support
- Cached after first use for performance
Lua
- Powered by Fengari (Lua VM in JavaScript)
- Status: ✅ Fully Working (v1.0.2+)
- Automatically loads Fengari when needed
- Lightweight and fast execution
- Cached after first use for performance
🚀 Implementation Guide
Basic Usage
The simplest way to use the package is with the runCode function:
import { runCode } from 'browser-code-runner';
// All languages work the same way
const result = await runCode({
language: 'javascript' | 'python' | 'lua',
code: 'your code here',
timeout: 5000 // optional, default: 5000ms
});Advanced Usage
For more control, use the CodeRunner class:
import { createCodeRunner } from 'browser-code-runner';
const runner = createCodeRunner();
try {
const result = await runner.runCode({
language: 'python',
code: 'print("Hello World")',
timeout: 10000
});
console.log('Output:', result.stdout);
console.log('Errors:', result.stderr);
console.log('Exit Code:', result.exitCode);
console.log('Execution Time:', result.timeMs + 'ms');
} finally {
// Always clean up resources
runner.terminate();
}Error Handling
import { runCode } from 'browser-code-runner';
try {
const result = await runCode({
language: 'python',
code: 'print("Hello")\nundefined_variable', // This will cause an error
timeout: 5000
});
if (result.exitCode !== 0) {
console.error('Execution failed:', result.stderr);
} else {
console.log('Success:', result.stdout);
}
} catch (error) {
if (error.message.includes('timed out')) {
console.error('Code execution timed out');
} else if (error.message.includes('Failed to load')) {
console.error('Library loading failed:', error.message);
} else {
console.error('Unexpected error:', error.message);
}
}📚 Language-Specific Examples
Python Examples
Basic Python
const result = await runCode({
language: 'python',
code: `
print("Hello from Python!")
print("2 + 2 =", 2 + 2)
# Lists and loops
numbers = [1, 2, 3, 4, 5]
for num in numbers:
print(f"Number: {num}")
# Functions
def greet(name):
return f"Hello, {name}!"
print(greet("World"))
`,
timeout: 8000 // Python needs more time for library loading
});Python with Libraries
const result = await runCode({
language: 'python',
code: `
import math
import random
from datetime import datetime
# Generate random data
data = [random.randint(1, 100) for _ in range(10)]
print("Random data:", data)
# Calculate statistics
mean = sum(data) / len(data)
print(f"Mean: {mean:.2f}")
print(f"Square root of 16: {math.sqrt(16)}")
# Current time
print(f"Current time: {datetime.now()}")
`,
timeout: 10000
});Lua Examples
Basic Lua
const result = await runCode({
language: 'lua',
code: `
print("Hello from Lua!")
print("2 + 2 =", 2 + 2)
-- Tables and loops
local numbers = {1, 2, 3, 4, 5}
for i, num in ipairs(numbers) do
print("Number:", num)
end
-- Functions
local function greet(name)
return "Hello, " .. name .. "!"
end
print(greet("World"))
`,
timeout: 5000
});Advanced Lua
const result = await runCode({
language: 'lua',
code: `
-- Fibonacci with memoization
local memo = {}
function fibonacci(n)
if memo[n] then
return memo[n]
end
if n <= 1 then
memo[n] = n
return n
end
memo[n] = fibonacci(n-1) + fibonacci(n-2)
return memo[n]
end
-- Calculate first 10 Fibonacci numbers
for i = 0, 10 do
print("fib(" .. i .. ") = " .. fibonacci(i))
end
`,
timeout: 6000
});JavaScript Examples
Basic JavaScript
const result = await runCode({
language: 'javascript',
code: `
console.log("Hello from JavaScript!");
console.log("2 + 2 =", 2 + 2);
// Arrays and loops
const numbers = [1, 2, 3, 4, 5];
numbers.forEach(num => console.log("Number:", num));
// Functions
function greet(name) {
return \`Hello, \${name}!\`;
}
console.log(greet("World"));
`,
timeout: 3000
});Advanced JavaScript
const result = await runCode({
language: 'javascript',
code: `
// Classes and async operations
class Calculator {
constructor() {
this.history = [];
}
add(a, b) {
const result = a + b;
this.history.push(\`\${a} + \${b} = \${result}\`);
return result;
}
getHistory() {
return this.history;
}
}
const calc = new Calculator();
console.log("5 + 3 =", calc.add(5, 3));
console.log("History:", calc.getHistory());
// Async operations
async function fetchData() {
const promise = Promise.resolve("Data fetched successfully!");
const result = await promise;
console.log(result);
}
fetchData();
`,
timeout: 4000
});🔧 API Reference
runCode(options: RunCodeOptions): Promise<RunCodeResult>
The main function to execute code in any supported language.
Parameters
interface RunCodeOptions {
language: 'javascript' | 'python' | 'lua';
code: string;
stdin?: string;
timeout?: number; // Default: 5000ms
}Returns
interface RunCodeResult {
stdout: string;
stderr: string;
exitCode: number; // 0 for success, non-zero for errors
timeMs: number; // Execution time in milliseconds
}createCodeRunner(workerUrl?: string): CodeRunner
Create a new CodeRunner instance for advanced usage.
CodeRunner Class
Advanced API for managing multiple code executions.
const runner = createCodeRunner();
// Execute code
const result = await runner.runCode({
language: 'javascript',
code: 'console.log("Hello World");'
});
// Clean up resources
runner.terminate();🚨 Troubleshooting
Common Issues
1. Python/Lua Execution Fails
Problem: Getting "Failed to load Pyodide/Fengari" errors Solution:
- Ensure you have a stable internet connection (libraries are loaded from CDN)
- Check if your browser supports WebAssembly
- Try increasing the timeout value
2. Code Execution Times Out
Problem: Code runs but times out before completion Solution:
- Increase the
timeoutparameter - For Python: Use
timeout: 8000or higher - For Lua: Use
timeout: 5000or higher - For JavaScript: Use
timeout: 3000or higher
3. Worker Not Found
Problem: "Worker script not found" error Solution:
- Ensure the worker file is accessible
- Check if you're using a custom worker URL
- Verify the package is properly built
4. Library Loading Issues
Problem: Pyodide or Fengari fails to load Solution:
- Check browser console for network errors
- Ensure CDN access is not blocked
- Try refreshing the page and retrying
Performance Tips
Set Appropriate Timeouts:
- JavaScript: 2000-5000ms
- Python: 8000-15000ms (first run), 3000-8000ms (subsequent)
- Lua: 5000-10000ms (first run), 2000-5000ms (subsequent)
Library Caching:
- First execution of Python/Lua will be slower due to library loading
- Subsequent executions will be much faster
- Libraries are cached in the worker
Code Optimization:
- Avoid infinite loops
- Use appropriate data structures
- Consider memory usage for large operations
Performance Considerations
Web Workers
- All code execution runs in separate threads
- Main thread remains responsive during execution
- Automatic cleanup of worker resources
Caching
- Python (Pyodide): ~7-10 MB initial download, cached after first use
- Lua (Fengari): ~1 MB, very lightweight
- JavaScript: No additional downloads required
Timeouts
- Default timeout: 5000ms (5 seconds)
- Recommended timeouts:
- JavaScript: 2000-5000ms
- Python: 8000-15000ms
- Lua: 5000-10000ms
- Automatic cleanup on timeout
Browser Compatibility
- Modern Browsers: Chrome 80+, Firefox 75+, Safari 13+, Edge 80+
- Web Worker Support: Required
- ES2020 Features: Required
- WebAssembly: Required for Python support
- Network Access: Required for library loading (CDN)
Development
Setup
git clone <repository-url>
cd browser-code-runner
npm installBuild
npm run build # Build TypeScript + worker
npm run build:vite # Build ES/UMD bundles
npm run build:all # Full build for publishingTest
npm test
npm run test:watchLint
npm run lint
npm run lint:fixFormat
npm run formatDemo
npm run demo # Build + copy worker + serve demoContributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
License
MIT License - see LICENSE file for details.
Roadmap
Phase 2 (Future)
- C/C++ support via Emscripten
- Ruby support via Opal or WASM MRI builds
- Go support via WebAssembly
- Rust support via WebAssembly
Phase 3 (Future)
- Real-time collaboration features
- Code sharing and execution
- Advanced debugging capabilities
- Performance profiling
Support
- Issues: GitHub Issues
- Documentation: GitHub Wiki
- Discussions: GitHub Discussions
Acknowledgments
- Pyodide - Python in the browser
- Fengari - Lua VM in JavaScript
- Web Workers API - Browser threading
