refactor(js): apply pr suggestions

pull/4/head
ALI Hamza 2021-03-21 14:41:36 +07:00
parent caaad47c74
commit 92296f6a56
Signed by: hamza
GPG Key ID: 22473A32291F8CB6
16 changed files with 144 additions and 1680 deletions

4
.gitignore vendored

@ -1,4 +1,4 @@
node_modules node_modules
example/node_modules
.gocache .gocache
wasm_exec.js wasm_exec.js
*.wasm

@ -1,4 +0,0 @@
dist/main.wasm
dist/main.js
node_modules
src/api/main.wasm

@ -0,0 +1 @@
dist/main.js

@ -0,0 +1,3 @@
module example
go 1.16

File diff suppressed because it is too large Load Diff

@ -4,17 +4,12 @@
"description": "", "description": "",
"private": true, "private": true,
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "GOROOT=`go env GOROOT` webpack serve" "start": "GOROOT=`go env GOROOT` webpack serve"
}, },
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"webpack": "^5.27.0", "webpack": "^5.27.0",
"webpack-cli": "^4.5.0",
"webpack-dev-server": "^3.11.2" "webpack-dev-server": "^3.11.2"
},
"dependencies": {
"crypto-browserify": "^3.12.0"
} }
} }

@ -0,0 +1,31 @@
package main
import (
"fmt"
"syscall/js"
)
func main() {
fmt.Println("Hello from go-mod-wasm!")
setup()
c := make(chan bool, 0) // To use anything from Go WASM, the program may not exit.
<-c
}
const hello = "Sample value"
func helloName(_ js.Value, args []js.Value) interface{} {
return fmt.Sprintf("Hello, %s!", args[0].String())
}
func setup() {
bridge := js.Global().Get("__go_wasm__")
bridge.Set("__ready__", true)
bridge.Set("hello", hello)
bridge.Set("helloName", js.FuncOf(helloName))
js.Global()
}

@ -0,0 +1,8 @@
import wasm from './api/main.go';
const { hello, helloName } = wasm;
(async () => {
console.log(await hello());
console.log(await helloName("world"));
})()

@ -7,13 +7,13 @@ module.exports = {
compress: true, compress: true,
port: 3000, port: 3000,
}, },
mode: "production", mode: "development",
output: { output: {
filename: 'main.js', filename: 'main.js',
path: path.resolve(__dirname, 'dist'), path: path.resolve(__dirname, 'dist'),
}, },
resolve: { resolve: {
extensions: [".go", ".tsx", ".ts", ".js"], extensions: [".js", ".go"],
fallback: { fallback: {
"fs": false, "fs": false,
"os": false, "os": false,
@ -26,7 +26,6 @@ module.exports = {
"https": false, "https": false,
"stream": false, "stream": false,
"crypto": false, "crypto": false,
"crypto-browserify": require.resolve('crypto-browserify'), //if you want to use this module also don't forget npm i crypto-browserify
} }
}, },
module: { module: {
@ -35,7 +34,7 @@ module.exports = {
test: /\.go$/, test: /\.go$/,
use: [ use: [
{ {
loader: path.resolve(__dirname, '../src/index.js') loader: path.resolve(__dirname, '../../src/index.js')
} }
] ]
} }
@ -43,7 +42,7 @@ module.exports = {
}, },
performance: { performance: {
assetFilter: (file) => { assetFilter: (file) => {
return !/\.wasm/.test(file) return !/(\.wasm|.map)$/.test(file)
} }
}, },
ignoreWarnings: [ ignoreWarnings: [

@ -1,5 +0,0 @@
module example
go 1.16
replace gitea.teamortix.com/Team-Ortix/go-mod-wasm/wasm => /home/hamza/code/misc/go-mod-wasm/wasm

@ -1,14 +0,0 @@
package main
import (
"fmt"
"syscall/js"
)
func main() {
fmt.Println("Hello from go-mod-wasm!")
js.Global().Get("__go_wasm__").Set("__ready__", true)
c := make(chan bool, 0) // in Go Wasm, the program may not exit
<-c
}

@ -1,5 +0,0 @@
import wasm from './api/main.go';
(async () => {
console.log(await wasm.__ready__())
})()

@ -1,6 +1,6 @@
{ {
"name": "go-mod-wasm", "name": "go-mod-wasm",
"version": "0.1.2", "version": "0.1.0",
"description": "A webpack-based configuration to work with wasm using Go.", "description": "A webpack-based configuration to work with wasm using Go.",
"main": "src/index.js", "main": "src/index.js",
"repository": { "repository": {

@ -1,41 +1,42 @@
const g = global || window || self const g = global || window || self;
if (!g.__go_wasm__) { if (!g.__go_wasm__) {
g.__go_wasm__ = {}; g.__go_wasm__ = {};
} }
const maxTime = new Date() const maxTime = 3 * 1000;
maxTime.setSeconds(maxTime.getSeconds() + 3) // if js does not initialize after 3 seconds, we allow it to start anyhow and print a warning
const bridge = g.__go_wasm__; const bridge = g.__go_wasm__;
function sleep() { function sleep() {
return new Promise(requestAnimationFrame) return new Promise(requestAnimationFrame);
} }
export default function (getBytes) { export default function (getBytes) {
let proxy;
async function init() { async function init() {
const go = new g.Go(); const go = new g.Go();
let bytes = await getBytes let bytes = await getBytes;
let result = await WebAssembly.instantiate(bytes, go.importObject); let result = await WebAssembly.instantiate(bytes, go.importObject);
go.run(result.instance); go.run(result.instance);
bridge.__proxy__ = proxy
setTimeout(() => { setTimeout(() => {
if (bridge.__ready__ !== true) { if (bridge.__ready__ !== true) {
console.warn("Golang Wasm Bridge (__go_wasm__.__ready__) still not true after max time") console.warn("Golang Wasm Bridge (__go_wasm__.__ready__) still not true after max time");
} }
}, 3 * 1000) }, maxTime);
} }
init(); init();
let proxy = new Proxy( proxy = new Proxy(
{}, {},
{ {
get: (_, key) => { get: (_, key) => {
return (...args) => { return (...args) => {
return new Promise(async (res, rej) => { return new Promise(async (res, rej) => {
while (bridge.__ready__ !== true) { while (bridge.__ready__ !== true) {
await sleep() await sleep();
} }
if (typeof bridge[key] !== 'function') { if (typeof bridge[key] !== 'function') {
@ -43,12 +44,14 @@ export default function (getBytes) {
return; return;
} }
const returnObj = bridge[key].apply(undefined, args) const returnObj = bridge[key].apply(undefined, args);
if (returnObj.error) { if (returnObj.error instanceof Error) {
rej(returnObj.error) return rej(returnObj.error)
} else {
res(returnObj.result)
} }
if (returnObj.result) return res(returnObj.result);
return res(returnObj)
}) })
}; };
} }

@ -1,21 +1,11 @@
const fs = require("fs") const fs = require("fs/promises");
const { execFileSync } = require("child_process") const util = require("util");
const path = require("path") const execFile = util.promisify(require("child_process").execFile);
const { lookpath } = require("lookpath") const path = require("path");
const { lookpath } = require("lookpath");
const exists = async (dir, file) => {
return new Promise((res, rej) => {
fs.access(path.join(dir, file), fs.constants.F_OK, (err) => {
if (err) {
return res(false)
}
return res(true)
})
})
}
module.exports = function (source) { module.exports = function (source) {
const cb = this.async() const cb = this.async();
const goBin = lookpath("go"); const goBin = lookpath("go");
if (!goBin) { if (!goBin) {
@ -24,62 +14,72 @@ module.exports = function (source) {
if (!process.env.GOROOT) { if (!process.env.GOROOT) {
return cb(new Error("Could not find GOROOT in environment.\n" + return cb(new Error("Could not find GOROOT in environment.\n" +
"Please try adding this to your script:\nGOROOT=`go env GOROOT` npm run ...")) "Please try adding this to your script:\n" +
"GOROOT=`go env GOROOT` npm run ..."));
} }
const parent = path.dirname(this.resourcePath) const parent = path.dirname(this.resourcePath);
const outFile = this.resourcePath.slice(0, -2) + "wasm" const outFile = this.resourcePath.slice(0, -2) + "wasm";
let modDir = parent let modDir = parent;
let found = false;
const opts = { const opts = {
cwd: parent, cwd: parent,
env: { env: {
GOPATH: process.env.GOPATH, GOPATH: process.env.GOPATH || path.join(process.env.HOME, "go"),
GOROOT: process.env.GOROOT, GOROOT: process.env.GOROOT,
GOCACHE: path.join(__dirname, ".gocache"), GOCACHE: path.join(__dirname, ".gocache"),
GOOS: "js", GOOS: "js",
GOARCH: "wasm", GOARCH: "wasm",
} },
}; };
(async () => { (async () => {
const root = path.resolve(path.sep) let found = false;
const root = path.resolve(path.sep);
while (path.resolve(modDir) != root) { while (path.resolve(modDir) != root) {
if (!(await exists(modDir, 'go.mod'))) { found = await fs.access(path.join(modDir, 'go.mod')).then(() => true).catch(() => false);
modDir = path.join(modDir, '..'); if (found) {
} else {
found = true;
break; break;
} }
modDir = path.join(modDir, "..");
} }
if (!found) { if (!found) {
return cb(new Error("Could not find go.mod in any parent directory of " + this.resourcePath)) return cb(new Error("Could not find go.mod in any parent directory of " + this.resourcePath));
} }
try { const wasmOrigPath = path.join(process.env.GOROOT, "misc", "wasm", "wasm_exec.js");
execFileSync("go", ["build", "-o", outFile, parent], opts) const wasmSavePath = path.join(__dirname, 'wasm_exec.js');
} catch (e) { const errorPaths = ["\t" + wasmOrigPath, "\t" + wasmSavePath];
return cb(e) 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 wasmOrigPath = path.join(process.env.GOROOT, "misc", "wasm", "wasm_exec.js")
const wasmEmitPath = path.join(__dirname, 'wasm_exec.js') const res = await execFile("go", ["build", "-o", outFile, parent], opts)
if (!(await exists(__dirname, 'wasm_exec.js'))) { .then(() => true)
fs.copyFileSync(wasmOrigPath, wasmEmitPath) .catch(e => e);
if (res instanceof Error) {
return cb(e);
} }
const contents = fs.readFileSync(outFile)
fs.unlinkSync(outFile)
const emitPath = path.basename(outFile) found = await fs.access(wasmSavePath).then(() => true).catch(() => false);
this.emitFile(emitPath, contents) if (!found) fs.copyFile(wasmOrigPath, wasmSavePath);
this.addContextDependency(modDir)
const contents = await fs.readFile(outFile);
fs.unlink(outFile);
const emitPath = path.basename(outFile);
this.emitFile(emitPath, contents);
this.addContextDependency(modDir);
cb(null, cb(null,
`require('!${wasmEmitPath}') `require('!${wasmSavePath}');
import goWasm from '${path.join(__dirname, 'bridge.js')}'; import goWasm from '${path.join(__dirname, 'bridge.js')}';
const wasm = fetch('${emitPath}').then(response => response.arrayBuffer()) const wasm = fetch('${emitPath}').then(response => response.arrayBuffer());
export default goWasm(wasm)`) export default goWasm(wasm);`);
})() })();
} }