Update fetch for static page gen, fix DOM patching
This commit is contained in:
109
go/wasmruntime/testdata/domexec.js
vendored
Normal file
109
go/wasmruntime/testdata/domexec.js
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
// A `go test -exec` wrapper for GOOS=js GOARCH=wasm that installs a minimal DOM
|
||||
// before starting the Go runtime, so the reconciler can be driven headlessly
|
||||
// under node instead of only in a browser. From kjol/go:
|
||||
//
|
||||
// GOOS=js GOARCH=wasm go test -exec="node testdata/domexec.js" ./wasmruntime
|
||||
//
|
||||
// The subtlety that matters: in a real browser, setting .innerHTML *parses* the
|
||||
// markup into real child nodes, so a later appendChild lands after it. The shim
|
||||
// models that (one opaque "#raw" child) rather than keeping innerHTML as a
|
||||
// detached string — treating it as a string would hide the very class of bug
|
||||
// these tests exist to catch (stale raw markup surviving a diff).
|
||||
"use strict";
|
||||
|
||||
const { execSync } = require("child_process");
|
||||
|
||||
class DNode {
|
||||
constructor(tag) {
|
||||
this.tag = tag;
|
||||
this.childNodes = [];
|
||||
this.attrs = {};
|
||||
this.parentNode = null;
|
||||
this.listeners = {};
|
||||
this.nodeValue = null;
|
||||
this.rawHTML = null;
|
||||
}
|
||||
get firstChild() { return this.childNodes[0] ?? null; }
|
||||
appendChild(c) { c.parentNode = this; this.childNodes.push(c); return c; }
|
||||
removeChild(c) {
|
||||
const i = this.childNodes.indexOf(c);
|
||||
if (i < 0) throw new Error("removeChild: node is not a child");
|
||||
this.childNodes.splice(i, 1);
|
||||
c.parentNode = null;
|
||||
return c;
|
||||
}
|
||||
replaceChild(next, old) {
|
||||
const i = this.childNodes.indexOf(old);
|
||||
if (i < 0) throw new Error("replaceChild: node is not a child");
|
||||
this.childNodes[i] = next;
|
||||
next.parentNode = this;
|
||||
old.parentNode = null;
|
||||
return old;
|
||||
}
|
||||
setAttribute(k, v) { this.attrs[k] = String(v); }
|
||||
removeAttribute(k) { delete this.attrs[k]; }
|
||||
addEventListener(name, fn) { (this.listeners[name] ??= []).push(fn); }
|
||||
removeEventListener(name, fn) {
|
||||
const l = this.listeners[name] ?? [];
|
||||
const i = l.indexOf(fn);
|
||||
if (i >= 0) l.splice(i, 1);
|
||||
}
|
||||
set innerHTML(html) {
|
||||
for (const c of this.childNodes) c.parentNode = null;
|
||||
this.childNodes = [];
|
||||
if (html !== "") {
|
||||
const raw = new DNode("#raw");
|
||||
raw.rawHTML = html;
|
||||
raw.parentNode = this;
|
||||
this.childNodes.push(raw);
|
||||
}
|
||||
}
|
||||
get innerHTML() { return this.childNodes.map(serialize).join(""); }
|
||||
get outerHTML() { return serialize(this); }
|
||||
}
|
||||
|
||||
function serialize(n) {
|
||||
if (n.tag === "#text") return n.nodeValue ?? "";
|
||||
if (n.tag === "#raw") return n.rawHTML ?? "";
|
||||
const attrs = Object.keys(n.attrs).sort().map((k) => ` ${k}="${n.attrs[k]}"`).join("");
|
||||
return `<${n.tag}${attrs}>${n.childNodes.map(serialize).join("")}</${n.tag}>`;
|
||||
}
|
||||
|
||||
globalThis.document = {
|
||||
createElement: (tag) => new DNode(tag),
|
||||
createTextNode: (text) => { const n = new DNode("#text"); n.nodeValue = text; return n; },
|
||||
getElementById: () => null,
|
||||
};
|
||||
|
||||
// ---- go_js_wasm_exec boilerplate ----
|
||||
globalThis.require = require;
|
||||
globalThis.fs = require("fs");
|
||||
globalThis.TextEncoder = require("util").TextEncoder;
|
||||
globalThis.TextDecoder = require("util").TextDecoder;
|
||||
globalThis.performance ??= require("performance");
|
||||
globalThis.crypto ??= require("crypto");
|
||||
|
||||
// wasm_exec.js moved from misc/wasm to lib/wasm in Go 1.24.
|
||||
const goroot = execSync("go env GOROOT").toString().trim();
|
||||
try {
|
||||
require(goroot + "/lib/wasm/wasm_exec.js");
|
||||
} catch {
|
||||
require(goroot + "/misc/wasm/wasm_exec.js");
|
||||
}
|
||||
|
||||
const go = new Go();
|
||||
go.argv = process.argv.slice(2);
|
||||
go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
|
||||
go.exit = process.exit;
|
||||
WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
|
||||
process.on("exit", (code) => {
|
||||
if (code === 0 && !go.exited) {
|
||||
go._pendingEvent = { id: 0 };
|
||||
go._resume();
|
||||
}
|
||||
});
|
||||
return go.run(result.instance);
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user