I currently have been trying to use WebContainers + emscripten for my compilation, and i want to know if it is possible, and if not other ways to do it. hello.js
import { WebContainer } from 'https://cdn.jsdelivr.net/npm/@webcontainer/api/dist/index.js';
let wc;
document.addEventListener('DOMContentLoaded', async () => {
const out = document.getElementById('out');
const codeEl = document.getElementById('code-editor');
wc = await WebContainer.boot({ coep: 'require-corp' });
const runner = new Worker('./run-worker.js', { type: 'module' });
runner.onmessage = (m) => {
const { stdout, stderr, exitCode } = m.data || {};
out.textContent += stdout + (stderr ? '\n[stderr]\n' + stderr : '') + '\n[exit ' + exitCode + ']';
};
document.getElementById('run').onclick = async () => {
try {
out.textContent = 'Compiling...\n';
const code = codeEl.value || '#include <iostream>\nint main(){std::cout<<"Hi\\n";}\n';
await wc.mount({
'package.json': {
file: {
contents: JSON.stringify({
name: 'cpp-wasm',
scripts: { build: 'emcc main.cpp -sSTANDALONE_WASM=1 -O2 -o a.wasm' },
devDependencies: { emscripten: 'latest' }
})
}
},
'main.cpp': {
file: { contents: code }
}
});
out.textContent += 'Installing emscripten...\n';
const install = await wc.spawn('npm', ['i']);
install.output.pipeTo(new WritableStream({
write(chunk) {
console.log('npm install:', chunk);
}
}));
const installCode = await install.exit;
console.log('npm i exit code:', installCode);
out.textContent += 'Building WASM...\n';
const build = await wc.spawn('npm', ['run', 'build']);
build.output.pipeTo(new WritableStream({
write(chunk) {
console.log('npm build:', chunk);
}
}));
const buildCode = await build.exit;
console.log('npm run build exit code:', buildCode);
const rootFiles = await wc.fs.readdir('/');
console.log('root files:', rootFiles);
const fsData = await wc.fs.readFile('/a.wasm');
const buf = fsData.buffer.slice(fsData.byteOffset, fsData.byteOffset + fsData.byteLength);
out.textContent += 'Running...\n';
runner.postMessage({ type: 'runWasi', wasm: buf }, [buf]);
} catch (err) {
out.textContent += 'Compile error: ' + String(err) + '\n';
console.error(err);
}
};
});
run worker.js
self.onmessage = async (e) => {
if (e.data.type !== 'runWasi') return;
const wasm = e.data.wasm;
const dec = new TextDecoder();
let out = '';
let inst;
function fd_write(fd, iov, iovcnt, pnum) {
const m = new DataView(inst.exports.memory.buffer);
let n = 0;
for (let i = 0; i < iovcnt; i++) {
const p = m.getUint32(iov + i * 8, true);
const l = m.getUint32(iov + i * 8 + 4, true);
const bytes = new Uint8Array(inst.exports.memory.buffer, p, l);
const t = dec.decode(bytes);
if (fd === 1 || fd === 2) out += t;
n += l;
}
m.setUint32(pnum, n, true);
return 0;
}
const imports = {
wasi_snapshot_preview1: {
fd_write,
fd_read: () => 0,
fd_close: () => 0,
fd_seek: () => 0,
fd_fdstat_get: () => 0,
environ_sizes_get: (pc, pb) => {
const m = new DataView(inst.exports.memory.buffer);
m.setUint32(pc, 0, true);
m.setUint32(pb, 0, true);
return 0;
},
environ_get: () => 0,
args_sizes_get: (pc, pb) => {
const m = new DataView(inst.exports.memory.buffer);
m.setUint32(pc, 0, true);
m.setUint32(pb, 0, true);
return 0;
},
args_get: () => 0,
clock_time_get: () => 0,
random_get: (p, l) => {
crypto.getRandomValues(new Uint8Array(inst.exports.memory.buffer, p, l));
return 0;
},
proc_exit: (c) => { throw { _wasi_exit: true, code: c }; }
}
};
try {
const { instance } = await WebAssembly.instantiate(wasm, imports);
inst = instance;
let code = 0;
try { (inst.exports._main || inst.exports.main)?.(); }
catch (ex) { if (!(ex && ex._wasi_exit)) throw ex; code = ex.code >>> 0; }
postMessage({ stdout: out, stderr: '', exitCode: code });
} catch (err) {
postMessage({ stdout: out, stderr: String(err), exitCode: 1 });
}
};
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Scrollable Boxes</title>
<link rel="stylesheet" href="hello.css">
<script type="module" src="./hello.js" defer></script>
</head>
<body>
<div class="box code-box">
<textarea id="code-editor" class="code-editor" spellcheck="false">
#include <iostream>
int main() {
std::cout << "Hello, World!" << '\n';
return 0;
}
</textarea>
<br>
<button id="run">Build & Run</button>
<pre id="out"></pre>
</div>
</div>
</body>
</html>
serving with Cross-Origin-Opener-Policy, same-origin Cross-Origin-Embedder-Policy, require-corp most recent output Compiling... Installing emscripten... Building WASM... Compile error: Error: ENOENT: no such file or directory, open '/home/uetuarq4gdsoqhfukc73ydw1enf14q-fg04/a.wasm'