|
@@ -26,6 +26,7 @@
|
|
|
#include "shell/browser/api/electron_api_app.h"
|
|
|
#include "shell/common/api/electron_bindings.h"
|
|
|
#include "shell/common/electron_command_line.h"
|
|
|
+#include "shell/common/gin_converters/callback_converter.h"
|
|
|
#include "shell/common/gin_converters/file_path_converter.h"
|
|
|
#include "shell/common/gin_helper/dictionary.h"
|
|
|
#include "shell/common/gin_helper/event.h"
|
|
@@ -33,8 +34,11 @@
|
|
|
#include "shell/common/gin_helper/locker.h"
|
|
|
#include "shell/common/gin_helper/microtasks_scope.h"
|
|
|
#include "shell/common/mac/main_application_bundle.h"
|
|
|
+#include "shell/common/world_ids.h"
|
|
|
+#include "third_party/blink/public/web/web_local_frame.h"
|
|
|
#include "third_party/blink/renderer/bindings/core/v8/v8_initializer.h" // nogncheck
|
|
|
#include "third_party/electron_node/src/debug_utils.h"
|
|
|
+#include "third_party/electron_node/src/module_wrap.h"
|
|
|
|
|
|
#if !IS_MAS_BUILD()
|
|
|
#include "shell/common/crash_keys.h"
|
|
@@ -171,6 +175,64 @@ bool AllowWasmCodeGenerationCallback(v8::Local<v8::Context> context,
|
|
|
return node::AllowWasmCodeGenerationCallback(context, source);
|
|
|
}
|
|
|
|
|
|
+v8::MaybeLocal<v8::Promise> HostImportModuleDynamically(
|
|
|
+ v8::Local<v8::Context> context,
|
|
|
+ v8::Local<v8::Data> v8_host_defined_options,
|
|
|
+ v8::Local<v8::Value> v8_referrer_resource_url,
|
|
|
+ v8::Local<v8::String> v8_specifier,
|
|
|
+ v8::Local<v8::FixedArray> v8_import_assertions) {
|
|
|
+ if (node::Environment::GetCurrent(context) == nullptr) {
|
|
|
+ if (electron::IsBrowserProcess() || electron::IsUtilityProcess())
|
|
|
+ return v8::MaybeLocal<v8::Promise>();
|
|
|
+ return blink::V8Initializer::HostImportModuleDynamically(
|
|
|
+ context, v8_host_defined_options, v8_referrer_resource_url,
|
|
|
+ v8_specifier, v8_import_assertions);
|
|
|
+ }
|
|
|
+
|
|
|
+ // If we're running with contextIsolation enabled in the renderer process,
|
|
|
+ // fall back to Blink's logic.
|
|
|
+ if (electron::IsRendererProcess()) {
|
|
|
+ blink::WebLocalFrame* frame =
|
|
|
+ blink::WebLocalFrame::FrameForContext(context);
|
|
|
+ if (!frame || frame->GetScriptContextWorldId(context) !=
|
|
|
+ electron::WorldIDs::ISOLATED_WORLD_ID) {
|
|
|
+ return blink::V8Initializer::HostImportModuleDynamically(
|
|
|
+ context, v8_host_defined_options, v8_referrer_resource_url,
|
|
|
+ v8_specifier, v8_import_assertions);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return node::loader::ImportModuleDynamically(
|
|
|
+ context, v8_host_defined_options, v8_referrer_resource_url, v8_specifier,
|
|
|
+ v8_import_assertions);
|
|
|
+}
|
|
|
+
|
|
|
+void HostInitializeImportMetaObject(v8::Local<v8::Context> context,
|
|
|
+ v8::Local<v8::Module> module,
|
|
|
+ v8::Local<v8::Object> meta) {
|
|
|
+ if (node::Environment::GetCurrent(context) == nullptr) {
|
|
|
+ if (electron::IsBrowserProcess() || electron::IsUtilityProcess())
|
|
|
+ return;
|
|
|
+ return blink::V8Initializer::HostGetImportMetaProperties(context, module,
|
|
|
+ meta);
|
|
|
+ }
|
|
|
+
|
|
|
+ // If we're running with contextIsolation enabled in the renderer process,
|
|
|
+ // fall back to Blink's logic.
|
|
|
+ if (electron::IsRendererProcess()) {
|
|
|
+ blink::WebLocalFrame* frame =
|
|
|
+ blink::WebLocalFrame::FrameForContext(context);
|
|
|
+ if (!frame || frame->GetScriptContextWorldId(context) !=
|
|
|
+ electron::WorldIDs::ISOLATED_WORLD_ID) {
|
|
|
+ return blink::V8Initializer::HostGetImportMetaProperties(context, module,
|
|
|
+ meta);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return node::loader::ModuleWrap::HostInitializeImportMetaObjectCallback(
|
|
|
+ context, module, meta);
|
|
|
+}
|
|
|
+
|
|
|
v8::ModifyCodeGenerationFromStringsResult ModifyCodeGenerationFromStrings(
|
|
|
v8::Local<v8::Context> context,
|
|
|
v8::Local<v8::Value> source,
|
|
@@ -481,7 +543,8 @@ std::shared_ptr<node::Environment> NodeBindings::CreateEnvironment(
|
|
|
v8::Handle<v8::Context> context,
|
|
|
node::MultiIsolatePlatform* platform,
|
|
|
std::vector<std::string> args,
|
|
|
- std::vector<std::string> exec_args) {
|
|
|
+ std::vector<std::string> exec_args,
|
|
|
+ absl::optional<base::RepeatingCallback<void()>> on_app_code_ready) {
|
|
|
// Feed node the path to initialization script.
|
|
|
std::string process_type;
|
|
|
switch (browser_env_) {
|
|
@@ -529,7 +592,8 @@ std::shared_ptr<node::Environment> NodeBindings::CreateEnvironment(
|
|
|
node::Environment* env;
|
|
|
uint64_t flags = node::EnvironmentFlags::kDefaultFlags |
|
|
|
node::EnvironmentFlags::kHideConsoleWindows |
|
|
|
- node::EnvironmentFlags::kNoGlobalSearchPaths;
|
|
|
+ node::EnvironmentFlags::kNoGlobalSearchPaths |
|
|
|
+ node::EnvironmentFlags::kNoRegisterESMLoader;
|
|
|
|
|
|
if (browser_env_ == BrowserEnvironment::kRenderer ||
|
|
|
browser_env_ == BrowserEnvironment::kWorker) {
|
|
@@ -541,8 +605,7 @@ std::shared_ptr<node::Environment> NodeBindings::CreateEnvironment(
|
|
|
// for processes that already have these defined by DOM.
|
|
|
// Check //third_party/electron_node/lib/internal/bootstrap/node.js
|
|
|
// for the list of overrides on globalThis.
|
|
|
- flags |= node::EnvironmentFlags::kNoRegisterESMLoader |
|
|
|
- node::EnvironmentFlags::kNoBrowserGlobals |
|
|
|
+ flags |= node::EnvironmentFlags::kNoBrowserGlobals |
|
|
|
node::EnvironmentFlags::kNoCreateInspector;
|
|
|
}
|
|
|
|
|
@@ -635,6 +698,10 @@ std::shared_ptr<node::Environment> NodeBindings::CreateEnvironment(
|
|
|
}
|
|
|
|
|
|
node::SetIsolateUpForNode(context->GetIsolate(), is);
|
|
|
+ context->GetIsolate()->SetHostImportModuleDynamicallyCallback(
|
|
|
+ HostImportModuleDynamically);
|
|
|
+ context->GetIsolate()->SetHostInitializeImportMetaObjectCallback(
|
|
|
+ HostInitializeImportMetaObject);
|
|
|
|
|
|
gin_helper::Dictionary process(context->GetIsolate(), env->process_object());
|
|
|
process.SetReadOnly("type", process_type);
|
|
@@ -644,6 +711,17 @@ std::shared_ptr<node::Environment> NodeBindings::CreateEnvironment(
|
|
|
base::PathService::Get(content::CHILD_PROCESS_EXE, &helper_exec_path);
|
|
|
process.Set("helperExecPath", helper_exec_path);
|
|
|
|
|
|
+ if (browser_env_ == BrowserEnvironment::kBrowser ||
|
|
|
+ browser_env_ == BrowserEnvironment::kRenderer) {
|
|
|
+ if (on_app_code_ready) {
|
|
|
+ process.SetMethod("appCodeLoaded", std::move(*on_app_code_ready));
|
|
|
+ } else {
|
|
|
+ process.SetMethod("appCodeLoaded",
|
|
|
+ base::BindRepeating(&NodeBindings::SetAppCodeLoaded,
|
|
|
+ base::Unretained(this)));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
auto env_deleter = [isolate, isolate_data,
|
|
|
context = v8::Global<v8::Context>{isolate, context}](
|
|
|
node::Environment* nenv) mutable {
|
|
@@ -664,7 +742,8 @@ std::shared_ptr<node::Environment> NodeBindings::CreateEnvironment(
|
|
|
|
|
|
std::shared_ptr<node::Environment> NodeBindings::CreateEnvironment(
|
|
|
v8::Handle<v8::Context> context,
|
|
|
- node::MultiIsolatePlatform* platform) {
|
|
|
+ node::MultiIsolatePlatform* platform,
|
|
|
+ absl::optional<base::RepeatingCallback<void()>> on_app_code_ready) {
|
|
|
#if BUILDFLAG(IS_WIN)
|
|
|
auto& electron_args = ElectronCommandLine::argv();
|
|
|
std::vector<std::string> args(electron_args.size());
|
|
@@ -673,7 +752,7 @@ std::shared_ptr<node::Environment> NodeBindings::CreateEnvironment(
|
|
|
#else
|
|
|
auto args = ElectronCommandLine::argv();
|
|
|
#endif
|
|
|
- return CreateEnvironment(context, platform, args, {});
|
|
|
+ return CreateEnvironment(context, platform, args, {}, on_app_code_ready);
|
|
|
}
|
|
|
|
|
|
void NodeBindings::LoadEnvironment(node::Environment* env) {
|
|
@@ -716,6 +795,37 @@ void NodeBindings::StartPolling() {
|
|
|
UvRunOnce();
|
|
|
}
|
|
|
|
|
|
+void NodeBindings::SetAppCodeLoaded() {
|
|
|
+ app_code_loaded_ = true;
|
|
|
+}
|
|
|
+
|
|
|
+void NodeBindings::JoinAppCode() {
|
|
|
+ // We can only "join" app code to the main thread in the browser process
|
|
|
+ if (browser_env_ != BrowserEnvironment::kBrowser) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ auto* browser = Browser::Get();
|
|
|
+ node::Environment* env = uv_env();
|
|
|
+
|
|
|
+ if (!env)
|
|
|
+ return;
|
|
|
+
|
|
|
+ v8::HandleScope handle_scope(env->isolate());
|
|
|
+ // Enter node context while dealing with uv events.
|
|
|
+ v8::Context::Scope context_scope(env->context());
|
|
|
+
|
|
|
+ // Pump the event loop until we get the signal that the app code has finished
|
|
|
+ // loading
|
|
|
+ while (!app_code_loaded_ && !browser->is_shutting_down()) {
|
|
|
+ int r = uv_run(uv_loop_, UV_RUN_ONCE);
|
|
|
+ if (r == 0) {
|
|
|
+ base::RunLoop().QuitWhenIdle(); // Quit from uv.
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void NodeBindings::UvRunOnce() {
|
|
|
node::Environment* env = uv_env();
|
|
|
|