feat(js): add basic webpack loader with example
parent
2946363e88
commit
f19165c53d
@ -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)`)
|
||||
})()
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue