diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 312d20a..b6a9619 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -57,10 +57,11 @@ jobs: wasm32-wasi-cabal build pandoc-cli popd - - name: wasm-opt + - name: dist run: | mkdir dist wasm-opt --low-memory-unused --converge --gufa --flatten --rereloop -Oz $(find pandoc -type f -name pandoc.wasm) -o dist/pandoc.wasm + cp frontend/*.html frontend/*.js dist - name: test run: | diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..d47461d --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,92 @@ + + + + + + pandoc-wasm playground + + + +
+ + +
+
+ +
+ + + diff --git a/frontend/index.js b/frontend/index.js new file mode 100644 index 0000000..4d7928a --- /dev/null +++ b/frontend/index.js @@ -0,0 +1,62 @@ +import { + WASI, + OpenFile, + File, + ConsoleStdout, +} from "https://cdn.jsdelivr.net/npm/@bjorn3/browser_wasi_shim@0.3.0/dist/index.js"; + +const mod = await WebAssembly.compileStreaming(fetch("./pandoc.wasm")); + +const instance_promise_pool_size = 8; + +const instance_promise_pool = []; + +function instance_promise_pool_fill() { + if (instance_promise_pool.length < instance_promise_pool_size) { + for ( + let i = instance_promise_pool.length; + i < instance_promise_pool_size; + ++i + ) { + const args = []; + const env = []; + const stdin_file = new File(new Uint8Array(), { readonly: true }); + const stdout_file = new File(new Uint8Array(), { readonly: false }); + const fds = [ + new OpenFile(stdin_file), + new OpenFile(stdout_file), + ConsoleStdout.lineBuffered((msg) => + console.warn(`[WASI stderr] ${msg}`) + ), + ]; + const options = { debug: false }; + const wasi = new WASI(args, env, fds, options); + instance_promise_pool.push( + WebAssembly.instantiate(mod, { + wasi_snapshot_preview1: wasi.wasiImport, + }).then((instance) => ({ instance, wasi, stdin_file, stdout_file })) + ); + } + } +} + +instance_promise_pool_fill(); + +const instances = (async function* () { + while (true) { + yield await instance_promise_pool.shift(); + instance_promise_pool_fill(); + } +})(); + +export async function run_pandoc(args, stdin_str) { + const { instance, wasi, stdin_file, stdout_file } = (await instances.next()) + .value; + wasi.args = ["pandoc.wasm", ...args]; + stdin_file.data = new TextEncoder().encode(stdin_str); + const ec = wasi.start(instance); + if (ec !== 0) { + throw new Error(`Non-zero exit code ${ec}`); + } + return new TextDecoder("utf-8", { fatal: true }).decode(stdout_file.data); +}