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