feat(js): add basic webpack loader with example

master
ALI Hamza 2021-03-21 00:32:11 +07:00
parent 2946363e88
commit f19165c53d
Signed by: hamza
GPG Key ID: 22473A32291F8CB6
14 changed files with 4756 additions and 2 deletions

3
.gitignore vendored

@ -0,0 +1,3 @@
node_modules
example/node_modules
.gocache

@ -0,0 +1,61 @@
const g = global || window || self
if (!g.__go_wasm__) {
g.__go_wasm__ = {};
}
const maxTime = new Date()
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__;
function sleep() {
return new Promise(requestAnimationFrame)
}
export default function (getBytes) {
async function init() {
const go = new g.Go();
let bytes = await getBytes
let result = await WebAssembly.instantiate(bytes, go.importObject);
go.run(result.instance);
setTimeout(() => {
if (bridge.__ready__ !== true) {
console.warn("Golang Wasm Bridge (__go_wasm__.__ready__) still not true after max time")
}
}, 3 * 1000)
}
init();
let proxy = new Proxy(
{},
{
get: (_, key) => {
return (...args) => {
return new Promise(async (res, rej) => {
while (bridge.__ready__ !== true) {
console.log("waiting")
await sleep()
}
console.log("done!")
if (typeof bridge[key] !== 'function') {
res(bridge[key]);
return;
}
const returnObj = bridge[key].apply(undefined, args)
if (returnObj.error) {
rej(returnObj.error)
} else {
res(returnObj.result)
}
})
};
}
}
);
return proxy;
}

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Example</title>
</head>
<body>
<script src="main.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

@ -0,0 +1,5 @@
module example
go 1.16
require gitea.teamortix.com/Team-Ortix/go-mod-wasm/wasm v0.0.0-20210320172655-205806929b8f

@ -0,0 +1,6 @@
gitea.teamortix.com/Team-Ortix/go-mod-wasm/wasm v0.0.0-20210320160445-87f4b612f08a h1:yP+ZWeFYr26sQbkjOZKlJvDdPNzxsdK3T9WeDDpRZ3Y=
gitea.teamortix.com/Team-Ortix/go-mod-wasm/wasm v0.0.0-20210320160445-87f4b612f08a/go.mod h1:aXGSS5eQ84RFpINcZVu4y/MeaguTCZM9RvZct1OtsE0=
gitea.teamortix.com/Team-Ortix/go-mod-wasm/wasm v0.0.0-20210320171600-df451aa899a5 h1:1obgUBM+Sx9Hi+2nv05MvPBR8qu/0ZDCRs8JIky8U2o=
gitea.teamortix.com/Team-Ortix/go-mod-wasm/wasm v0.0.0-20210320171600-df451aa899a5/go.mod h1:aXGSS5eQ84RFpINcZVu4y/MeaguTCZM9RvZct1OtsE0=
gitea.teamortix.com/Team-Ortix/go-mod-wasm/wasm v0.0.0-20210320172655-205806929b8f h1:A1ImTmMMUKGRvxCXO+hQh92DAsRz37ioQGlg8dpxFjc=
gitea.teamortix.com/Team-Ortix/go-mod-wasm/wasm v0.0.0-20210320172655-205806929b8f/go.mod h1:aXGSS5eQ84RFpINcZVu4y/MeaguTCZM9RvZct1OtsE0=

File diff suppressed because it is too large Load Diff

@ -0,0 +1,20 @@
{
"name": "example",
"version": "1.0.0",
"description": "",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "GOROOT=`go env GOROOT` webpack"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^5.27.0",
"webpack-cli": "^4.5.0"
},
"dependencies": {
"crypto-browserify": "^3.12.0",
"loader-utils": "^2.0.0"
}
}

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

@ -0,0 +1,14 @@
package main
import (
"fmt"
"gitea.teamortix.com/Team-Ortix/go-mod-wasm/wasm"
)
func main() {
c := make(chan bool, 0)
fmt.Println("Hello Go!")
wasm.Ready()
<-c
}

@ -0,0 +1,39 @@
const path = require('path');
module.exports = {
entry: './src/index.js',
mode: "production",
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
},
resolve: {
extensions: [".go", ".tsx", ".ts", ".js"],
fallback: {
"fs": false,
"os": false,
"util": false,
"tls": false,
"net": false,
"path": false,
"zlib": false,
"http": false,
"https": false,
"stream": 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: {
rules: [
{
test: /\.go$/,
use: [
{
loader: path.resolve(__dirname, '../index.js')
}
]
}
]
},
};

@ -0,0 +1,78 @@
const fs = require("fs")
const { execSync, execFileSync } = require("child_process")
const path = require("path")
const { lookpath } = require("lookpath")
const { executionAsyncResource } = require("async_hooks")
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) {
const cb = this.async()
const goBin = lookpath("go");
if (!goBin) {
return cb(new Error("go bin not found in path."));
}
const parent = path.dirname(this.resourcePath)
const outFile = this.resourcePath.slice(0, -2) + "wasm"
let modDir = parent
let found = false;
const opts = {
cwd: parent,
env: {
GOPATH: process.env.GOPATH,
GOROOT: process.env.GOROOT,
GOCACHE: path.join(__dirname, ".gocache"),
GOOS: "js",
GOARCH: "wasm",
}
};
(async () => {
const root = path.resolve(path.sep)
while (path.resolve(modDir) != root) {
if (!(await exists(modDir, 'go.mod'))) {
modDir = path.join(modDir, '..');
} else {
found = true;
break;
}
}
if (!found) {
return cb(new Error("Could not find go.mod in any parent directory of " + this.resourcePath))
}
try {
execFileSync("go", ["build", "-o", outFile, parent], opts)
} catch (e) {
return cb(e)
}
const wasmPath = path.join(process.env.GOROOT, "misc", "wasm", "wasm_exec.js")
let contents = fs.readFileSync(outFile)
fs.unlinkSync(outFile)
const emitPath = path.basename(outFile)
this.emitFile(emitPath, contents)
this.addContextDependency(modDir)
cb(null,
`require('!${wasmPath}')
import goWasm from '${path.join(__dirname, 'bridge.js')}';
const wasm = fetch('${emitPath}').then(response => response.arrayBuffer())
export default goWasm(wasm)`)
})()
}

1264
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -18,5 +18,9 @@
"webpack"
],
"author": "hhhapz, chanbakjsd",
"license": "MIT"
}
"license": "MIT",
"dependencies": {
"lookpath": "^1.2.0",
"webpack": "^5.27.0"
}
}