Repository: electron/electron
Pull request: fix: new WebAssembly API support in Node.js

#### Description of Change

Closes https://github.com/electron/electron/issues/36282. 

Re-enables support for `WebAssembly.{compileStreaming|instantiateStreaming}` in Node.js. We need to reconfigure initialization order a bit here for reasons stated in #36282 as gin conflicts with how Node.js controls isolate initialization.

#### Checklist
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->

- [x] PR description included and stakeholders cc'd
- [x] `npm test` passes
- [x] tests are [changed or added](https://github.com/electron/electron/blob/main/docs/development/testing.md)
- [x] [PR release notes](https://github.com/electron/clerk/blob/master/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/master/README.md#examples).

#### Release Notes

Notes: Enabled support for  `WebAssembly.{compileStreaming|instantiateStreaming}` in Node.js.

Changed files:
filename: script/node-disabled-tests.json
patch: @@ -121,7 +121,6 @@
   "parallel/test-trace-events-v8",
   "parallel/test-trace-events-vm",
   "parallel/test-trace-events-worker-metadata",
-  "parallel/test-wasm-web-api",
   "parallel/test-webcrypto-derivebits-cfrg",
   "parallel/test-webcrypto-derivekey-cfrg",
   "parallel/test-webcrypto-encrypt-decrypt",

filename: shell/app/node_main.cc
patch: @@ -205,7 +205,11 @@ int NodeMain(int argc, char* argv[]) {
     uv_loop_configure(loop, UV_METRICS_IDLE_TIME);
 
     // Initialize gin::IsolateHolder.
-    JavascriptEnvironment gin_env(loop);
+    bool setup_wasm_streaming =
+        node::per_process::cli_options->get_per_isolate_options()
+            ->get_per_env_options()
+            ->experimental_fetch;
+    JavascriptEnvironment gin_env(loop, setup_wasm_streaming);
 
     v8::Isolate* isolate = gin_env.isolate();
 
@@ -226,8 +230,7 @@ int NodeMain(int argc, char* argv[]) {
           static_cast<node::EnvironmentFlags::Flags>(env_flags));
       CHECK_NE(nullptr, env);
 
-      node::IsolateSettings is;
-      node::SetIsolateUpForNode(isolate, is);
+      node::SetIsolateUpForNode(isolate);
 
       gin_helper::Dictionary process(isolate, env->process_object());
       process.SetMethod("crash", &ElectronBindings::Crash);

filename: shell/browser/javascript_environment.cc
patch: @@ -24,6 +24,7 @@
 #include "shell/common/gin_helper/cleaned_up_at_exit.h"
 #include "shell/common/node_includes.h"
 #include "third_party/blink/public/common/switches.h"
+#include "third_party/electron_node/src/node_wasm_web_api.h"
 
 namespace {
 v8::Isolate* g_isolate;
@@ -73,8 +74,9 @@ struct base::trace_event::TraceValue::Helper<
 
 namespace electron {
 
-JavascriptEnvironment::JavascriptEnvironment(uv_loop_t* event_loop)
-    : isolate_(Initialize(event_loop)),
+JavascriptEnvironment::JavascriptEnvironment(uv_loop_t* event_loop,
+                                             bool setup_wasm_streaming)
+    : isolate_(Initialize(event_loop, setup_wasm_streaming)),
       isolate_holder_(base::ThreadTaskRunnerHandle::Get(),
                       gin::IsolateHolder::kSingleThread,
                       gin::IsolateHolder::kAllowAtomicsWait,
@@ -247,7 +249,8 @@ class TracingControllerImpl : public node::tracing::TracingController {
   }
 };
 
-v8::Isolate* JavascriptEnvironment::Initialize(uv_loop_t* event_loop) {
+v8::Isolate* JavascriptEnvironment::Initialize(uv_loop_t* event_loop,
+                                               bool setup_wasm_streaming) {
   auto* cmd = base::CommandLine::ForCurrentProcess();
 
   // --js-flags.
@@ -276,6 +279,17 @@ v8::Isolate* JavascriptEnvironment::Initialize(uv_loop_t* event_loop) {
 
   v8::Isolate* isolate = v8::Isolate::Allocate();
   platform_->RegisterIsolate(isolate, event_loop);
+
+  // This is done here because V8 checks for the callback in NewContext.
+  // Our setup order doesn't allow for calling SetupIsolateForNode
+  // before NewContext without polluting JavaScriptEnvironment with
+  // Node.js logic and so we conditionally do it here to keep
+  // concerns separate.
+  if (setup_wasm_streaming) {
+    isolate->SetWasmStreamingCallback(
+        node::wasm_web_api::StartStreamingCompilation);
+  }
+
   g_isolate = isolate;
 
   return isolate;

filename: shell/browser/javascript_environment.h
patch: @@ -22,7 +22,8 @@ class MicrotasksRunner;
 // Manage the V8 isolate and context automatically.
 class JavascriptEnvironment {
  public:
-  explicit JavascriptEnvironment(uv_loop_t* event_loop);
+  explicit JavascriptEnvironment(uv_loop_t* event_loop,
+                                 bool setup_wasm_streaming = false);
   ~JavascriptEnvironment();
 
   // disable copy
@@ -41,7 +42,7 @@ class JavascriptEnvironment {
   static v8::Isolate* GetIsolate();
 
  private:
-  v8::Isolate* Initialize(uv_loop_t* event_loop);
+  v8::Isolate* Initialize(uv_loop_t* event_loop, bool setup_wasm_streaming);
   std::unique_ptr<node::MultiIsolatePlatform> platform_;
 
   v8::Isolate* isolate_;