Skip to content

Commit 3faa6c1

Browse files
committed
Finish client side wasm rendering
1 parent 05d5536 commit 3faa6c1

File tree

3 files changed

+87
-40
lines changed

3 files changed

+87
-40
lines changed

src/theme/book.js

+72-25
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ function playground_text(playground) {
124124

125125
result_block.innerText = "Running...";
126126

127+
params = {
128+
code: text
129+
}
127130
// fetch_with_timeout("https://play.rust-lang.org/evaluate.json", {
128131
// headers: {
129132
// 'Content-Type': "application/json",
@@ -132,35 +135,79 @@ function playground_text(playground) {
132135
// mode: 'cors',
133136
// body: JSON.stringify(params)
134137
// })
135-
new Promise((resolve, reject) => {
136-
setTimeout(() => {
137-
resolve("foo");
138-
}, 200)
138+
prepareSandbox(params).then(src => processHTML(src)).then(html => {
139+
result_block.innerText = "";
140+
var iframe = result_block.appendChild(document.createElement('iframe')),
141+
doc = iframe.contentWindow.document;
142+
iframe.id = "wasm-rendering";
143+
iframe.style.width = "100%";
144+
iframe.style.height = "100%";
145+
iframe.border = 0;
146+
iframe.scrolling = "no";
147+
doc.open().write(html);
148+
doc.close();
139149
})
140-
// .then(response => response.json())
141-
// .then(response => result_block.innerText = response.result)
142-
// .then(response => result_block.innerHTML = "<div style=\"height: 300px;background-color: red;\"></div>")
143-
// .then(response => result_block.innerHTML = " <div id=\"button_click\"></div><script type=\"module\" src=\"wasm-test.js\"></script>")
144-
.then(response => {
145-
result_block.innerText = "";
146-
var iframe = result_block.appendChild(document.createElement('iframe')),
147-
doc = iframe.contentWindow.document;
148-
iframe.id = "wasm-rendering";
149-
iframe.style.width = "100%";
150-
iframe.style.height = "100%";
151-
var xhr = new XMLHttpRequest();
152-
xhr.open('GET', 'iframe.html', true);
153-
xhr.onreadystatechange = function () {
154-
if (this.readyState !== 4) return;
155-
if (this.status !== 200) return; // or whatever error handling you want
156-
var html = this.responseText;
157-
doc.open().write(html);
158-
doc.close();
159-
};
160-
xhr.send();
150+
}
151+
async function prepareSandbox(params) {
152+
var wasmResult = fetch_with_timeout("http://192.168.217.100:9999/wasm-pack", {
153+
headers: {
154+
'Content-Type': "application/json",
155+
},
156+
method: 'POST',
157+
mode: 'cors',
158+
body: JSON.stringify(params)
159+
})
160+
.then(response => response.json())
161+
.then(({ wasm_js, wasm_bg }) => {
162+
var wasm_bg_blob = base64ToByteArray(wasm_bg);
163+
return {
164+
wasm_js: atob(wasm_js),
165+
wasm_bg: wasm_bg_blob
166+
}
161167
})
162168
.catch(error => result_block.innerText = "Playground Communication: " + error.message);
163169

170+
var htmlSrc = fetch(new Request("iframe.html"))
171+
.then(response => response.text());
172+
var jsSrc = fetch(new Request("wasm-entry.mjs"))
173+
.then(response => response.text());
174+
175+
return Promise.all([htmlSrc, jsSrc, wasmResult])
176+
.catch(error => console.log(error));
177+
}
178+
function base64ToByteArray(src) {
179+
var decode = atob(src);
180+
const byteNumbers = new Array(decode.length);
181+
for (let i = 0; i < decode.length; i++) {
182+
byteNumbers[i] = decode.charCodeAt(i);
183+
}
184+
return new Uint8Array(byteNumbers);
185+
}
186+
async function processHTML([htmlSrc, jsSrc, { wasm_js, wasm_bg }]) {
187+
var src = rewriteJS(jsSrc, wasm_js, wasm_bg);
188+
var blob = new Blob([src], { type: "application/javascript" });
189+
var jsBlob = URL.createObjectURL(blob);
190+
return htmlSrc.replace(/\bsrc\s*=\s*['"](.+?)['"]/g, (all, path) => {
191+
return `src="${jsBlob}"`;
192+
});
193+
}
194+
195+
function rewriteJS(src, wasmJS, bgWasm) {
196+
var blob = new Blob([wasmJS], { type: "application/javascript" });
197+
var wasmJSBlob = URL.createObjectURL(blob);
198+
199+
var blob = new Blob([bgWasm], { type: "application/wasm" });
200+
var bgWasmBlob = URL.createObjectURL(blob);
201+
202+
// replace wasm.js
203+
src = src.replace(/\bfrom\s+['"](.+?)['"](\s*[;\n])/g, (all, path, sep) => {
204+
return `from "${wasmJSBlob}"${sep}`;
205+
})
206+
// replace `input` of init to object URL
207+
src = src.replace(/\(['"](.+?)['"]\)/g, (all, url) => {
208+
return `("${bgWasmBlob}")`;
209+
})
210+
return src
164211
}
165212

166213
// Syntax highlighting Configuration

src/theme/iframe.html

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
<!-- Code injected from iframe.html -->
1+
<!DOCTYPE html>
2+
<html>
3+
24
<head>
3-
<script>
4-
// dynamically create script element and append to head
5-
// call wasm-entry to load the built wasm.js
6-
function body_onload() {
7-
var d = document;
8-
var script = d.createElement('script');
9-
script.type = 'module';
10-
script.src = 'wasm-entry.mjs';
11-
d.getElementsByTagName('head')[0].appendChild(script);
5+
<meta charset="utf-8">
6+
<style>
7+
body {
8+
background-color: rgb(255, 255, 255);
129
}
13-
</script>
10+
</style>
1411
</head>
1512

16-
<body onload="body_onload();">
17-
<div id="_start"></div>
18-
</body>
13+
<body>
14+
<span id="container"></span>
15+
<script src="wasm-entry.mjs" type="module"></script>
16+
</body>
17+
18+
</html>

src/theme/wasm-entry.mjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
import init from './wasm.js';
22

3-
init();
3+
await init("WASM_URL");

0 commit comments

Comments
 (0)