wasm-bindgen-lite 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/cli/build.js CHANGED
@@ -11,16 +11,47 @@ function exec(cmd, options = {}) {
11
11
  }
12
12
  }
13
13
 
14
- function runCargoBuild({ crateDir, release, simd }) {
14
+ function resolveTargetDir(crateDir) {
15
+ try {
16
+ const raw = execSync('cargo metadata --format-version 1 --no-deps', {
17
+ cwd: crateDir,
18
+ stdio: ['ignore', 'pipe', 'inherit'],
19
+ }).toString()
20
+ const meta = JSON.parse(raw)
21
+ if (meta?.target_directory) return meta.target_directory
22
+ } catch {
23
+ console.warn(
24
+ 'Warning: failed to read cargo metadata, defaulting to local target dir'
25
+ )
26
+ }
27
+ return join(crateDir, 'target')
28
+ }
29
+
30
+ function runCargoBuild({ crateDir, release, simd, targetDir, features }) {
15
31
  const args = ['build', '--target', 'wasm32-unknown-unknown']
16
32
  if (release) args.push('--release')
33
+ if (features) {
34
+ args.push('--features', features)
35
+ }
17
36
 
18
37
  const env = { ...process.env }
38
+
39
+ if (release) {
40
+ // Explicitly force opt-level 3 for fastest execution
41
+ env.CARGO_PROFILE_RELEASE_OPT_LEVEL = '3'
42
+ env.CARGO_PROFILE_RELEASE_PANIC = 'abort'
43
+ env.CARGO_PROFILE_RELEASE_CODEGEN_UNITS = '1'
44
+ env.CARGO_PROFILE_RELEASE_LTO = 'fat'
45
+ }
46
+
19
47
  if (simd) {
20
- const base = process.env.RUSTFLAGS || ''
48
+ const base = env.RUSTFLAGS || ''
21
49
  const extra = '-C target-feature=+simd128'
22
50
  env.RUSTFLAGS = [base, extra].filter(Boolean).join(' ').trim()
23
51
  }
52
+ if (targetDir) {
53
+ env.CARGO_TARGET_DIR = targetDir
54
+ }
24
55
 
25
56
  exec(`cargo ${args.join(' ')}`, {
26
57
  cwd: crateDir,
@@ -28,18 +59,17 @@ function runCargoBuild({ crateDir, release, simd }) {
28
59
  })
29
60
  }
30
61
 
31
- function wasmPath({ crateDir, release, wasmFileStem }) {
62
+ function wasmPath({ targetDir, release, wasmFileStem }) {
32
63
  const profile = release ? 'release' : 'debug'
33
64
  return join(
34
- crateDir,
35
- 'target',
65
+ targetDir,
36
66
  'wasm32-unknown-unknown',
37
67
  profile,
38
68
  `${wasmFileStem}.wasm`
39
69
  )
40
70
  }
41
71
 
42
- function maybeRunWasmOpt(wasmFile, wasmOpt) {
72
+ function maybeRunWasmOpt(wasmFile, wasmOpt, release) {
43
73
  if (wasmOpt.mode === 'off') return
44
74
  if (wasmOpt.mode === 'auto') {
45
75
  try {
@@ -49,7 +79,24 @@ function maybeRunWasmOpt(wasmFile, wasmOpt) {
49
79
  }
50
80
  }
51
81
 
52
- const args = ['wasm-opt', ...wasmOpt.args, wasmFile, '-o', wasmFile]
82
+ const args = ['wasm-opt']
83
+
84
+ if (release) {
85
+ // Only strip metadata and debug info for fastest performance
86
+ args.push('--strip-debug')
87
+ args.push('--strip-producers')
88
+ args.push('--strip-target-features')
89
+
90
+ // We EXPLICITLY avoid -O passes here to maintain absolute fastest speed
91
+ // unless the user provided specific args
92
+ if (wasmOpt.args.length > 0) {
93
+ args.push(...wasmOpt.args)
94
+ }
95
+ } else {
96
+ args.push(...wasmOpt.args)
97
+ }
98
+
99
+ args.push(wasmFile, '-o', wasmFile)
53
100
  exec(args.join(' '))
54
101
  }
55
102
 
@@ -62,6 +109,7 @@ export function buildArtifacts({
62
109
  release,
63
110
  wasmOpt,
64
111
  }) {
112
+ const targetDir = resolveTargetDir(crateDir)
65
113
  mkdirSync(outDir, { recursive: true })
66
114
  const wasmOutDir = join(outDir, 'wasm')
67
115
  mkdirSync(wasmOutDir, { recursive: true })
@@ -72,9 +120,13 @@ export function buildArtifacts({
72
120
  const label = isSimd ? 'SIMD' : 'baseline'
73
121
  console.log(`Building ${label} wasm...`)
74
122
 
75
- runCargoBuild({ crateDir, release, simd: isSimd })
123
+ const simdFeatures = isSimd ? targets.simdFeatures : null
124
+ const baselineFeatures = !isSimd ? targets.baselineFeatures : null
125
+ const features = simdFeatures || baselineFeatures
126
+
127
+ runCargoBuild({ crateDir, release, simd: isSimd, targetDir, features })
76
128
 
77
- const built = wasmPath({ crateDir, release, wasmFileStem })
129
+ const built = wasmPath({ targetDir, release, wasmFileStem })
78
130
  const dest = join(wasmOutDir, `${artifactBaseName}.${suffix}.wasm`)
79
131
 
80
132
  copyFileSync(built, dest)
package/src/cli/config.js CHANGED
@@ -21,7 +21,7 @@ const DEFAULT_CONFIG = {
21
21
  inline: true,
22
22
  types: true,
23
23
  },
24
- custom: null, // path to custom JS file to include and re-export
24
+ custom: null, // path to custom JS/TS file to include and re-export
25
25
  },
26
26
  exports: [
27
27
  {
@@ -138,6 +138,8 @@ export function loadConfigFromCli(cliOpts = {}) {
138
138
  typeof cliOpts.simd === 'boolean'
139
139
  ? cliOpts.simd
140
140
  : (fileConfig.targets?.simd ?? DEFAULT_CONFIG.targets.simd),
141
+ simdFeatures: fileConfig.targets?.simdFeatures ?? null,
142
+ baselineFeatures: fileConfig.targets?.baselineFeatures ?? null,
141
143
  },
142
144
 
143
145
  inline:
@@ -182,6 +184,12 @@ export function loadConfigFromCli(cliOpts = {}) {
182
184
  version:
183
185
  fileConfig.wasmDelivery?.version ?? fileConfig.version ?? 'latest',
184
186
  },
187
+
188
+ // SIMD variant configuration
189
+ simd: fileConfig.simd ?? null,
190
+
191
+ // Benchmark configuration
192
+ bench: fileConfig.bench ?? null,
185
193
  }
186
194
 
187
195
  return config
package/src/cli/emit.js CHANGED
@@ -1,8 +1,11 @@
1
1
  import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'
2
- import { join } from 'node:path'
2
+ import { join, extname } from 'node:path'
3
+ import { createRequire } from 'node:module'
3
4
  import { fileURLToPath } from 'node:url'
4
5
 
5
6
  const UTIL_PATH = fileURLToPath(new URL('../js/util.js', import.meta.url))
7
+ const require = createRequire(import.meta.url)
8
+ const TS_EXTS = new Set(['.ts', '.tsx', '.cts', '.mts'])
6
9
 
7
10
  export function buildWrapperIR(exportsList) {
8
11
  return exportsList.map((entry) => {
@@ -112,51 +115,55 @@ export function createCore({ exportsList, autoInit, stream }) {
112
115
  b.line('}')
113
116
  b.blank()
114
117
 
115
- b.line('function scalarSize(type) {')
116
- b.indent(() => {
117
- b.line('switch (type) {')
118
- b.line(' case "f64": return 8;')
119
- b.line(' case "f32":')
120
- b.line(' case "i32":')
121
- b.line(' case "u32": return 4;')
122
- b.line(' case "i16":')
123
- b.line(' case "u16": return 2;')
124
- b.line(' case "i8":')
125
- b.line(' case "u8": return 1;')
126
- b.line(' case "u32_array":')
127
- b.line(' case "i32_array":')
128
- b.line(' case "f32_array": return 1024 * 1024;')
129
- b.line(' default: return 0;')
118
+ const needsDecoders = wrappersIR.some((w) => w.returnType !== 'bytes')
119
+
120
+ if (needsDecoders) {
121
+ b.line('function scalarSize(type) {')
122
+ b.indent(() => {
123
+ b.line('switch (type) {')
124
+ b.line(' case "f64": return 8;')
125
+ b.line(' case "f32":')
126
+ b.line(' case "i32":')
127
+ b.line(' case "u32": return 4;')
128
+ b.line(' case "i16":')
129
+ b.line(' case "u16": return 2;')
130
+ b.line(' case "i8":')
131
+ b.line(' case "u8": return 1;')
132
+ b.line(' case "u32_array":')
133
+ b.line(' case "i32_array":')
134
+ b.line(' case "f32_array": return 1024 * 1024;')
135
+ b.line(' default: return 0;')
136
+ b.line('}')
137
+ })
130
138
  b.line('}')
131
- })
132
- b.line('}')
133
- b.blank()
139
+ b.blank()
134
140
 
135
- b.line('function decodeReturn(view, type) {')
136
- b.indent(() => {
137
- b.line('switch (type) {')
138
- b.line(' case "f32": return view.getFloat32(0, true);')
139
- b.line(' case "f64": return view.getFloat64(0, true);')
140
- b.line(' case "i32": return view.getInt32(0, true);')
141
- b.line(' case "u32": return view.getUint32(0, true);')
142
- b.line(' case "i16": return view.getInt16(0, true);')
143
- b.line(' case "u16": return view.getUint16(0, true);')
144
- b.line(' case "i8": return view.getInt8(0);')
145
- b.line(' case "u8": return view.getUint8(0);')
146
- b.line(
147
- ' case "u32_array": return new Uint32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));'
148
- )
149
- b.line(
150
- ' case "i32_array": return new Int32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));'
151
- )
152
- b.line(
153
- ' case "f32_array": return new Float32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));'
154
- )
155
- b.line(' default: return null;')
141
+ b.line('function decodeReturn(view, type) {')
142
+ b.indent(() => {
143
+ b.line('switch (type) {')
144
+ b.line(' case "f32": return view.getFloat32(0, true);')
145
+ b.line(' case "f64": return view.getFloat64(0, true);')
146
+ b.line(' case "i32": return view.getInt32(0, true);')
147
+ b.line(' case "u32": return view.getUint32(0, true);')
148
+ b.line(' case "i16": return view.getInt16(0, true);')
149
+ b.line(' case "u16": return view.getUint16(0, true);')
150
+ b.line(' case "i8": return view.getInt8(0);')
151
+ b.line(' case "u8": return view.getUint8(0);')
152
+ b.line(
153
+ ' case "u32_array": return new Uint32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));'
154
+ )
155
+ b.line(
156
+ ' case "i32_array": return new Int32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));'
157
+ )
158
+ b.line(
159
+ ' case "f32_array": return new Float32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));'
160
+ )
161
+ b.line(' default: return null;')
162
+ b.line('}')
163
+ })
156
164
  b.line('}')
157
- })
158
- b.line('}')
159
- b.blank()
165
+ b.blank()
166
+ }
160
167
 
161
168
  b.line('function callWasm(abi, input, outLen, reuse) {')
162
169
  b.indent(() => {
@@ -445,7 +452,10 @@ export function code() {
445
452
  }
446
453
 
447
454
  export function createLoaderTypes({ exportFrom }) {
448
- return `export function init(imports?: WebAssembly.Imports): Promise<void>;
455
+ return `export interface InitOptions {
456
+ backend?: 'auto' | 'simd' | 'base';
457
+ }
458
+ export function init(imports?: WebAssembly.Imports, opts?: InitOptions): Promise<void>;
449
459
  export * from "${exportFrom}";
450
460
  `
451
461
  }
@@ -457,14 +467,17 @@ export function createLoader({ exportFrom, autoInit, getBytesSrc }) {
457
467
  : '\nregisterInit(init);'
458
468
 
459
469
  return `import { setInstance, registerInit } from "./core.js";
460
- import { instantiateWithFallback } from "./util.js";
470
+ import { instantiateWithBackend } from "./util.js";
461
471
  ${getBytesSrc}
462
472
 
463
473
  let _ready = null;
464
- export function init(imports = {}) {
465
- return (_ready ??= (async () => {
466
- const { simdBytes, baseBytes } = await getWasmBytes();
467
- const { instance } = await instantiateWithFallback(simdBytes, baseBytes, imports);
474
+ let _backend = null;
475
+ export function init(imports = {}, opts = {}) {
476
+ const backend = opts.backend || 'auto';
477
+ if (_ready && _backend === backend) return _ready;
478
+ _backend = backend;
479
+ return (_ready = (async () => {
480
+ const { instance } = await instantiateWithBackend({ getSimdBytes, getBaseBytes, imports, backend });
468
481
  setInstance(instance);
469
482
  })());
470
483
  }
@@ -491,10 +504,14 @@ function createBrowserLoader({ name, autoInit, customJs, wasmDelivery }) {
491
504
  const simdUrl = ${simdUrl};
492
505
  const baseUrl = ${baseUrl};
493
506
 
494
- async function getWasmBytes() {
495
- const [simdRes, baseRes] = await Promise.all([fetch(simdUrl), fetch(baseUrl)]);
496
- const [simdBytes, baseBytes] = await Promise.all([simdRes.arrayBuffer(), baseRes.arrayBuffer()]);
497
- return { simdBytes, baseBytes };
507
+ async function getSimdBytes() {
508
+ const res = await fetch(simdUrl);
509
+ return res.arrayBuffer();
510
+ }
511
+
512
+ async function getBaseBytes() {
513
+ const res = await fetch(baseUrl);
514
+ return res.arrayBuffer();
498
515
  }
499
516
  `
500
517
  return createLoader({ exportFrom, autoInit, getBytesSrc })
@@ -509,9 +526,12 @@ import { fileURLToPath } from "node:url";
509
526
  const simdPath = fileURLToPath(new URL("./wasm/${name}.simd.wasm", import.meta.url));
510
527
  const basePath = fileURLToPath(new URL("./wasm/${name}.base.wasm", import.meta.url));
511
528
 
512
- async function getWasmBytes() {
513
- const [simdBytes, baseBytes] = await Promise.all([readFile(simdPath), readFile(basePath)]);
514
- return { simdBytes, baseBytes };
529
+ async function getSimdBytes() {
530
+ return readFile(simdPath);
531
+ }
532
+
533
+ async function getBaseBytes() {
534
+ return readFile(basePath);
515
535
  }
516
536
  `
517
537
  return createLoader({ exportFrom, autoInit, getBytesSrc })
@@ -520,11 +540,15 @@ async function getWasmBytes() {
520
540
  function createInlineLoader({ name, autoInit, customJs }) {
521
541
  const exportFrom = customJs ? './custom.js' : './core.js'
522
542
  const getBytesSrc = `
523
- import { wasmBytes as simdBytes } from "./wasm-inline/${name}.simd.wasm.js";
524
- import { wasmBytes as baseBytes } from "./wasm-inline/${name}.base.wasm.js";
543
+ import { wasmBytes as _simdBytes } from "./wasm-inline/${name}.simd.wasm.js";
544
+ import { wasmBytes as _baseBytes } from "./wasm-inline/${name}.base.wasm.js";
525
545
 
526
- async function getWasmBytes() {
527
- return { simdBytes, baseBytes };
546
+ async function getSimdBytes() {
547
+ return _simdBytes;
548
+ }
549
+
550
+ async function getBaseBytes() {
551
+ return _baseBytes;
528
552
  }
529
553
  `
530
554
  return createLoader({ exportFrom, autoInit, getBytesSrc })
@@ -536,6 +560,38 @@ export const wasmBytes = new Uint8Array([${bytes.join(',')}]);
536
560
  `
537
561
  }
538
562
 
563
+ function loadCustomModule(crateDir, customJs) {
564
+ const customPath = join(crateDir, customJs)
565
+ const source = readFileSync(customPath, 'utf8')
566
+ const ext = extname(customJs).toLowerCase()
567
+
568
+ if (!TS_EXTS.has(ext)) return source
569
+
570
+ let ts
571
+ try {
572
+ ts = require('typescript')
573
+ } catch {
574
+ throw new Error(
575
+ "Custom TypeScript runtime requires the 'typescript' package. Install it with `npm install typescript` in your project."
576
+ )
577
+ }
578
+
579
+ const { outputText } = ts.transpileModule(source, {
580
+ fileName: customPath,
581
+ compilerOptions: {
582
+ module: ts.ModuleKind.ESNext,
583
+ target: ts.ScriptTarget.ES2020,
584
+ jsx: ts.JsxEmit.ReactJSX,
585
+ esModuleInterop: true,
586
+ allowSyntheticDefaultImports: true,
587
+ sourceMap: false,
588
+ },
589
+ reportDiagnostics: false,
590
+ })
591
+
592
+ return outputText
593
+ }
594
+
539
595
  function writeInlineModules({
540
596
  outDir,
541
597
  artifactBaseName,
@@ -559,6 +615,7 @@ function writeInlineModules({
559
615
  }
560
616
 
561
617
  export function emitRuntime({
618
+ crateDir,
562
619
  outDir,
563
620
  artifactBaseName,
564
621
  emitNode,
@@ -575,15 +632,15 @@ export function emitRuntime({
575
632
  mkdirSync(outDir, { recursive: true })
576
633
 
577
634
  if (customJs) {
578
- const customJsContent = readFileSync(join(process.cwd(), customJs), 'utf8')
635
+ const customJsContent = loadCustomModule(crateDir, customJs)
579
636
  writeFileSync(join(outDir, 'custom.js'), customJsContent)
580
637
 
581
638
  if (emitTypes) {
582
- const customTsPath = customJs.replace(/\.js$/, '.d.ts')
583
- if (existsSync(join(process.cwd(), customTsPath))) {
639
+ const customTsPath = customJs.replace(/\.[^.]+$/, '.d.ts')
640
+ if (existsSync(join(crateDir, customTsPath))) {
584
641
  writeFileSync(
585
642
  join(outDir, 'custom.d.ts'),
586
- readFileSync(join(process.cwd(), customTsPath), 'utf8')
643
+ readFileSync(join(crateDir, customTsPath), 'utf8')
587
644
  )
588
645
  }
589
646
  }
package/src/cli/index.js CHANGED
@@ -3,6 +3,7 @@ import { loadConfigFromCli, summarizeConfig } from './config.js'
3
3
  import { buildArtifacts } from './build.js'
4
4
  import { emitRuntime } from './emit.js'
5
5
  import { updatePackageJson } from './pkg.js'
6
+ import { runBench } from './bench.js'
6
7
 
7
8
  export async function runBuild(cliOpts) {
8
9
  const cfg = loadConfigFromCli(cliOpts)
@@ -19,6 +20,7 @@ export async function runBuild(cliOpts) {
19
20
  })
20
21
 
21
22
  emitRuntime({
23
+ crateDir: cfg.crateDir,
22
24
  outDir: cfg.outDir,
23
25
  artifactBaseName: cfg.artifactBaseName,
24
26
  emitNode: cfg.js.emit.node,
@@ -55,12 +57,19 @@ export async function runClean(cliOpts) {
55
57
  }
56
58
  }
57
59
 
60
+ export async function runBenchCmd(cliOpts) {
61
+ const cfg = loadConfigFromCli(cliOpts)
62
+ console.log('Configuration:', summarizeConfig(cfg))
63
+ await runBench(cfg, cliOpts)
64
+ }
65
+
58
66
  export function printHelp() {
59
67
  const help = `
60
68
  wasm-bindgen-lite <command> [options]
61
69
 
62
70
  Commands:
63
71
  build Build wasm artifacts and emit JS loaders (default release)
72
+ bench Build variant matrix and run SIMD analysis
64
73
  clean Remove the configured output directory
65
74
  help Show this message
66
75
 
@@ -73,7 +82,27 @@ Options (for build):
73
82
  --simd | --no-simd Build SIMD variant (default: simd on)
74
83
  --wasm-opt | --no-wasm-opt Force enable/disable wasm-opt (default: auto detect)
75
84
  --wasm-opt-args "<args>" Extra args, default "-Oz"
76
- --no-update-package-json Do not modify package.json exports (default: updates if package.json exists)
85
+ --no-update-package-json Do not modify package.json exports
86
+
87
+ Options (for bench):
88
+ --crate <path> Crate root (default: .)
89
+ --config <path> Path to config JSON
90
+ --clean Clean output directory before building
91
+ --skip-build Skip building, use existing variants
92
+
93
+ SIMD Configuration (in wasm-bindgen-lite.config.json):
94
+ {
95
+ "simd": {
96
+ "features": {
97
+ "explicit-simd-encode": { "name": "encode" },
98
+ "explicit-simd-decode": { "name": "decode" }
99
+ },
100
+ "allFeature": "explicit-simd"
101
+ },
102
+ "bench": {
103
+ "outputDir": "bench_out"
104
+ }
105
+ }
77
106
  `
78
107
  console.log(help)
79
108
  }
@@ -1,17 +1,30 @@
1
- import { wasmBytes as simdBytes } from './wasm-inline/mod.simd.wasm.js'
2
- import { wasmBytes as baseBytes } from './wasm-inline/mod.base.wasm.js'
1
+ import { wasmBytes as _simdBytes } from './wasm-inline/mod.simd.wasm.js'
2
+ import { wasmBytes as _baseBytes } from './wasm-inline/mod.base.wasm.js'
3
3
  import { setInstance } from './core.js'
4
- import { instantiateWithFallback } from './util.js'
4
+ import { instantiateWithBackend } from './util.js'
5
+
6
+ async function getSimdBytes() {
7
+ return _simdBytes
8
+ }
9
+
10
+ async function getBaseBytes() {
11
+ return _baseBytes
12
+ }
5
13
 
6
14
  let _ready = null
15
+ let _backend = null
7
16
 
8
- export function init(imports = {}) {
9
- return (_ready ??= (async () => {
10
- const { instance } = await instantiateWithFallback(
11
- simdBytes,
12
- baseBytes,
13
- imports
14
- )
17
+ export function init(imports = {}, opts = {}) {
18
+ const backend = opts.backend || 'auto'
19
+ if (_ready && _backend === backend) return _ready
20
+ _backend = backend
21
+ return (_ready = (async () => {
22
+ const { instance } = await instantiateWithBackend({
23
+ getSimdBytes,
24
+ getBaseBytes,
25
+ imports,
26
+ backend,
27
+ })
15
28
  setInstance(instance)
16
29
  })())
17
30
  }
package/src/js/browser.js CHANGED
@@ -1,28 +1,33 @@
1
1
  import { setInstance } from './core.js'
2
- import { instantiateWithFallback } from './util.js'
2
+ import { instantiateWithBackend } from './util.js'
3
3
 
4
4
  const simdUrl = new URL('./wasm/mod.simd.wasm', import.meta.url)
5
5
  const baseUrl = new URL('./wasm/mod.base.wasm', import.meta.url)
6
6
 
7
- let _ready = null
7
+ async function getSimdBytes() {
8
+ const res = await fetch(simdUrl)
9
+ return res.arrayBuffer()
10
+ }
8
11
 
9
- export function init(imports = {}) {
10
- return (_ready ??= (async () => {
11
- const [simdRes, baseRes] = await Promise.all([
12
- fetch(simdUrl),
13
- fetch(baseUrl),
14
- ])
12
+ async function getBaseBytes() {
13
+ const res = await fetch(baseUrl)
14
+ return res.arrayBuffer()
15
+ }
15
16
 
16
- const [simdBytes, baseBytes] = await Promise.all([
17
- simdRes.arrayBuffer(),
18
- baseRes.arrayBuffer(),
19
- ])
17
+ let _ready = null
18
+ let _backend = null
20
19
 
21
- const { instance } = await instantiateWithFallback(
22
- simdBytes,
23
- baseBytes,
24
- imports
25
- )
20
+ export function init(imports = {}, opts = {}) {
21
+ const backend = opts.backend || 'auto'
22
+ if (_ready && _backend === backend) return _ready
23
+ _backend = backend
24
+ return (_ready = (async () => {
25
+ const { instance } = await instantiateWithBackend({
26
+ getSimdBytes,
27
+ getBaseBytes,
28
+ imports,
29
+ backend,
30
+ })
26
31
  setInstance(instance)
27
32
  })())
28
33
  }
@@ -1,17 +1,30 @@
1
- import { wasmBytes as simdBytes } from './wasm-inline/mod.simd.wasm.js'
2
- import { wasmBytes as baseBytes } from './wasm-inline/mod.base.wasm.js'
1
+ import { wasmBytes as _simdBytes } from './wasm-inline/mod.simd.wasm.js'
2
+ import { wasmBytes as _baseBytes } from './wasm-inline/mod.base.wasm.js'
3
3
  import { setInstance } from './core.js'
4
- import { instantiateWithFallback } from './util.js'
4
+ import { instantiateWithBackend } from './util.js'
5
+
6
+ async function getSimdBytes() {
7
+ return _simdBytes
8
+ }
9
+
10
+ async function getBaseBytes() {
11
+ return _baseBytes
12
+ }
5
13
 
6
14
  let _ready = null
15
+ let _backend = null
7
16
 
8
- export function init(imports = {}) {
9
- return (_ready ??= (async () => {
10
- const { instance } = await instantiateWithFallback(
11
- simdBytes,
12
- baseBytes,
13
- imports
14
- )
17
+ export function init(imports = {}, opts = {}) {
18
+ const backend = opts.backend || 'auto'
19
+ if (_ready && _backend === backend) return _ready
20
+ _backend = backend
21
+ return (_ready = (async () => {
22
+ const { instance } = await instantiateWithBackend({
23
+ getSimdBytes,
24
+ getBaseBytes,
25
+ imports,
26
+ backend,
27
+ })
15
28
  setInstance(instance)
16
29
  })())
17
30
  }
package/src/js/node.js CHANGED
@@ -1,24 +1,33 @@
1
1
  import { readFile } from 'node:fs/promises'
2
2
  import { fileURLToPath } from 'node:url'
3
3
  import { setInstance } from './core.js'
4
- import { instantiateWithFallback } from './util.js'
4
+ import { instantiateWithBackend } from './util.js'
5
5
 
6
6
  const simdPath = fileURLToPath(new URL('./wasm/mod.simd.wasm', import.meta.url))
7
7
  const basePath = fileURLToPath(new URL('./wasm/mod.base.wasm', import.meta.url))
8
8
 
9
+ async function getSimdBytes() {
10
+ return readFile(simdPath)
11
+ }
12
+
13
+ async function getBaseBytes() {
14
+ return readFile(basePath)
15
+ }
16
+
9
17
  let _ready = null
18
+ let _backend = null
10
19
 
11
- export function init(imports = {}) {
12
- return (_ready ??= (async () => {
13
- const [simdBytes, baseBytes] = await Promise.all([
14
- readFile(simdPath),
15
- readFile(basePath),
16
- ])
17
- const { instance } = await instantiateWithFallback(
18
- simdBytes,
19
- baseBytes,
20
- imports
21
- )
20
+ export function init(imports = {}, opts = {}) {
21
+ const backend = opts.backend || 'auto'
22
+ if (_ready && _backend === backend) return _ready
23
+ _backend = backend
24
+ return (_ready = (async () => {
25
+ const { instance } = await instantiateWithBackend({
26
+ getSimdBytes,
27
+ getBaseBytes,
28
+ imports,
29
+ backend,
30
+ })
22
31
  setInstance(instance)
23
32
  })())
24
33
  }