emnapi 1.11.0 → 2.0.0-alpha.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.
Files changed (79) hide show
  1. package/CMakeLists.txt +127 -57
  2. package/README.md +164 -776
  3. package/cmake/wasm32.cmake +0 -3
  4. package/common.gypi +16 -14
  5. package/dist/library_async_work.js +390 -0
  6. package/dist/library_napi.js +1476 -2802
  7. package/dist/library_threadsafe_function.js +1178 -0
  8. package/dist/library_v8.js +1594 -0
  9. package/emnapi.gyp +37 -0
  10. package/include/node/emnapi.h +13 -2
  11. package/include/node/js_native_api_types.h +22 -0
  12. package/include/node/node.h +198 -0
  13. package/include/node/node_api.h +0 -10
  14. package/include/node/node_buffer.h +92 -0
  15. package/include/node/node_object_wrap.h +132 -0
  16. package/include/node/node_version.h +110 -0
  17. package/include/node/uv/unix.h +1 -0
  18. package/include/node/uv/version.h +43 -0
  19. package/include/node/uv.h +6 -0
  20. package/index.js +15 -7
  21. package/lib/wasm32-emscripten/libemnapi-mt.a +0 -0
  22. package/lib/wasm32-emscripten/libemnapi.a +0 -0
  23. package/lib/wasm32-wasip1-threads/libemnapi-mt.a +0 -0
  24. package/lib/wasm32-wasip1-threads/libemnapi-napi-rs-mt.a +0 -0
  25. package/lib/wasm32-wasip1-threads/libemnapi.a +0 -0
  26. package/lib/wasm64-emscripten/libemnapi-mt.a +0 -0
  27. package/lib/wasm64-emscripten/libemnapi.a +0 -0
  28. package/package.json +1 -1
  29. package/src/async_cleanup_hook.c +6 -6
  30. package/src/emnapi_internal.h +5 -10
  31. package/src/js_native_api.c +37 -21
  32. package/src/js_native_api_internal.h +66 -0
  33. package/src/node_api.c +1 -1
  34. package/src/threadsafe_function.c +2 -2
  35. package/src/uv/unix/thread.c +21 -0
  36. package/src/v8/array.cc +19 -0
  37. package/src/v8/boolean.cc +26 -0
  38. package/src/v8/date.cc +15 -0
  39. package/src/v8/exception.cc +48 -0
  40. package/src/v8/external.cc +23 -0
  41. package/src/v8/function.cc +35 -0
  42. package/src/v8/handle_scope.cc +46 -0
  43. package/src/v8/internal.cc +126 -0
  44. package/src/v8/internal.h +41 -0
  45. package/src/v8/isolate.cc +35 -0
  46. package/src/v8/json.cc +25 -0
  47. package/src/v8/node.cc +24 -0
  48. package/src/v8/number.cc +62 -0
  49. package/src/v8/object.cc +106 -0
  50. package/src/v8/script.cc +75 -0
  51. package/src/v8/string.cc +104 -0
  52. package/src/v8/template.cc +234 -0
  53. package/src/v8/try_catch.cc +50 -0
  54. package/src/v8/v8_impl.h +42 -0
  55. package/src/v8/value.cc +138 -0
  56. package/lib/wasm32/libdlmalloc-mt.a +0 -0
  57. package/lib/wasm32/libdlmalloc.a +0 -0
  58. package/lib/wasm32/libemmalloc-mt.a +0 -0
  59. package/lib/wasm32/libemmalloc.a +0 -0
  60. package/lib/wasm32/libemnapi-basic-mt.a +0 -0
  61. package/lib/wasm32/libemnapi-basic.a +0 -0
  62. package/lib/wasm32/libemnapi.a +0 -0
  63. package/lib/wasm32-emscripten/libemnapi-basic.a +0 -0
  64. package/lib/wasm32-wasi/libemnapi-basic-mt.a +0 -0
  65. package/lib/wasm32-wasi/libemnapi-basic.a +0 -0
  66. package/lib/wasm32-wasi/libemnapi.a +0 -0
  67. package/lib/wasm32-wasi-threads/libemnapi-basic-mt.a +0 -0
  68. package/lib/wasm32-wasi-threads/libemnapi-basic-napi-rs-mt.a +0 -0
  69. package/lib/wasm32-wasi-threads/libemnapi-basic.a +0 -0
  70. package/lib/wasm32-wasi-threads/libemnapi-mt.a +0 -0
  71. package/lib/wasm32-wasi-threads/libemnapi-napi-rs-mt.a +0 -0
  72. package/lib/wasm32-wasi-threads/libemnapi.a +0 -0
  73. package/lib/wasm32-wasip1/libemnapi-basic-mt.a +0 -0
  74. package/lib/wasm32-wasip1/libemnapi-basic.a +0 -0
  75. package/lib/wasm32-wasip1/libemnapi.a +0 -0
  76. package/lib/wasm32-wasip1-threads/libemnapi-basic-mt.a +0 -0
  77. package/lib/wasm32-wasip1-threads/libemnapi-basic-napi-rs-mt.a +0 -0
  78. package/lib/wasm32-wasip1-threads/libemnapi-basic.a +0 -0
  79. package/lib/wasm64-emscripten/libemnapi-basic.a +0 -0
package/README.md CHANGED
@@ -14,6 +14,8 @@
14
14
 
15
15
  [![Build](https://github.com/toyobayashi/emnapi/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/toyobayashi/emnapi/actions/workflows/main.yml)
16
16
 
17
+ # This is 2.x branch, [go stable 1.x branch here](https://github.com/toyobayashi/emnapi/tree/v1.x)
18
+
17
19
  [Node-API](https://nodejs.org/docs/latest/api/n-api.html) implementation for [Emscripten](https://emscripten.org/index.html), [wasi-sdk](https://github.com/WebAssembly/wasi-sdk) and clang with wasm support.
18
20
 
19
21
  This project aims to
@@ -43,51 +45,33 @@ If you want to deep dive into WebAssembly, highly recommend you to visit [learn-
43
45
 
44
46
  You will need to install:
45
47
 
46
- - Node.js `>= v16.15.0`
48
+ - Node.js `>= v22.12.0`
47
49
  - npm `>= v8`
48
- - Emscripten `>= v3.1.9` / wasi-sdk / LLVM clang with wasm support
49
- - (Optional) CMake `>= v3.13`
50
- - (Optional) node-gyp `>= v10.2.0`
51
- - (Optional) ninja
52
- - (Optional) make
53
- - (Optional) [node-addon-api](https://github.com/nodejs/node-addon-api) `>= 6.1.0`
54
50
 
55
- There are several choices to get `make` for Windows user
51
+ Tool chain choices:
56
52
 
57
- - Install [mingw-w64](https://www.mingw-w64.org/downloads/), then use `mingw32-make`
58
- - Download [MSVC prebuilt binary of GNU make](https://github.com/toyobayashi/make-win-build/releases), add to `%Path%` then rename it to `mingw32-make`
59
- - Install [Visual Studio 2022](https://visualstudio.microsoft.com/) C++ desktop workload, use `nmake` in `Visual Studio Developer Command Prompt`
60
- - Install [Visual C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/), use `nmake` in `Visual Studio Developer Command Prompt`
53
+ - Emscripten `>= v4.1.7` with `EMSDK` environment variable set
54
+ - wasi-sdk `>= v26` with `WASI_SDK_PATH` environment variable set
61
55
 
62
- Verify your environment:
56
+ Build system choices:
63
57
 
64
- ```bash
65
- node -v
66
- npm -v
67
- emcc -v
58
+ - CMake `>= v3.13`
59
+ - node-gyp `>= v10.2.0`
60
+ - make / ninja
68
61
 
69
- # clang -v
70
- # clang -print-targets # ensure wasm32 target exists
62
+ Optional:
71
63
 
72
- cmake --version
64
+ - [node-addon-api](https://github.com/nodejs/node-addon-api) `>= 6.1.0`
73
65
 
74
- # if you use node-gyp
75
- node-gyp --version
76
-
77
- # if you use ninja
78
- ninja --version
79
-
80
- # if you use make
81
- make -v
66
+ There are several choices to get `make` for Windows user
82
67
 
83
- # if you use nmake in Visual Studio Developer Command Prompt
84
- nmake /?
85
- ```
68
+ - Install [mingw-w64](https://www.mingw-w64.org/downloads/), then use `mingw32-make`
69
+ - Download [MSVC prebuilt binary of GNU make](https://github.com/toyobayashi/make-win-build/releases), add to `%Path%` then rename it to `mingw32-make`
70
+ - Install [Visual Studio 2022](https://visualstudio.microsoft.com/) C++ desktop workload, use `nmake` in `Visual Studio Developer Command Prompt`
71
+ - Install [Visual C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/), use `nmake` in `Visual Studio Developer Command Prompt`
86
72
 
87
73
  ## Build from source
88
74
 
89
- You need to set `EMSDK` and `WASI_SDK_PATH` environment variables.
90
-
91
75
  ```bash
92
76
  git clone https://github.com/toyobayashi/emnapi.git
93
77
  cd ./emnapi
@@ -96,25 +80,31 @@ npm install
96
80
  npm run build # output ./packages/*/dist
97
81
  node ./script/release.js # output ./out
98
82
 
99
- # test
100
- npm run rebuild:test
101
- npm test
83
+ # test for emscripten
84
+ npm run rebuild -w packages/test
85
+ npm run test -w packages/test
86
+
87
+ # test for wasi-sdk
88
+ npm run rebuild:wt -w packages/test
89
+ npm run test:wt -w packages/test
102
90
  ```
103
91
 
104
92
  See [CONTRIBUTING](https://github.com/toyobayashi/emnapi/blob/main/CONTRIBUTING.md) for more details.
105
93
 
106
94
  ## Quick Start
107
95
 
96
+ [See full example](https://github.com/toyobayashi/emnapi/tree/main/packages/example)
97
+
108
98
  ### NPM Install
109
99
 
110
100
  ```bash
111
101
  npm install -D emnapi
112
102
  npm install @emnapi/runtime
113
103
 
114
- # for non-emscripten
104
+ # additionally, for wasi-sdk, install @emnapi/core
115
105
  npm install @emnapi/core
116
106
 
117
- # if you use node-addon-api
107
+ # if you need node-addon-api
118
108
  npm install node-addon-api
119
109
  ```
120
110
 
@@ -122,525 +112,197 @@ Each package should match the same version.
122
112
 
123
113
  ### Using C
124
114
 
125
- Create `hello.c`.
115
+ Create `binding.c`:
126
116
 
127
117
  ```c
128
118
  #include <node_api.h>
129
119
 
130
- #define NODE_API_CALL(env, the_call) \
131
- do { \
132
- if ((the_call) != napi_ok) { \
133
- const napi_extended_error_info *error_info; \
134
- napi_get_last_error_info((env), &error_info); \
135
- bool is_pending; \
136
- const char* err_message = error_info->error_message; \
137
- napi_is_exception_pending((env), &is_pending); \
138
- if (!is_pending) { \
139
- const char* error_message = err_message != NULL ? \
140
- err_message : \
141
- "empty error message"; \
142
- napi_throw_error((env), NULL, error_message); \
143
- } \
144
- return NULL; \
145
- } \
146
- } while (0)
147
-
148
- static napi_value js_hello(napi_env env, napi_callback_info info) {
149
- napi_value world;
150
- const char* str = "world";
151
- NODE_API_CALL(env, napi_create_string_utf8(env, str, NAPI_AUTO_LENGTH, &world));
152
- return world;
153
- }
120
+ // ...
154
121
 
155
122
  NAPI_MODULE_INIT() {
156
- napi_value hello;
157
- NODE_API_CALL(env, napi_create_function(env, "hello", NAPI_AUTO_LENGTH,
158
- js_hello, NULL, &hello));
159
- NODE_API_CALL(env, napi_set_named_property(env, exports, "hello", hello));
123
+ napi_value fn;
124
+ napi_create_function(env, "run", NAPI_AUTO_LENGTH, run, NULL, &fn);
125
+ napi_set_named_property(env, exports, "run", fn);
160
126
  return exports;
161
127
  }
162
128
  ```
163
129
 
164
- The C code is equivalant to the following JavaScript:
165
-
166
- ```js
167
- module.exports = (function (exports) {
168
- const hello = function hello () {
169
- // native code in js_hello
170
- const world = 'world'
171
- return world
172
- }
173
-
174
- exports.hello = hello
175
- return exports
176
- })(module.exports)
177
- ```
178
-
179
- #### Building
180
-
181
- <details>
182
- <summary>emscripten</summary><br />
183
-
184
- ```bash
185
- emcc -O3 \
186
- -DBUILDING_NODE_EXTENSION \
187
- "-DNAPI_EXTERN=__attribute__((__import_module__(\"env\")))" \
188
- -I./node_modules/emnapi/include/node \
189
- -L./node_modules/emnapi/lib/wasm32-emscripten \
190
- --js-library=./node_modules/emnapi/dist/library_napi.js \
191
- -sEXPORTED_FUNCTIONS="['_malloc','_free','_napi_register_wasm_v1','_node_api_module_get_api_version_v1']" \
192
- -sEXPORTED_RUNTIME_METHODS=['emnapiInit'] \
193
- -o hello.js \
194
- hello.c \
195
- -lemnapi
196
- ```
197
-
198
- </details>
199
-
200
- <details>
201
- <summary>wasi-sdk</summary><br />
130
+ Build with Emscripten:
202
131
 
203
132
  ```bash
204
- clang -O3 \
205
- -DBUILDING_NODE_EXTENSION \
206
- -I./node_modules/emnapi/include/node \
207
- -L./node_modules/emnapi/lib/wasm32-wasi \
208
- --target=wasm32-wasi \
209
- --sysroot=$WASI_SDK_PATH/share/wasi-sysroot \
210
- -mexec-model=reactor \
211
- -Wl,--initial-memory=16777216 \
212
- -Wl,--export-dynamic \
213
- -Wl,--export=malloc \
214
- -Wl,--export=free \
215
- -Wl,--export=napi_register_wasm_v1 \
216
- -Wl,--export-if-defined=node_api_module_get_api_version_v1 \
217
- -Wl,--import-undefined \
218
- -Wl,--export-table \
219
- -o hello.wasm \
220
- hello.c \
221
- -lemnapi
222
- ```
223
-
224
- </details>
225
-
226
- <details>
227
- <summary>clang wasm32</summary><br />
228
-
229
- Choose `libdlmalloc.a` or `libemmalloc.a` for `malloc` and `free`.
133
+ emcc -O3 -pthread \
134
+ -DBUILDING_NODE_EXTENSION \
135
+ "-DNAPI_EXTERN=__attribute__((__import_module__(\"env\")))" \
136
+ -I./node_modules/emnapi/include/node \
137
+ -L./node_modules/emnapi/lib/wasm32-emscripten \
138
+ --js-library=./node_modules/emnapi/dist/library_napi.js \
139
+ -sWASM_BIGINT=1 \
140
+ -sALLOW_MEMORY_GROWTH=1 \
141
+ -sALLOW_TABLE_GROWTH=1 \
142
+ -sEXPORTED_FUNCTIONS=$(node -p "JSON.stringify(require('emnapi').requiredConfig.emscripten.settings.EXPORTED_FUNCTIONS)") \
143
+ -sEXPORTED_RUNTIME_METHODS=$(node -p "JSON.stringify(require('emnapi').requiredConfig.emscripten.settings.EXPORTED_RUNTIME_METHODS)") \
144
+ -sEXPORT_ES6=1 \
145
+ -sPTHREAD_POOL_SIZE=4 \
146
+ -o out/binding.js \
147
+ binding.c \
148
+ -lemnapi-mt
149
+ ```
150
+
151
+ Build with wasi-sdk:
230
152
 
231
153
  ```bash
232
- clang -O3 \
233
- -DBUILDING_NODE_EXTENSION \
234
- -I./node_modules/emnapi/include/node \
235
- -L./node_modules/emnapi/lib/wasm32 \
236
- --target=wasm32 \
237
- -nostdlib \
238
- -Wl,--no-entry \
239
- -Wl,--initial-memory=16777216 \
240
- -Wl,--export-dynamic \
241
- -Wl,--export=malloc \
242
- -Wl,--export=free \
243
- -Wl,--export=napi_register_wasm_v1 \
244
- -Wl,--export-if-defined=node_api_module_get_api_version_v1 \
245
- -Wl,--import-undefined \
246
- -Wl,--export-table \
247
- -o hello.wasm \
248
- hello.c \
249
- -lemnapi \
250
- -ldlmalloc # -lemmalloc
251
- ```
252
-
253
- </details>
254
-
255
- #### Initialization
256
-
257
- To initialize emnapi, you need to import the emnapi runtime to create a `Context` by `createContext` or `getDefaultContext` first.
258
- Each context owns isolated Node-API object such as `napi_env`, `napi_value`, `napi_ref`. If you have multiple emnapi modules, you should reuse the same `Context` across them.
259
-
260
- ```ts
261
- declare namespace emnapi {
262
- // module '@emnapi/runtime'
263
- export class Context { /* ... */ }
264
- /** Create a new context */
265
- export function createContext (): Context
266
- /** Create or get */
267
- export function getDefaultContext (): Context
268
- // ...
269
- }
270
- ```
271
-
272
- <details>
273
- <summary>emscripten</summary><br />
274
-
275
- then call `Module.emnapiInit` after emscripten runtime initialized.
276
- `Module.emnapiInit` only do initialization once, it will always return the same binding exports after successfully initialized.
277
-
278
- ```ts
279
- declare namespace Module {
280
- interface EmnapiInitOptions {
281
- context: emnapi.Context
282
-
283
- /** node_api_get_module_file_name */
284
- filename?: string
285
-
286
- /**
287
- * Support following async_hooks related things
288
- * on Node.js runtime only
289
- *
290
- * napi_async_init,
291
- * napi_async_destroy,
292
- * napi_make_callback,
293
- * async resource parameter of
294
- * napi_create_async_work and napi_create_threadsafe_function
295
- */
296
- nodeBinding?: typeof import('@emnapi/node-binding')
297
-
298
- /** See Multithread part */
299
- asyncWorkPoolSize?: number
300
- }
301
- export function emnapiInit (options: EmnapiInitOptions): any
302
- }
303
- ```
304
-
305
- ```html
306
- <script src="node_modules/@emnapi/runtime/dist/emnapi.min.js"></script>
307
- <script src="hello.js"></script>
308
- <script>
309
- Module.onRuntimeInitialized = function () {
310
- var binding;
311
- try {
312
- binding = Module.emnapiInit({ context: emnapi.getDefaultContext() });
313
- } catch (err) {
314
- console.error(err);
315
- return;
316
- }
317
- var msg = 'hello ' + binding.hello();
318
- window.alert(msg);
319
- };
320
-
321
- // if -sMODULARIZE=1
322
- Module({ /* Emscripten module init options */ }).then(function (Module) {
323
- var binding = Module.emnapiInit({ context: emnapi.getDefaultContext() });
324
- });
325
- </script>
326
- ```
327
-
328
- If you are using `Visual Studio Code` and have `Live Server` extension installed, you can right click the HTML file in Visual Studio Code source tree and click `Open With Live Server`, then you can see the hello world alert!
329
-
330
- Running on Node.js:
154
+ "$WASI_SDK_PATH/bin/clang" --target=wasm32-wasip1-threads -O3 \
155
+ -pthread -matomics -mbulk-memory \
156
+ -DBUILDING_NODE_EXTENSION \
157
+ -I./node_modules/emnapi/include/node \
158
+ -L./node_modules/emnapi/lib/wasm32-wasip1-threads \
159
+ --sysroot="$WASI_SDK_PATH/share/wasi-sysroot" \
160
+ -mexec-model=reactor \
161
+ -Wl,--import-memory -Wl,--shared-memory -Wl,--export-memory \
162
+ -Wl,--export-table -Wl,--growable-table \
163
+ -Wl,--export=malloc,--export=free \
164
+ -Wl,--export=napi_register_wasm_v1 \
165
+ -Wl,--export=emnapi_create_env,--export=emnapi_delete_env \
166
+ -Wl,--export-if-defined=node_api_module_get_api_version_v1 \
167
+ -Wl,--export-if-defined=uv_library_shutdown \
168
+ -Wl,--import-undefined \
169
+ -o out/binding.wasm \
170
+ binding.c \
171
+ -lemnapi-mt
172
+ ```
173
+
174
+ Use in JavaScript (Emscripten):
331
175
 
332
176
  ```js
333
- const emnapi = require('@emnapi/runtime')
334
- const Module = require('./hello.js')
335
-
336
- Module.onRuntimeInitialized = function () {
337
- let binding
338
- try {
339
- binding = Module.emnapiInit({ context: emnapi.getDefaultContext() })
340
- } catch (err) {
341
- console.error(err)
342
- return
343
- }
344
- const msg = `hello ${binding.hello()}`
345
- console.log(msg)
346
- }
347
-
348
- // if -sMODULARIZE=1
349
- Module({ /* Emscripten module init options */ }).then((Module) => {
350
- const binding = Module.emnapiInit({ context: emnapi.getDefaultContext() })
177
+ import init from './out/binding.js'
178
+ import { createContext } from '@emnapi/runtime'
179
+
180
+ const emnapiCtx = createContext()
181
+ const Module = await init()
182
+ const binding = Module.emnapiInit({
183
+ context: emnapiCtx,
184
+ asyncWorkPoolSize: 4 // the same effect to UV_THREADPOOL_SIZE, must less than PTHREAD_POOL_SIZE
351
185
  })
352
- ```
353
-
354
- </details>
186
+ binding.run(/* ... */)
355
187
 
356
- <details>
357
- <summary>wasi-sdk or clang wasm32</summary><br />
358
-
359
- For non-emscripten, you need to use `@emnapi/core`. The initialization is similar to emscripten.
360
-
361
- ```html
362
- <script src="node_modules/@emnapi/runtime/dist/emnapi.min.js"></script>
363
- <script src="node_modules/@emnapi/core/dist/emnapi-core.min.js"></script>
364
- <script>
365
- emnapiCore.instantiateNapiModule(fetch('./hello.wasm'), {
366
- context: emnapi.getDefaultContext(),
367
- overwriteImports (importObject) {
368
- // importObject.env = {
369
- // ...importObject.env,
370
- // ...importObject.napi,
371
- // ...importObject.emnapi,
372
- // // ...
373
- // }
374
- }
375
- }).then(({ instance, module, napiModule }) => {
376
- const binding = napiModule.exports
377
- // ...
378
- })
379
- </script>
188
+ // cleanup
189
+ Module._uv_library_shutdown()
190
+ emnapiCtx.destroy()
380
191
  ```
381
192
 
382
- Using WASI on Node.js
383
-
384
- ```js
385
- const { instantiateNapiModule } = require('@emnapi/core')
386
- const { getDefaultContext } = require('@emnapi/runtime')
387
- const { WASI } = require('wasi')
388
- const fs = require('fs')
389
-
390
- instantiateNapiModule(fs.promises.readFile('./hello.wasm'), {
391
- wasi: new WASI({ /* ... */ }),
392
- context: getDefaultContext(),
393
- overwriteImports (importObject) {
394
- // importObject.env = {
395
- // ...importObject.env,
396
- // ...importObject.napi,
397
- // ...importObject.emnapi,
398
- // // ...
399
- // }
400
- }
401
- }).then(({ instance, module, napiModule }) => {
402
- const binding = napiModule.exports
403
- // ...
404
- })
405
- ```
193
+ For non-emscripten please [reference full JavaScript example](https://github.com/toyobayashi/emnapi/tree/main/packages/example/index-wasi.js)
406
194
 
407
- Using WASI on browser, you can use WASI polyfill in [wasm-util](https://github.com/toyobayashi/wasm-util),
408
- and [memfs-browser](https://github.com/toyobayashi/memfs-browser)
409
-
410
- ```js
411
- import { instantiateNapiModule } from '@emnapi/core'
412
- import { getDefaultContext } from '@emnapi/runtime'
413
- import { WASI } from '@tybys/wasm-util'
414
- import { Volume, createFsFromVolume } from 'memfs-browser'
415
-
416
- const fs = createFsFromVolume(Volume.fromJSON({ /* ... */ }))
417
- instantiateNapiModule(fetch('./hello.wasm'), {
418
- wasi: new WASI({ fs, /* ... */ })
419
- context: getDefaultContext(),
420
- overwriteImports (importObject) {
421
- // importObject.env = {
422
- // ...importObject.env,
423
- // ...importObject.napi,
424
- // ...importObject.emnapi,
425
- // // ...
426
- // }
427
- }
428
- }).then(({ instance, module, napiModule }) => {
429
- const binding = napiModule.exports
430
- // ...
431
- })
432
- ```
433
-
434
- </details>
195
+ <!---->
435
196
 
436
197
  ### Using C++ and node-addon-api
437
198
 
438
- Require [`node-addon-api`](https://github.com/nodejs/node-addon-api) `>= 6.1.0`
439
-
440
- ```bash
441
- npm install node-addon-api
442
- ```
443
-
444
199
  **Note: C++ wrapper can only be used to target Node.js v14.6.0+ and modern browsers those support `FinalizationRegistry` and `WeakRef` ([v8 engine v8.4+](https://v8.dev/blog/v8-release-84))!**
445
200
 
446
- Create `hello.cpp`.
201
+ Create `binding.cpp`:
447
202
 
448
203
  ```cpp
449
204
  #include <napi.h>
450
205
 
451
- Napi::String Method(const Napi::CallbackInfo& info) {
452
- Napi::Env env = info.Env();
453
- return Napi::String::New(env, "world");
454
- }
206
+ // ...
455
207
 
456
208
  Napi::Object Init(Napi::Env env, Napi::Object exports) {
457
- exports.Set(Napi::String::New(env, "hello"),
458
- Napi::Function::New(env, Method)).Check();
209
+ exports.Set("run", Napi::Function::New(env, Run));
459
210
  return exports;
460
211
  }
461
212
 
462
- NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
213
+ NODE_API_MODULE(binding, Init)
463
214
  ```
464
215
 
465
- Compile `hello.cpp` using `em++`. C++ exception is disabled by Emscripten default, and not supported by wasi-sdk, so predefine `-DNAPI_DISABLE_CPP_EXCEPTIONS` and `-DNODE_ADDON_API_ENABLE_MAYBE` here. If you would like to enable C++ exception, use `-sDISABLE_EXCEPTION_CATCHING=0` instead and remove `.Check()` call. See official documentation [here](https://github.com/nodejs/node-addon-api/blob/main/doc/error_handling.md).
466
-
467
- #### Building
468
-
469
- <details>
470
- <summary>emscripten</summary><br />
216
+ Build with Emscripten:
471
217
 
472
218
  ```bash
473
- em++ -O3 \
474
- -DBUILDING_NODE_EXTENSION \
475
- "-DNAPI_EXTERN=__attribute__((__import_module__(\"env\")))" \
476
- -DNAPI_DISABLE_CPP_EXCEPTIONS \
477
- -DNODE_ADDON_API_ENABLE_MAYBE \
478
- -I./node_modules/emnapi/include/node \
479
- -I./node_modules/node-addon-api \
480
- -L./node_modules/emnapi/lib/wasm32-emscripten \
481
- --js-library=./node_modules/emnapi/dist/library_napi.js \
482
- -sEXPORTED_FUNCTIONS="['_malloc','_free','_napi_register_wasm_v1','_node_api_module_get_api_version_v1']" \
483
- -sEXPORTED_RUNTIME_METHODS=['emnapiInit'] \
484
- -o hello.js \
485
- hello.cpp \
486
- -lemnapi
487
- ```
488
-
489
- </details>
490
-
491
- <details>
492
- <summary>wasi-sdk</summary><br />
219
+ em++ -O3 -pthread \
220
+ -DBUILDING_NODE_EXTENSION \
221
+ -DNAPI_DISABLE_CPP_EXCEPTIONS \
222
+ "-DNAPI_EXTERN=__attribute__((__import_module__(\"env\")))" \
223
+ -I./node_modules/emnapi/include/node \
224
+ -I$(node -p "require('node-addon-api').include_dir") \
225
+ -L./node_modules/emnapi/lib/wasm32-emscripten \
226
+ --js-library=./node_modules/emnapi/dist/library_napi.js \
227
+ -sWASM_BIGINT=1 \
228
+ -sALLOW_MEMORY_GROWTH=1 \
229
+ -sALLOW_TABLE_GROWTH=1 \
230
+ -sEXPORTED_FUNCTIONS=$(node -p "JSON.stringify(require('emnapi').requiredConfig.emscripten.settings.EXPORTED_FUNCTIONS)") \
231
+ -sEXPORTED_RUNTIME_METHODS=$(node -p "JSON.stringify(require('emnapi').requiredConfig.emscripten.settings.EXPORTED_RUNTIME_METHODS)") \
232
+ -sEXPORT_ES6=1 \
233
+ -sPTHREAD_POOL_SIZE=4 \
234
+ -o out/binding-naa.js \
235
+ binding.cpp \
236
+ -lemnapi-mt
237
+ ```
238
+
239
+ Build with wasi-sdk:
493
240
 
494
241
  ```bash
495
- clang++ -O3 \
496
- -DBUILDING_NODE_EXTENSION \
497
- -DNAPI_DISABLE_CPP_EXCEPTIONS \
498
- -DNODE_ADDON_API_ENABLE_MAYBE \
499
- -I./node_modules/emnapi/include/node \
500
- -I./node_modules/node-addon-api \
501
- -L./node_modules/emnapi/lib/wasm32-wasi \
502
- --target=wasm32-wasi \
503
- --sysroot=$WASI_SDK_PATH/share/wasi-sysroot \
504
- -fno-exceptions \
505
- -mexec-model=reactor \
506
- -Wl,--initial-memory=16777216 \
507
- -Wl,--export-dynamic \
508
- -Wl,--export=malloc \
509
- -Wl,--export=free \
510
- -Wl,--export=napi_register_wasm_v1 \
511
- -Wl,--export-if-defined=node_api_module_get_api_version_v1 \
512
- -Wl,--import-undefined \
513
- -Wl,--export-table \
514
- -o hello.wasm \
515
- hello.cpp \
516
- -lemnapi
242
+ "$WASI_SDK_PATH/bin/clang++" --target=wasm32-wasip1-threads -O3 \
243
+ -pthread -matomics -mbulk-memory -fno-exceptions \
244
+ -DBUILDING_NODE_EXTENSION \
245
+ -DNAPI_DISABLE_CPP_EXCEPTIONS \
246
+ -I./node_modules/emnapi/include/node \
247
+ -I$(node -p "require('node-addon-api').include_dir") \
248
+ -L./node_modules/emnapi/lib/wasm32-wasip1-threads \
249
+ --sysroot="$WASI_SDK_PATH/share/wasi-sysroot" \
250
+ -mexec-model=reactor \
251
+ -Wl,--import-memory -Wl,--shared-memory -Wl,--export-memory \
252
+ -Wl,--export-table -Wl,--growable-table \
253
+ -Wl,--export=malloc,--export=free \
254
+ -Wl,--export=napi_register_wasm_v1 \
255
+ -Wl,--export=emnapi_create_env,--export=emnapi_delete_env \
256
+ -Wl,--export-if-defined=node_api_module_get_api_version_v1 \
257
+ -Wl,--export-if-defined=uv_library_shutdown \
258
+ -Wl,--import-undefined \
259
+ -o out/binding-naa.wasm \
260
+ binding.cpp \
261
+ -lemnapi-mt
517
262
  ```
518
263
 
519
- </details>
520
-
521
- <details>
522
- <summary>clang wasm32</summary><br />
523
-
524
- `node-addon-api` is using the C++ standard libraries, so you must use WASI if you are using `node-addon-api`.
525
-
526
- You can still use `wasm32-unknown-unknown` target if you use Node-API C API only in C++.
527
-
528
- ```bash
529
- clang++ -O3 \
530
- -DBUILDING_NODE_EXTENSION \
531
- -I./node_modules/emnapi/include/node \
532
- -L./node_modules/emnapi/lib/wasm32 \
533
- --target=wasm32 \
534
- -fno-exceptions \
535
- -nostdlib \
536
- -Wl,--no-entry \
537
- -Wl,--initial-memory=16777216 \
538
- -Wl,--export-dynamic \
539
- -Wl,--export=malloc \
540
- -Wl,--export=free \
541
- -Wl,--export=napi_register_wasm_v1 \
542
- -Wl,--export-if-defined=node_api_module_get_api_version_v1 \
543
- -Wl,--import-undefined \
544
- -Wl,--export-table \
545
- -o node_api_c_api_only.wasm \
546
- node_api_c_api_only.cpp \
547
- -lemnapi \
548
- -ldlmalloc # -lemmalloc
549
- ```
550
-
551
- `operator new` and `operator delete`.
552
-
553
- ```cpp
554
- #include <stddef.h>
555
-
556
- extern "C" void* malloc(size_t size);
557
- extern "C" void free(void* p);
558
-
559
- void* operator new(size_t size) {
560
- return malloc(size);
561
- }
562
-
563
- void operator delete(void* p) noexcept {
564
- free(p);
565
- }
566
-
567
- void operator delete(void* p, size_t) noexcept {
568
- free(p);
569
- }
570
- ```
571
-
572
- </details>
573
-
574
264
  ### Using CMake
575
265
 
576
- Create `CMakeLists.txt`.
266
+ Create `CMakeLists.txt`:
577
267
 
578
268
  ```cmake
579
269
  cmake_minimum_required(VERSION 3.13)
270
+ project(myproject)
580
271
 
581
- project(emnapiexample)
272
+ # optional: enable node-addon-api
273
+ # set(EMNAPI_FIND_NODE_ADDON_API ON)
582
274
 
583
- add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/node_modules/emnapi")
275
+ add_subdirectory("node_modules/emnapi")
584
276
 
585
- add_executable(hello hello.c)
277
+ add_executable(binding binding.c)
278
+
279
+ target_link_libraries(binding PRIVATE emnapi-mt)
586
280
 
587
- target_link_libraries(hello emnapi)
588
281
  if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
589
- target_link_options(hello PRIVATE
590
- "-sEXPORTED_FUNCTIONS=['_malloc','_free','_napi_register_wasm_v1','_node_api_module_get_api_version_v1']"
591
- "-sEXPORTED_RUNTIME_METHODS=['emnapiInit']"
592
- )
593
- elseif(CMAKE_SYSTEM_NAME STREQUAL "WASI")
594
- set_target_properties(hello PROPERTIES SUFFIX ".wasm")
595
- target_link_options(hello PRIVATE
596
- "-mexec-model=reactor"
597
- "-Wl,--export=napi_register_wasm_v1"
598
- "-Wl,--export-if-defined=node_api_module_get_api_version_v1"
599
- "-Wl,--initial-memory=16777216,--export-dynamic,--export=malloc,--export=free,--import-undefined,--export-table"
600
- )
601
- elseif((CMAKE_C_COMPILER_TARGET STREQUAL "wasm32") OR (CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-unknown-unknown"))
602
- set_target_properties(hello PROPERTIES SUFFIX ".wasm")
603
- target_link_options(hello PRIVATE
604
- "-nostdlib"
605
- "-Wl,--export=napi_register_wasm_v1"
606
- "-Wl,--export-if-defined=node_api_module_get_api_version_v1"
607
- "-Wl,--no-entry"
608
- "-Wl,--initial-memory=16777216,--export-dynamic,--export=malloc,--export=free,--import-undefined,--export-table"
609
- )
610
- target_link_libraries(hello dlmalloc)
611
- # target_link_libraries(hello emmalloc)
282
+ # ...
283
+ elseif((CMAKE_SYSTEM_NAME STREQUAL "WASI") AND ((CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-wasi-threads") OR (CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-wasip1-threads")))
284
+ # ...
612
285
  endif()
613
286
  ```
614
287
 
615
- If you use node-addon-api, you can use `-DEMNAPI_FIND_NODE_ADDON_API=ON` or manually add node-addon-api directory to the include dir via `include_directories()` or `target_include_directories()`.
288
+ Build with Emscripten:
616
289
 
617
290
  ```bash
618
- mkdir build
291
+ mkdir build && cd build
292
+ emcmake cmake .. -DCMAKE_BUILD_TYPE=Release
293
+ cmake --build .
294
+ ```
619
295
 
620
- # emscripten
621
- emcmake cmake -DCMAKE_BUILD_TYPE=Release \
622
- -DEMNAPI_FIND_NODE_ADDON_API=ON \
623
- -G Ninja -H. -Bbuild
296
+ Build with wasi-sdk:
624
297
 
625
- # wasi-sdk
626
- cmake -DCMAKE_TOOLCHAIN_FILE=$WASI_SDK_PATH/share/cmake/wasi-sdk.cmake \
627
- -DWASI_SDK_PREFIX=$WASI_SDK_PATH \
628
- -DEMNAPI_FIND_NODE_ADDON_API=ON \
629
- -DCMAKE_BUILD_TYPE=Release \
630
- -G Ninja -H. -Bbuild
631
-
632
- # wasm32
633
- cmake -DCMAKE_TOOLCHAIN_FILE=node_modules/emnapi/cmake/wasm32.cmake \
634
- -DLLVM_PREFIX=$WASI_SDK_PATH \
635
- -DCMAKE_BUILD_TYPE=Release \
636
- -G Ninja -H. -Bbuild
637
-
638
- cmake --build build
298
+ ```bash
299
+ mkdir build && cd build
300
+ cmake .. -DCMAKE_BUILD_TYPE=Release \
301
+ -DCMAKE_TOOLCHAIN_FILE="$WASI_SDK_PATH/share/cmake/wasi-sdk-pthread.cmake"
302
+ cmake --build .
639
303
  ```
640
304
 
641
- Output code can run in recent version modern browsers and Node.js latest LTS. IE is not supported.
642
-
643
- ### Using node-gyp (Experimental)
305
+ ### Using node-gyp
644
306
 
645
307
  Require node-gyp `>= 10.2.0`
646
308
 
@@ -787,157 +449,13 @@ make -C %~dp0build
787
449
 
788
450
  See [napi-rs](https://github.com/napi-rs/napi-rs)
789
451
 
790
- ### Multithread
791
-
792
- Related API:
793
-
794
- - [napi_*_async_work](https://nodejs.org/dist/latest/docs/api/n-api.html#napi_create_async_work)
795
- - [napi_*_threadsafe_function](https://nodejs.org/dist/latest/docs/api/n-api.html#asynchronous-thread-safe-function-calls)
796
-
797
- They are available in emnapi, but you need to know more details before you start to use them.
798
- Now emnapi has 3 implementations of async work and 2 implementations of TSFN:
799
-
800
- - Async work
801
- - A. Libuv threadpool and pthread based implementation in C
802
- - B. Single thread mock in JavaScript
803
- - C. Web worker based implementation in C (stack allocation) and JavaScript
804
- - TSFN
805
- - D. Libuv and pthread based implementation in C
806
- - E. Web worker based implementation in JavaScript
807
-
808
- | | Library to Link | `wasm32-emscripten` | `wasm32` | `wasm32-wasi` | `wasm32-wasi-threads` |
809
- |---|------------------------|---------------------|----------|---------------|-----------------------|
810
- | A | libemnapi-mt.a | ✅ | ❌ | ❌ | ✅ |
811
- | B | libemnapi-basic(-mt).a | ✅ | ✅ | ✅ | ✅ |
812
- | C | libemnapi-basic-mt.a | ❌ | ✅ | ❌ | ✅ |
813
- | D | libemnapi-mt.a | ✅ | ❌ | ❌ | ✅ |
814
- | E | libemnapi-basic(-mt).a | ✅ | ✅ | ✅ | ✅ |
815
-
816
- There are some limitations on browser about wasi-libc's pthread implementation, for example
817
- `pthread_mutex_lock` may call `__builtin_wasm_memory_atomic_wait32`(`memory.atomic.wait32`)
818
- which is disallowed in browser JS main thread. While Emscripten's pthread implementation
819
- has considered usage in browser. This issue can be solved by upgrading `wasi-sdk` to v26+
820
- and emnapi v1.5.0+ then pass `--export=emnapi_thread_crashed` to the linker. If you need to
821
- run your addon with multithreaded features, we recommend you use A & D or C & E.
822
-
823
- Note: For browsers, all the multithreaded features relying on Web Workers (Emscripten pthread also relying on Web Workers)
824
- require cross-origin isolation to enable `SharedArrayBuffer`. You can make a page cross-origin isolated
825
- by serving the page with these headers:
826
-
827
- ```
828
- Cross-Origin-Embedder-Policy: require-corp
829
- Cross-Origin-Opener-Policy: same-origin
830
- ```
831
-
832
- If you would like to avoid `SharedArrayBuffer` and cross-origin isolation, please use B & E (link against `libemnapi-basic.a`), see the following table for more details.
833
-
834
- #### About Prebuilt Libraries
835
-
836
- Prebuilt libraries can be found in the `lib` directory in `emnapi` npm package.
837
-
838
- | Library | Description | `wasm32-emscripten` | `wasm32` | `wasm32-wasi` | `wasm32-wasi-threads` |
839
- |----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------|----------|---------------|-----------------------------------------|
840
- | libemnapi.a | no atomics feature.<br/><br/> no libuv port.<br/><br/> `napi_*_async_work` and `napi_*_threadsafe_function` always return `napi_generic_failure`. | ✅ | ✅ | ✅ | ✅ |
841
- | libemnapi-mt.a | atomics feature enabled.<br/><br/> `napi_*_async_work` and `napi_*_threadsafe_function` are based on pthread and libuv port. | ✅ | ❌ | ❌ | ✅ |
842
- | libemnapi-basic.a | no atomics feature.<br/><br/> no libuv port.<br/><br/> `napi_*_async_work` and `napi_*_threadsafe_function` are imported from JavaScript land. | ✅ | ✅ | ✅ | ✅ |
843
- | libemnapi-basic-mt.a | atomics feature enabled.<br/><br/> no libuv port.<br/><br/> `napi_*_async_work` and `napi_*_threadsafe_function` are imported from JavaScript land.<br/><br/> include `emnapi_async_worker_create` and `emnapi_async_worker_init` for WebWorker based async work implementation. | ❌ | ✅ | ✅ | ✅ |
844
- | libdlmalloc.a | no atomics feature, no thread safe garanteed. | ❌ | ✅ | ❌ | ❌ |
845
- | libdlmalloc-mt.a | atomics feature enabled, thread safe. | ❌ | ✅ | ❌ | ❌ |
846
- | libemmalloc.a | no atomics feature, no thread safe garanteed. | ❌ | ✅ | ❌ | ❌ |
847
- | libemmalloc-mt.a | atomics feature enabled, thread safe. | ❌ | ✅ | ❌ | ❌ |
848
-
849
- #### Usage
850
-
851
- ```cmake
852
- add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/node_modules/emnapi")
853
-
854
- add_executable(hello hello.c)
855
-
856
- if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
857
- target_link_libraries(hello emnapi-mt)
858
- target_compile_options(hello PRIVATE "-pthread")
859
- target_link_options(hello PRIVATE
860
- "-sALLOW_MEMORY_GROWTH=1"
861
- "-sEXPORTED_FUNCTIONS=['_malloc','_free','_napi_register_wasm_v1','_node_api_module_get_api_version_v1']"
862
- "-sEXPORTED_RUNTIME_METHODS=['emnapiInit']"
863
- "-pthread"
864
- "-sPTHREAD_POOL_SIZE=4"
865
- # try to specify stack size if you experience pthread errors
866
- "-sSTACK_SIZE=2MB"
867
- "-sDEFAULT_PTHREAD_STACK_SIZE=2MB"
868
- )
869
- elseif(CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-wasi-threads")
870
- target_link_libraries(hello emnapi-mt)
871
- set_target_properties(hello PROPERTIES SUFFIX ".wasm")
872
- target_compile_options(hello PRIVATE "-fno-exceptions" "-pthread")
873
- target_link_options(hello PRIVATE
874
- "-pthread"
875
- "-mexec-model=reactor"
876
- "-Wl,--import-memory"
877
- "-Wl,--max-memory=2147483648"
878
- "-Wl,--export-dynamic"
879
- "-Wl,--export=napi_register_wasm_v1"
880
- "-Wl,--export-if-defined=node_api_module_get_api_version_v1"
881
- "-Wl,--export=malloc"
882
- "-Wl,--export=free"
883
- "-Wl,--export=emnapi_thread_crashed"
884
- "-Wl,--import-undefined"
885
- "-Wl,--export-table"
886
- )
887
- elseif((CMAKE_C_COMPILER_TARGET STREQUAL "wasm32") OR (CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-unknown-unknown"))
888
- target_link_libraries(hello emnapi-basic-mt)
889
- set_target_properties(hello PROPERTIES SUFFIX ".wasm")
890
- target_compile_options(hello PRIVATE "-fno-exceptions" "-matomics" "-mbulk-memory")
891
- target_link_options(hello PRIVATE
892
- "-nostdlib"
893
- "-Wl,--no-entry"
894
- "-Wl,--export=napi_register_wasm_v1"
895
- "-Wl,--export-if-defined=node_api_module_get_api_version_v1"
896
- "-Wl,--export=emnapi_async_worker_create"
897
- "-Wl,--export=emnapi_async_worker_init"
898
- "-Wl,--import-memory,--shared-memory,--max-memory=2147483648,--import-undefined"
899
- "-Wl,--export-dynamic,--export=malloc,--export=free,--export-table"
900
- )
901
- endif()
902
- ```
903
-
904
- ```bash
905
- # emscripten
906
- emcmake cmake -DCMAKE_BUILD_TYPE=Release \
907
- -DEMNAPI_FIND_NODE_ADDON_API=ON \
908
- -DEMNAPI_WORKER_POOL_SIZE=4 \
909
- -G Ninja -H. -Bbuild
910
-
911
- # wasi-sdk with thread support
912
- cmake -DCMAKE_TOOLCHAIN_FILE=$WASI_SDK_PATH/share/cmake/wasi-sdk-pthread.cmake \
913
- -DWASI_SDK_PREFIX=$WASI_SDK_PATH \
914
- -DEMNAPI_FIND_NODE_ADDON_API=ON \
915
- -DCMAKE_BUILD_TYPE=Release \
916
- -G Ninja -H. -Bbuild
917
-
918
- cmake -DCMAKE_TOOLCHAIN_FILE=node_modules/emnapi/cmake/wasm32.cmake \
919
- -DLLVM_PREFIX=$WASI_SDK_PATH \
920
- -DCMAKE_BUILD_TYPE=Release \
921
- -G Ninja -H. -Bbuild
922
-
923
- cmake --build build
924
- ```
925
-
926
- And additional work is required during instantiating wasm compiled with non-emscripten.
452
+ ### Reference for instantiateNapiModule input parameters
927
453
 
928
454
  ```js
929
455
  // emnapi main thread (could be in a Worker)
930
456
  instantiateNapiModule(input, {
931
457
  context: getDefaultContext(),
932
- /**
933
- * emscripten
934
- * 0: no effect
935
- * > 0: the same effect to UV_THREADPOOL_SIZE
936
- * non-emscripten
937
- * 0: single thread mock
938
- * > 0 schedule async work in web worker
939
- */
940
- asyncWorkPoolSize: 4, // 0: single thread mock, > 0: schedule async work in web worker
458
+ asyncWorkPoolSize: 4, // the same effect to UV_THREADPOOL_SIZE, must less than `reuseWorker.size`
941
459
  wasi: new WASI(/* ... */),
942
460
 
943
461
  /**
@@ -984,141 +502,11 @@ instantiateNapiModule(input, {
984
502
  })
985
503
  ```
986
504
 
987
- ```js
988
- // worker.js
989
- (function () {
990
- let fs, WASI, emnapiCore
991
-
992
- const ENVIRONMENT_IS_NODE =
993
- typeof process === 'object' && process !== null &&
994
- typeof process.versions === 'object' && process.versions !== null &&
995
- typeof process.versions.node === 'string'
996
-
997
- if (ENVIRONMENT_IS_NODE) {
998
- const nodeWorkerThreads = require('worker_threads')
999
-
1000
- const parentPort = nodeWorkerThreads.parentPort
1001
-
1002
- parentPort.on('message', (data) => {
1003
- globalThis.onmessage({ data })
1004
- })
1005
-
1006
- fs = require('fs')
1007
-
1008
- Object.assign(globalThis, {
1009
- self: globalThis,
1010
- require,
1011
- Worker: nodeWorkerThreads.Worker,
1012
- importScripts: function (f) {
1013
- (0, eval)(fs.readFileSync(f, 'utf8') + '//# sourceURL=' + f)
1014
- },
1015
- postMessage: function (msg) {
1016
- parentPort.postMessage(msg)
1017
- }
1018
- })
1019
-
1020
- WASI = require('wasi').WASI
1021
- emnapiCore = require('@emnapi/core')
1022
- } else {
1023
- importScripts('./node_modules/memfs-browser/dist/memfs.js')
1024
- importScripts('./node_modules/@tybys/wasm-util/dist/wasm-util.min.js')
1025
- importScripts('./node_modules/@emnapi/core/dist/emnapi-core.js')
1026
- emnapiCore = globalThis.emnapiCore
1027
-
1028
- const { Volume, createFsFromVolume } = memfs
1029
- fs = createFsFromVolume(Volume.fromJSON({
1030
- '/': null
1031
- }))
1032
-
1033
- WASI = globalThis.wasmUtil.WASI
1034
- }
1035
-
1036
- const { instantiateNapiModuleSync, MessageHandler } = emnapiCore
1037
-
1038
- const handler = new MessageHandler({
1039
- onLoad ({ wasmModule, wasmMemory }) {
1040
- const wasi = new WASI({ fs })
1041
-
1042
- return instantiateNapiModuleSync(wasmModule, {
1043
- childThread: true,
1044
- wasi,
1045
- overwriteImports (importObject) {
1046
- importObject.env.memory = wasmMemory
1047
- }
1048
- })
1049
- }
1050
- })
1051
-
1052
- globalThis.onmessage = function (e) {
1053
- handler.handle(e)
1054
- // handle other messages
1055
- }
1056
- })()
1057
- ```
1058
-
1059
- ## Preprocess Macro Options
1060
-
1061
- ### `-DEMNAPI_WORKER_POOL_SIZE=4`
1062
-
1063
- This is [`UV_THREADPOOL_SIZE`](http://docs.libuv.org/en/v1.x/threadpool.html?highlight=UV_THREADPOOL_SIZE) equivalent at compile time, if not predefined, emnapi will read `asyncWorkPoolSize` option or `UV_THREADPOOL_SIZE` from Emscripten [environment variable](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#interacting-with-code-environment-variables) at runtime:
1064
-
1065
- ```js
1066
- Module.init({
1067
- // ...
1068
- asyncWorkPoolSize: 2
1069
- })
505
+ Note: For browsers, all the multithreaded features relying on Web Workers (Emscripten pthread also relying on Web Workers)
506
+ require cross-origin isolation to enable `SharedArrayBuffer`. You can make a page cross-origin isolated
507
+ by serving the page with these headers:
1070
508
 
1071
- // if asyncWorkPoolSize is not specified
1072
- Module.preRun = Module.preRun || [];
1073
- Module.preRun.push(function () {
1074
- if (typeof ENV !== 'undefined') {
1075
- ENV.UV_THREADPOOL_SIZE = '2';
1076
- }
1077
- });
1078
509
  ```
1079
-
1080
- ```js
1081
- // wasi
1082
- instantiateNapiModule({
1083
- // ...
1084
- asyncWorkPoolSize: 2
1085
- })
1086
- // if asyncWorkPoolSize is not specified
1087
- new WASI({
1088
- env: {
1089
- UV_THREADPOOL_SIZE: '2'
1090
- }
1091
- })
510
+ Cross-Origin-Embedder-Policy: require-corp
511
+ Cross-Origin-Opener-Policy: same-origin
1092
512
  ```
1093
-
1094
- It represent max of `EMNAPI_WORKER_POOL_SIZE` async work (`napi_queue_async_work`) can be executed in parallel. Default is not defined.
1095
-
1096
- You can set both `PTHREAD_POOL_SIZE` and `EMNAPI_WORKER_POOL_SIZE` to `number of CPU cores` in general.
1097
- If you use another library function which may create `N` child threads in async work,
1098
- then you need to set `PTHREAD_POOL_SIZE` to `EMNAPI_WORKER_POOL_SIZE * (N + 1)`.
1099
-
1100
- This option only has effect if you use `-pthread`.
1101
- Emnapi will create `EMNAPI_WORKER_POOL_SIZE` threads when initializing,
1102
- it will throw error if `PTHREAD_POOL_SIZE < EMNAPI_WORKER_POOL_SIZE && PTHREAD_POOL_SIZE_STRICT == 2`.
1103
-
1104
- See [Issue #8](https://github.com/toyobayashi/emnapi/issues/8) for more detail.
1105
-
1106
- ### `-DEMNAPI_NEXTTICK_TYPE=0`
1107
-
1108
- This option only has effect if you use `-pthread`, Default is `0`.
1109
- Tell emnapi how to delay async work in `uv_async_send` / `uv__async_close`.
1110
-
1111
- - `0`: Use `setImmediate()` (Node.js native `setImmediate` or browser `MessageChannel` and `port.postMessage`)
1112
- - `1`: Use `Promise.resolve().then()`
1113
-
1114
- ### `-DEMNAPI_USE_PROXYING=1`
1115
-
1116
- This option only has effect if you use emscripten `-pthread`. Default is `1` if emscripten version `>= 3.1.9`, else `0`.
1117
-
1118
- - `0`
1119
-
1120
- Use JavaScript implementation to send async work from worker threads, runtime code will access the Emscripten internal `PThread` object to add custom worker message listener.
1121
-
1122
- - `1`:
1123
-
1124
- Use Emscripten [proxying API](https://emscripten.org/docs/api_reference/proxying.h.html) to send async work from worker threads in C. If you experience something wrong, you can switch set this to `0` and feel free to create an issue.