golang-wasm/src/index.js

86 lines
2.9 KiB
JavaScript

const fs = require("fs/promises");
const util = require("util");
const execFile = util.promisify(require("child_process").execFile);
const path = require("path");
const { lookpath } = require("lookpath");
module.exports = function (source) {
const cb = this.async();
const goBin = lookpath("go");
if (!goBin) {
return cb(new Error("go bin not found in path."));
}
if (!process.env.GOROOT) {
return cb(new Error("Could not find GOROOT in environment.\n" +
"Please try adding this to your script:\n" +
"GOROOT=`go env GOROOT` npm run ..."));
}
const parent = path.dirname(this.resourcePath);
const outFile = this.resourcePath.slice(0, -2) + "wasm";
let modDir = parent;
const opts = {
cwd: parent,
env: {
GOPATH: process.env.GOPATH || path.join(process.env.HOME, "go"),
GOROOT: process.env.GOROOT,
GOCACHE: path.join(__dirname, ".gocache"),
GOOS: "js",
GOARCH: "wasm",
},
};
(async () => {
let found = false;
const root = path.resolve(path.sep);
while (path.resolve(modDir) != root) {
found = await fs.access(path.join(modDir, 'go.mod')).then(() => true).catch(() => false);
if (found) {
break;
}
modDir = path.join(modDir, "..");
}
if (!found) {
return cb(new Error("Could not find go.mod in any parent directory of " + this.resourcePath));
}
const wasmOrigPath = path.join(process.env.GOROOT, "misc", "wasm", "wasm_exec.js");
const wasmSavePath = path.join(__dirname, 'wasm_exec.js');
const errorPaths = ["\t" + wasmOrigPath, "\t" + wasmSavePath];
if (!(await fs.access(wasmOrigPath).then(() => true).catch(() => false)) &&
!(await fs.access(wasmSavePath).then(() => true).catch(() => false))) {
return cb(new Error("Could not find wasm_exec.js file. Invalid GOROOT? Searched paths:\n" +
errorPaths.join(",\n") + "\n"));
}
const res = await execFile("go", ["build", "-o", outFile, parent], opts)
.then(() => true)
.catch(e => e);
if (res instanceof Error) {
return cb(e);
}
found = await fs.access(wasmSavePath).then(() => true).catch(() => false);
if (!found) fs.copyFile(wasmOrigPath, wasmSavePath);
const contents = await fs.readFile(outFile);
fs.unlink(outFile);
const emitPath = path.basename(outFile);
this.emitFile(emitPath, contents);
this.addContextDependency(modDir);
cb(null,
`require('!${wasmSavePath}');
import goWasm from '${path.join(__dirname, 'bridge.js')}';
const wasm = fetch('${emitPath}').then(response => response.arrayBuffer());
export default goWasm(wasm);`);
})();
}