Skip to content

Commit

Permalink
feat: support wasi target on browser (#757)
Browse files Browse the repository at this point in the history
  • Loading branch information
Brooooooklyn authored Jan 9, 2024
1 parent ed4e9aa commit f39eec0
Show file tree
Hide file tree
Showing 37 changed files with 827 additions and 183 deletions.
3 changes: 3 additions & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ parserOptions:
ecmaVersion: latest
sourceType: module

globals:
globalThis: true

env:
browser: true
es6: true
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@
"devDependencies": {
"@emnapi/core": "^0.45.0",
"@emnapi/runtime": "^0.45.0",
"@napi-rs/cli": "^3.0.0-alpha.30",
"@napi-rs/cli": "^3.0.0-alpha.33",
"@swc-node/core": "^1.10.6",
"@swc-node/register": "^1.6.8",
"@swc/core": "^1.3.101",
"@taplo/cli": "^0.5.2",
"@tybys/wasm-util": "^0.8.1",
"@types/node": "^20.10.5",
"@typescript-eslint/eslint-plugin": "^6.16.0",
"@typescript-eslint/parser": "^6.16.0",
Expand All @@ -45,6 +46,7 @@
"husky": "^8.0.3",
"lerna": "^8.0.1",
"lint-staged": "^15.2.0",
"memfs-browser": "^3.4.13000",
"npm-run-all": "^4.1.5",
"prettier": "^3.1.1",
"ts-node": "^10.9.2",
Expand Down
77 changes: 77 additions & 0 deletions packages/argon2/argon2.wasi-browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { instantiateNapiModuleSync as __emnapiInstantiateNapiModuleSync } from '@emnapi/core'
import { getDefaultContext as __emnapiGetDefaultContext } from '@emnapi/runtime'
import { WASI as __WASI } from '@tybys/wasm-util'
import { Volume as __Volume, createFsFromVolume as __createFsFromVolume } from 'memfs-browser'

import __wasmUrl from './argon2.wasm32-wasi.wasm?url'

const __fs = __createFsFromVolume(
__Volume.fromJSON({
'/': null,
}),
)

const __wasi = new __WASI({
version: 'preview1',
fs: __fs,
})

const __emnapiContext = __emnapiGetDefaultContext()

const __sharedMemory = new WebAssembly.Memory({
initial: 1024,
maximum: 10240,
shared: true,
})

const __wasmFile = await fetch(__wasmUrl).then((res) => res.arrayBuffer())

const {
instance: __napiInstance,
module: __wasiModule,
napiModule: __napiModule,
} = __emnapiInstantiateNapiModuleSync(__wasmFile, {
context: __emnapiContext,
asyncWorkPoolSize: 4,
wasi: __wasi,
onCreateWorker() {
return new Worker(new URL('./wasi-worker-browser.mjs', import.meta.url), {
type: 'module',
})
},
overwriteImports(importObject) {
importObject.env = {
...importObject.env,
...importObject.napi,
...importObject.emnapi,
memory: __sharedMemory,
}
return importObject
},
beforeInit({ instance }) {
__napi_rs_initialize_modules(instance)
},
})

function __napi_rs_initialize_modules(__napiInstance) {
__napiInstance.exports['__napi_register__Algorithm_0']?.()
__napiInstance.exports['__napi_register__Version_1']?.()
__napiInstance.exports['__napi_register__Options_struct_2']?.()
__napiInstance.exports['__napi_register__HashTask_impl_3']?.()
__napiInstance.exports['__napi_register__hash_4']?.()
__napiInstance.exports['__napi_register__hash_sync_5']?.()
__napiInstance.exports['__napi_register__RawHashTask_impl_6']?.()
__napiInstance.exports['__napi_register__hash_raw_7']?.()
__napiInstance.exports['__napi_register__hash_raw_sync_8']?.()
__napiInstance.exports['__napi_register__VerifyTask_impl_9']?.()
__napiInstance.exports['__napi_register__verify_10']?.()
__napiInstance.exports['__napi_register__verify_sync_11']?.()
}
export const Algorithm = __napiModule.exports.Algorithm
export const hash = __napiModule.exports.hash
export const hashRaw = __napiModule.exports.hashRaw
export const hashRawSync = __napiModule.exports.hashRawSync
export const hashSync = __napiModule.exports.hashSync
export const verify = __napiModule.exports.verify
export const verifySync = __napiModule.exports.verifySync
export const Version = __napiModule.exports.Version
32 changes: 19 additions & 13 deletions packages/argon2/argon2.wasi.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ const __wasi = new __nodeWASI({
version: 'preview1',
env: process.env,
preopens: {
'/': '/'
}
'/': '/',
},
})

const __emnapiContext = __emnapiGetDefaultContext()
Expand All @@ -33,13 +33,19 @@ if (!__nodeFs.existsSync(__wasmFilePath)) {
try {
__wasmFilePath = __nodePath.resolve('@node-rs/argon2-wasm32-wasi')
} catch {
throw new Error('Cannot find argon2.wasm32-wasi.wasm file, and @node-rs/argon2-wasm32-wasi package is not installed.')
throw new Error(
'Cannot find argon2.wasm32-wasi.wasm file, and @node-rs/argon2-wasm32-wasi package is not installed.',
)
}
}

const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule } = __emnapiInstantiateNapiModuleSync(__nodeFs.readFileSync(__wasmFilePath), {
const {
instance: __napiInstance,
module: __wasiModule,
napiModule: __napiModule,
} = __emnapiInstantiateNapiModuleSync(__nodeFs.readFileSync(__wasmFilePath), {
context: __emnapiContext,
asyncWorkPoolSize: (function() {
asyncWorkPoolSize: (function () {
const threadsSizeFromEnv = Number(process.env.NAPI_RS_ASYNC_WORK_POOL_SIZE ?? process.env.UV_THREADPOOL_SIZE)
// NaN > 0 is false
if (threadsSizeFromEnv > 0) {
Expand All @@ -66,7 +72,7 @@ const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule
},
beforeInit({ instance }) {
__napi_rs_initialize_modules(instance)
}
},
})

function __napi_rs_initialize_modules(__napiInstance) {
Expand All @@ -83,11 +89,11 @@ function __napi_rs_initialize_modules(__napiInstance) {
__napiInstance.exports['__napi_register__verify_10']?.()
__napiInstance.exports['__napi_register__verify_sync_11']?.()
}
module.exports.Algorithm = __napiModule.exports.Algorithm,
module.exports.hash = __napiModule.exports.hash,
module.exports.hashRaw = __napiModule.exports.hashRaw,
module.exports.hashRawSync = __napiModule.exports.hashRawSync,
module.exports.hashSync = __napiModule.exports.hashSync,
module.exports.verify = __napiModule.exports.verify,
module.exports.verifySync = __napiModule.exports.verifySync,
module.exports.Algorithm = __napiModule.exports.Algorithm
module.exports.hash = __napiModule.exports.hash
module.exports.hashRaw = __napiModule.exports.hashRaw
module.exports.hashRawSync = __napiModule.exports.hashRawSync
module.exports.hashSync = __napiModule.exports.hashSync
module.exports.verify = __napiModule.exports.verify
module.exports.verifySync = __napiModule.exports.verifySync
module.exports.Version = __napiModule.exports.Version
9 changes: 7 additions & 2 deletions packages/argon2/npm/wasm32-wasi/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"files": [
"argon2.wasm32-wasi.wasm",
"argon2.wasi.cjs",
"wasi-worker.mjs"
"argon2.wasi-browser.js",
"wasi-worker.mjs",
"wasi-worker-browser.mjs"
],
"description": "RustCrypto: Argon2 binding for Node.js",
"keywords": [
Expand All @@ -35,8 +37,11 @@
"type": "git",
"url": "git+https://github.com/napi-rs/node-rs.git"
},
"browser": "argon2.wasi-browser.js",
"dependencies": {
"@emnapi/core": "^0.45.0",
"@emnapi/runtime": "^0.45.0"
"@emnapi/runtime": "^0.45.0",
"@tybys/wasm-util": "^0.8.1",
"memfs-browser": "^3.4.13000"
}
}
2 changes: 1 addition & 1 deletion packages/argon2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"version": "napi version"
},
"devDependencies": {
"@napi-rs/cli": "^3.0.0-alpha.30",
"@napi-rs/cli": "^3.0.0-alpha.33",
"argon2": "^0.31.2",
"cross-env": "^7.0.3"
}
Expand Down
37 changes: 37 additions & 0 deletions packages/argon2/wasi-worker-browser.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { instantiateNapiModuleSync, MessageHandler } from '@emnapi/core'
import { WASI } from '@tybys/wasm-util'
import { Volume, createFsFromVolume } from 'memfs-browser'

const fs = createFsFromVolume(
Volume.fromJSON({
'/': null,
}),
)

const handler = new MessageHandler({
onLoad({ wasmModule, wasmMemory }) {
const wasi = new WASI({
fs,
print: function () {
// eslint-disable-next-line no-console
console.log.apply(console, arguments)
},
})
return instantiateNapiModuleSync(wasmModule, {
childThread: true,
wasi,
overwriteImports(importObject) {
importObject.env = {
...importObject.env,
...importObject.napi,
...importObject.emnapi,
memory: wasmMemory,
}
},
})
},
})

globalThis.onmessage = function (e) {
handler.handle(e)
}
38 changes: 19 additions & 19 deletions packages/argon2/wasi-worker.mjs
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
import fs from "node:fs";
import { createRequire } from "node:module";
import { parentPort, Worker } from "node:worker_threads";
import fs from 'node:fs'
import { createRequire } from 'node:module'
import { parentPort, Worker } from 'node:worker_threads'

import { instantiateNapiModuleSync, MessageHandler } from "@emnapi/core";
import { WASI } from "@tybys/wasm-util";
import { instantiateNapiModuleSync, MessageHandler } from '@emnapi/core'
import { WASI } from '@tybys/wasm-util'

const require = createRequire(import.meta.url);
const require = createRequire(import.meta.url)

if (parentPort) {
parentPort.on("message", (data) => {
globalThis.onmessage({ data });
});
parentPort.on('message', (data) => {
globalThis.onmessage({ data })
})
}

Object.assign(globalThis, {
self: globalThis,
require,
Worker,
importScripts: function (f) {
;(0, eval)(fs.readFileSync(f, "utf8") + "//# sourceURL=" + f);
;(0, eval)(fs.readFileSync(f, 'utf8') + '//# sourceURL=' + f)
},
postMessage: function (msg) {
if (parentPort) {
parentPort.postMessage(msg);
parentPort.postMessage(msg)
}
},
});
})

const handler = new MessageHandler({
onLoad({ wasmModule, wasmMemory }) {
const wasi = new WASI({ fs });
const wasi = new WASI({ fs })

return instantiateNapiModuleSync(wasmModule, {
childThread: true,
Expand All @@ -39,13 +39,13 @@ const handler = new MessageHandler({
...importObject.env,
...importObject.napi,
...importObject.emnapi,
memory: wasmMemory
};
memory: wasmMemory,
}
},
});
})
},
});
})

globalThis.onmessage = function (e) {
handler.handle(e);
};
handler.handle(e)
}
74 changes: 74 additions & 0 deletions packages/bcrypt/bcrypt.wasi-browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { instantiateNapiModuleSync as __emnapiInstantiateNapiModuleSync } from '@emnapi/core'
import { getDefaultContext as __emnapiGetDefaultContext } from '@emnapi/runtime'
import { WASI as __WASI } from '@tybys/wasm-util'
import { Volume as __Volume, createFsFromVolume as __createFsFromVolume } from 'memfs-browser'

import __wasmUrl from './bcrypt.wasm32-wasi.wasm?url'

const __fs = __createFsFromVolume(
__Volume.fromJSON({
'/': null,
}),
)

const __wasi = new __WASI({
version: 'preview1',
fs: __fs,
})

const __emnapiContext = __emnapiGetDefaultContext()

const __sharedMemory = new WebAssembly.Memory({
initial: 1024,
maximum: 10240,
shared: true,
})

const __wasmFile = await fetch(__wasmUrl).then((res) => res.arrayBuffer())

const {
instance: __napiInstance,
module: __wasiModule,
napiModule: __napiModule,
} = __emnapiInstantiateNapiModuleSync(__wasmFile, {
context: __emnapiContext,
asyncWorkPoolSize: 4,
wasi: __wasi,
onCreateWorker() {
return new Worker(new URL('./wasi-worker-browser.mjs', import.meta.url), {
type: 'module',
})
},
overwriteImports(importObject) {
importObject.env = {
...importObject.env,
...importObject.napi,
...importObject.emnapi,
memory: __sharedMemory,
}
return importObject
},
beforeInit({ instance }) {
__napi_rs_initialize_modules(instance)
},
})

function __napi_rs_initialize_modules(__napiInstance) {
__napiInstance.exports['__napi_register__HashTask_impl_0']?.()
__napiInstance.exports['__napi_register__SaltTask_impl_1']?.()
__napiInstance.exports['__napi_register__VerifyTask_impl_2']?.()
__napiInstance.exports['__napi_register__DEFAULT_COST_3']?.()
__napiInstance.exports['__napi_register__gen_salt_sync_4']?.()
__napiInstance.exports['__napi_register__gen_salt_js_5']?.()
__napiInstance.exports['__napi_register__hash_sync_6']?.()
__napiInstance.exports['__napi_register__hash_7']?.()
__napiInstance.exports['__napi_register__verify_sync_8']?.()
__napiInstance.exports['__napi_register__verify_9']?.()
}
export const DEFAULT_COST = __napiModule.exports.DEFAULT_COST
export const genSalt = __napiModule.exports.genSalt
export const genSaltSync = __napiModule.exports.genSaltSync
export const hash = __napiModule.exports.hash
export const hashSync = __napiModule.exports.hashSync
export const verify = __napiModule.exports.verify
export const verifySync = __napiModule.exports.verifySync
Loading

0 comments on commit f39eec0

Please sign in to comment.