chore: remove node patches by using the preload feature (#41080)
This commit is contained in:
		
					parent
					
						
							
								031d636823
							
						
					
				
			
			
				commit
				
					
						d13a93fb61
					
				
			
		
					 21 changed files with 403 additions and 135 deletions
				
			
		
							
								
								
									
										22
									
								
								BUILD.gn
									
										
									
									
									
								
							
							
						
						
									
										22
									
								
								BUILD.gn
									
										
									
									
									
								
							|  | @ -166,15 +166,6 @@ npm_action("build_electron_definitions") { | |||
|   outputs = [ "$target_gen_dir/tsc/typings/electron.d.ts" ] | ||||
| } | ||||
| 
 | ||||
| webpack_build("electron_asar_bundle") { | ||||
|   deps = [ ":build_electron_definitions" ] | ||||
| 
 | ||||
|   inputs = auto_filenames.asar_bundle_deps | ||||
| 
 | ||||
|   config_file = "//electron/build/webpack/webpack.config.asar.js" | ||||
|   out_file = "$target_gen_dir/js2c/asar_bundle.js" | ||||
| } | ||||
| 
 | ||||
| webpack_build("electron_browser_bundle") { | ||||
|   deps = [ ":build_electron_definitions" ] | ||||
| 
 | ||||
|  | @ -220,6 +211,15 @@ webpack_build("electron_isolated_renderer_bundle") { | |||
|   out_file = "$target_gen_dir/js2c/isolated_bundle.js" | ||||
| } | ||||
| 
 | ||||
| webpack_build("electron_node_bundle") { | ||||
|   deps = [ ":build_electron_definitions" ] | ||||
| 
 | ||||
|   inputs = auto_filenames.node_bundle_deps | ||||
| 
 | ||||
|   config_file = "//electron/build/webpack/webpack.config.node.js" | ||||
|   out_file = "$target_gen_dir/js2c/node_init.js" | ||||
| } | ||||
| 
 | ||||
| webpack_build("electron_utility_bundle") { | ||||
|   deps = [ ":build_electron_definitions" ] | ||||
| 
 | ||||
|  | @ -231,9 +231,9 @@ webpack_build("electron_utility_bundle") { | |||
| 
 | ||||
| action("electron_js2c") { | ||||
|   deps = [ | ||||
|     ":electron_asar_bundle", | ||||
|     ":electron_browser_bundle", | ||||
|     ":electron_isolated_renderer_bundle", | ||||
|     ":electron_node_bundle", | ||||
|     ":electron_renderer_bundle", | ||||
|     ":electron_sandboxed_renderer_bundle", | ||||
|     ":electron_utility_bundle", | ||||
|  | @ -242,9 +242,9 @@ action("electron_js2c") { | |||
|   ] | ||||
| 
 | ||||
|   sources = [ | ||||
|     "$target_gen_dir/js2c/asar_bundle.js", | ||||
|     "$target_gen_dir/js2c/browser_init.js", | ||||
|     "$target_gen_dir/js2c/isolated_bundle.js", | ||||
|     "$target_gen_dir/js2c/node_init.js", | ||||
|     "$target_gen_dir/js2c/renderer_init.js", | ||||
|     "$target_gen_dir/js2c/sandbox_bundle.js", | ||||
|     "$target_gen_dir/js2c/utility_init.js", | ||||
|  |  | |||
|  | @ -1,5 +0,0 @@ | |||
| module.exports = require('./webpack.config.base')({ | ||||
|   target: 'asar', | ||||
|   alwaysHasNode: true, | ||||
|   targetDeletesNodeGlobals: true | ||||
| }); | ||||
							
								
								
									
										4
									
								
								build/webpack/webpack.config.node.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								build/webpack/webpack.config.node.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | |||
| module.exports = require('./webpack.config.base')({ | ||||
|   target: 'node', | ||||
|   alwaysHasNode: true | ||||
| }); | ||||
|  | @ -336,10 +336,9 @@ auto_filenames = { | |||
|     "typings/internal-electron.d.ts", | ||||
|   ] | ||||
| 
 | ||||
|   asar_bundle_deps = [ | ||||
|     "lib/asar/fs-wrapper.ts", | ||||
|     "lib/asar/init.ts", | ||||
|     "lib/common/webpack-provider.ts", | ||||
|   node_bundle_deps = [ | ||||
|     "lib/node/asar-fs-wrapper.ts", | ||||
|     "lib/node/init.ts", | ||||
|     "package.json", | ||||
|     "tsconfig.electron.json", | ||||
|     "tsconfig.json", | ||||
|  |  | |||
|  | @ -1,3 +0,0 @@ | |||
| import { wrapFsWithAsar } from './fs-wrapper'; | ||||
| 
 | ||||
| wrapFsWithAsar(require('fs')); | ||||
							
								
								
									
										31
									
								
								lib/node/init.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								lib/node/init.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | |||
| // Initialize ASAR support in fs module.
 | ||||
| import { wrapFsWithAsar } from './asar-fs-wrapper'; | ||||
| wrapFsWithAsar(require('fs')); | ||||
| 
 | ||||
| // Hook child_process.fork.
 | ||||
| const cp = require('child_process'); | ||||
| const originalFork = cp.fork; | ||||
| cp.fork = (modulePath: string, args: any, options: any) => { | ||||
|   // Parse optional args.
 | ||||
|   if (args == null) { | ||||
|     args = []; | ||||
|   } else if (typeof args === 'object' && !Array.isArray(args)) { | ||||
|     options = args; | ||||
|     args = []; | ||||
|   } | ||||
|   // Fallback to original fork to report arg type errors.
 | ||||
|   if (typeof modulePath !== 'string' || !Array.isArray(args) || | ||||
|       (typeof options !== 'object' && typeof options !== 'undefined')) { | ||||
|     return originalFork(modulePath, args, options); | ||||
|   } | ||||
|   // When forking a child script, we setup a special environment to make
 | ||||
|   // the electron binary run like upstream Node.js.
 | ||||
|   options = options ?? {}; | ||||
|   options.env = Object.create(options.env || process.env); | ||||
|   options.env.ELECTRON_RUN_AS_NODE = 1; | ||||
|   // On mac the child script runs in helper executable.
 | ||||
|   if (!options.execPath && process.platform === 'darwin') { | ||||
|     options.execPath = process.helperExecPath; | ||||
|   } | ||||
|   return originalFork(modulePath, args, options); | ||||
| }; | ||||
|  | @ -1,5 +1,3 @@ | |||
| refactor_alter_child_process_fork_to_use_execute_script_with.patch | ||||
| feat_initialize_asar_support.patch | ||||
| expose_get_builtin_module_function.patch | ||||
| build_add_gn_build_files.patch | ||||
| fix_add_default_values_for_variables_in_common_gypi.patch | ||||
|  | @ -46,3 +44,4 @@ build_do_not_rely_on_gn_helpers_in_gn_build.patch | |||
| test_make_test-node-output-v8-warning_generic.patch | ||||
| test_match_wpt_streams_transferable_transform-stream-members_any_js.patch | ||||
| build_ensure_v8_pointer_compression_sandbox_is_enabled_on_64bit.patch | ||||
| src_preload_function_for_environment.patch | ||||
|  |  | |||
|  | @ -26,10 +26,10 @@ index 1f3b719048f2477de183e2856b9b8eee8502f708..21116088c101f4679b5a5f41762ce710 | |||
|          try { | ||||
|            resolvedArgv = Module._resolveFilename(process.argv[1], null, false); | ||||
| diff --git a/lib/internal/process/pre_execution.js b/lib/internal/process/pre_execution.js
 | ||||
| index fc8f61ee6d30cf18951ec7a5eb5f09a9583a85ae..61858f6bdcdbc231d7e2327e42732ad928d47ac7 100644
 | ||||
| index 9142fed75e9050fcc17c01208e82f1bc57923fcd..157a85623c7eb5338baa77aba5dc448a4614ded0 100644
 | ||||
| --- a/lib/internal/process/pre_execution.js
 | ||||
| +++ b/lib/internal/process/pre_execution.js
 | ||||
| @@ -238,12 +238,14 @@ function patchProcessObject(expandArgv1) {
 | ||||
| @@ -232,12 +232,14 @@ function patchProcessObject(expandArgv1) {
 | ||||
|    if (expandArgv1 && process.argv[1] && | ||||
|        !StringPrototypeStartsWith(process.argv[1], '-')) { | ||||
|      // Expand process.argv[1] into a full path. | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ to child processes spawned with `ELECTRON_RUN_AS_NODE` which is used | |||
| by the crashpad client to connect with the handler process. | ||||
| 
 | ||||
| diff --git a/lib/child_process.js b/lib/child_process.js
 | ||||
| index 9dd33ecbac3a5d516f9bff76fdbe1a8aece531f2..0464ecc7b53389cdff97a7fe4cb01582e8b72dbb 100644
 | ||||
| index 449013906e93e59568a90264d5372a3962db6cb0..168163001f13b641bc284fd01a71f075e1ada94f 100644
 | ||||
| --- a/lib/child_process.js
 | ||||
| +++ b/lib/child_process.js
 | ||||
| @@ -61,6 +61,7 @@ let debug = require('internal/util/debuglog').debuglog(
 | ||||
|  | @ -19,7 +19,7 @@ index 9dd33ecbac3a5d516f9bff76fdbe1a8aece531f2..0464ecc7b53389cdff97a7fe4cb01582 | |||
|   | ||||
|  const { | ||||
|    AbortError, | ||||
| @@ -162,7 +163,6 @@ function fork(modulePath, args = [], options) {
 | ||||
| @@ -154,7 +155,6 @@ function fork(modulePath, args = [], options) {
 | ||||
|        ArrayPrototypeSplice(execArgv, index - 1, 2); | ||||
|      } | ||||
|    } | ||||
|  | @ -27,7 +27,7 @@ index 9dd33ecbac3a5d516f9bff76fdbe1a8aece531f2..0464ecc7b53389cdff97a7fe4cb01582 | |||
|    args = [...execArgv, modulePath, ...args]; | ||||
|   | ||||
|    if (typeof options.stdio === 'string') { | ||||
| @@ -625,6 +625,21 @@ function normalizeSpawnArguments(file, args, options) {
 | ||||
| @@ -617,6 +617,21 @@ function normalizeSpawnArguments(file, args, options) {
 | ||||
|                      'options.windowsVerbatimArguments'); | ||||
|    } | ||||
|   | ||||
|  |  | |||
|  | @ -1,37 +0,0 @@ | |||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Shelley Vohr <shelley.vohr@gmail.com> | ||||
| Date: Thu, 13 Sep 2018 08:56:07 -0700 | ||||
| Subject: feat: initialize asar support | ||||
| 
 | ||||
| This patch initializes asar support in Node.js. | ||||
| 
 | ||||
| diff --git a/lib/internal/process/pre_execution.js b/lib/internal/process/pre_execution.js
 | ||||
| index 9142fed75e9050fcc17c01208e82f1bc57923fcd..fc8f61ee6d30cf18951ec7a5eb5f09a9583a85ae 100644
 | ||||
| --- a/lib/internal/process/pre_execution.js
 | ||||
| +++ b/lib/internal/process/pre_execution.js
 | ||||
| @@ -87,6 +87,7 @@ function prepareShadowRealmExecution() {
 | ||||
|    }); | ||||
|  } | ||||
|   | ||||
| +let processLinkedBinding = process._linkedBinding;
 | ||||
|  function prepareExecution(options) { | ||||
|    const { expandArgv1, initializeModules, isMainThread } = options; | ||||
|   | ||||
| @@ -193,12 +194,17 @@ function setupUserModules(forceDefaultLoader = false) {
 | ||||
|    } | ||||
|    // Need to be done after --require setup. | ||||
|    initializeFrozenIntrinsics(); | ||||
| +  setupAsarSupport();
 | ||||
|  } | ||||
|   | ||||
|  function refreshRuntimeOptions() { | ||||
|    refreshOptions(); | ||||
|  } | ||||
|   | ||||
| +function setupAsarSupport() {
 | ||||
| +  processLinkedBinding('electron_common_asar').initAsarSupport(require);
 | ||||
| +}
 | ||||
| +
 | ||||
|  /** | ||||
|   * Patch the process object with legacy properties and normalizations. | ||||
|   * Replace `process.argv[0]` with `process.execPath`, preserving the original `argv[0]` value as `process.argv0`. | ||||
|  | @ -1,27 +0,0 @@ | |||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Shelley Vohr <shelley.vohr@gmail.com> | ||||
| Date: Mon, 30 Jul 2018 10:30:35 -0700 | ||||
| Subject: refactor: alter child_process.fork to use execute script with | ||||
|  Electron | ||||
| 
 | ||||
| When forking a child script, we setup a special environment to make the Electron binary run like the upstream node. On Mac, we use the helper app as node binary. | ||||
| 
 | ||||
| diff --git a/lib/child_process.js b/lib/child_process.js
 | ||||
| index 449013906e93e59568a90264d5372a3962db6cb0..9dd33ecbac3a5d516f9bff76fdbe1a8aece531f2 100644
 | ||||
| --- a/lib/child_process.js
 | ||||
| +++ b/lib/child_process.js
 | ||||
| @@ -139,6 +139,14 @@ function fork(modulePath, args = [], options) {
 | ||||
|      validateObject(options, 'options'); | ||||
|    } | ||||
|    options = { __proto__: null, ...options, shell: false }; | ||||
| +  // When forking a child script, we setup a special environment to make
 | ||||
| +  // the electron binary run like upstream Node.js
 | ||||
| +  options.env = Object.create(options.env || process.env)
 | ||||
| +  options.env.ELECTRON_RUN_AS_NODE = 1;
 | ||||
| +
 | ||||
| +  if (!options.execPath && process.type && process.platform == 'darwin') {
 | ||||
| +     options.execPath = process.helperExecPath;
 | ||||
| +  }
 | ||||
|    options.execPath = options.execPath || process.execPath; | ||||
|    validateArgumentNullCheck(options.execPath, 'options.execPath'); | ||||
|   | ||||
							
								
								
									
										299
									
								
								patches/node/src_preload_function_for_environment.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								patches/node/src_preload_function_for_environment.patch
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,299 @@ | |||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Cheng Zhao <zcbenz@gmail.com> | ||||
| Date: Mon, 22 Jan 2024 13:45:55 +0900 | ||||
| Subject: src: preload function for Environment | ||||
| 
 | ||||
| https://github.com/nodejs/node/pull/51539 | ||||
| 
 | ||||
| This PR adds a |preload| arg to the node::CreateEnvironment to allow | ||||
| embedders to set a preload function for the environment, which will run | ||||
| after the environment is loaded and before the main script runs. | ||||
| 
 | ||||
| This is similiar to the --require CLI option, but runs a C++ function, | ||||
| and can only be set by embedders. | ||||
| 
 | ||||
| The preload function can be used by embedders to inject scripts before | ||||
| running the main script, for example: | ||||
| 1. In Electron it is used to initialize the ASAR virtual filesystem, | ||||
|    inject custom process properties, etc. | ||||
| 2. In VS Code it can be used to reset the module search paths for | ||||
|    extensions. | ||||
| 
 | ||||
| diff --git a/lib/internal/process/pre_execution.js b/lib/internal/process/pre_execution.js
 | ||||
| index 157a85623c7eb5338baa77aba5dc448a4614ded0..701f91f1c9603c1da03e0fe6d20c8627c8d644fb 100644
 | ||||
| --- a/lib/internal/process/pre_execution.js
 | ||||
| +++ b/lib/internal/process/pre_execution.js
 | ||||
| @@ -185,6 +185,9 @@ function setupUserModules(forceDefaultLoader = false) {
 | ||||
|    initializeESMLoader(forceDefaultLoader); | ||||
|    const CJSLoader = require('internal/modules/cjs/loader'); | ||||
|    assert(!CJSLoader.hasLoadedAnyUserCJSModule); | ||||
| +  if (getEmbedderOptions().hasEmbedderPreload) {
 | ||||
| +    runEmbedderPreload();
 | ||||
| +  }
 | ||||
|    // Do not enable preload modules if custom loaders are disabled. | ||||
|    // For example, loader workers are responsible for doing this themselves. | ||||
|    // And preload modules are not supported in ShadowRealm as well. | ||||
| @@ -742,6 +745,10 @@ function initializeFrozenIntrinsics() {
 | ||||
|    } | ||||
|  } | ||||
|   | ||||
| +function runEmbedderPreload() {
 | ||||
| +  internalBinding('mksnapshot').runEmbedderPreload(process, require);
 | ||||
| +}
 | ||||
| +
 | ||||
|  function loadPreloadModules() { | ||||
|    // For user code, we preload modules if `-r` is passed | ||||
|    const preloadModules = getOptionValue('--require'); | ||||
| diff --git a/src/api/environment.cc b/src/api/environment.cc
 | ||||
| index 9045de3b17c93c4864a1bb1024b08f7d1ffa83be..7c580e1ce1af66e010083240aaf8b0037dd41f2e 100644
 | ||||
| --- a/src/api/environment.cc
 | ||||
| +++ b/src/api/environment.cc
 | ||||
| @@ -442,7 +442,8 @@ Environment* CreateEnvironment(
 | ||||
|      const std::vector<std::string>& exec_args, | ||||
|      EnvironmentFlags::Flags flags, | ||||
|      ThreadId thread_id, | ||||
| -    std::unique_ptr<InspectorParentHandle> inspector_parent_handle) {
 | ||||
| +    std::unique_ptr<InspectorParentHandle> inspector_parent_handle,
 | ||||
| +    EmbedderPreloadCallback preload) {
 | ||||
|    Isolate* isolate = isolate_data->isolate(); | ||||
|   | ||||
|    Isolate::Scope isolate_scope(isolate); | ||||
| @@ -463,7 +464,8 @@ Environment* CreateEnvironment(
 | ||||
|                                       exec_args, | ||||
|                                       env_snapshot_info, | ||||
|                                       flags, | ||||
| -                                     thread_id);
 | ||||
| +                                     thread_id,
 | ||||
| +                                     std::move(preload));
 | ||||
|    CHECK_NOT_NULL(env); | ||||
|   | ||||
|    if (use_snapshot) { | ||||
| diff --git a/src/env-inl.h b/src/env-inl.h
 | ||||
| index 564de2990c09a54693686666f9ad66398ff76ab5..b10bc2396539b011dec6f09719251bfc842072af 100644
 | ||||
| --- a/src/env-inl.h
 | ||||
| +++ b/src/env-inl.h
 | ||||
| @@ -438,6 +438,10 @@ inline void Environment::set_embedder_entry_point(StartExecutionCallback&& fn) {
 | ||||
|    embedder_entry_point_ = std::move(fn); | ||||
|  } | ||||
|   | ||||
| +inline const EmbedderPreloadCallback& Environment::embedder_preload() const {
 | ||||
| +  return embedder_preload_;
 | ||||
| +}
 | ||||
| +
 | ||||
|  inline double Environment::new_async_id() { | ||||
|    async_hooks()->async_id_fields()[AsyncHooks::kAsyncIdCounter] += 1; | ||||
|    return async_hooks()->async_id_fields()[AsyncHooks::kAsyncIdCounter]; | ||||
| diff --git a/src/env.cc b/src/env.cc
 | ||||
| index ba575a04340b91709fb6c8710ab160a4ca1f8b77..76db0ac4ef72b902a7567a96cfd751ff879117b7 100644
 | ||||
| --- a/src/env.cc
 | ||||
| +++ b/src/env.cc
 | ||||
| @@ -767,7 +767,8 @@ Environment::Environment(IsolateData* isolate_data,
 | ||||
|                           const std::vector<std::string>& exec_args, | ||||
|                           const EnvSerializeInfo* env_info, | ||||
|                           EnvironmentFlags::Flags flags, | ||||
| -                         ThreadId thread_id)
 | ||||
| +                         ThreadId thread_id,
 | ||||
| +                         EmbedderPreloadCallback preload)
 | ||||
|      : isolate_(isolate), | ||||
|        isolate_data_(isolate_data), | ||||
|        async_hooks_(isolate, MAYBE_FIELD_PTR(env_info, async_hooks)), | ||||
| @@ -793,7 +794,8 @@ Environment::Environment(IsolateData* isolate_data,
 | ||||
|        flags_(flags), | ||||
|        thread_id_(thread_id.id == static_cast<uint64_t>(-1) | ||||
|                       ? AllocateEnvironmentThreadId().id | ||||
| -                     : thread_id.id) {
 | ||||
| +                     : thread_id.id),
 | ||||
| +      embedder_preload_(std::move(preload)) {
 | ||||
|    constexpr bool is_shared_ro_heap = | ||||
|  #ifdef NODE_V8_SHARED_RO_HEAP | ||||
|        true; | ||||
| diff --git a/src/env.h b/src/env.h
 | ||||
| index 448075e354c760a2dbd1dd763f40b7a645730250..a5aad9596953536b0a1f741dfbc4f21f6a961404 100644
 | ||||
| --- a/src/env.h
 | ||||
| +++ b/src/env.h
 | ||||
| @@ -635,7 +635,8 @@ class Environment : public MemoryRetainer {
 | ||||
|                const std::vector<std::string>& exec_args, | ||||
|                const EnvSerializeInfo* env_info, | ||||
|                EnvironmentFlags::Flags flags, | ||||
| -              ThreadId thread_id);
 | ||||
| +              ThreadId thread_id,
 | ||||
| +              EmbedderPreloadCallback preload);
 | ||||
|    void InitializeMainContext(v8::Local<v8::Context> context, | ||||
|                               const EnvSerializeInfo* env_info); | ||||
|    ~Environment() override; | ||||
| @@ -986,6 +987,8 @@ class Environment : public MemoryRetainer {
 | ||||
|    inline const StartExecutionCallback& embedder_entry_point() const; | ||||
|    inline void set_embedder_entry_point(StartExecutionCallback&& fn); | ||||
|   | ||||
| +  inline const EmbedderPreloadCallback& embedder_preload() const;
 | ||||
| +
 | ||||
|    inline void set_process_exit_handler( | ||||
|        std::function<void(Environment*, ExitCode)>&& handler); | ||||
|   | ||||
| @@ -1186,6 +1189,7 @@ class Environment : public MemoryRetainer {
 | ||||
|   | ||||
|    builtins::BuiltinLoader builtin_loader_; | ||||
|    StartExecutionCallback embedder_entry_point_; | ||||
| +  EmbedderPreloadCallback embedder_preload_;
 | ||||
|   | ||||
|    // Used by allocate_managed_buffer() and release_managed_buffer() to keep | ||||
|    // track of the BackingStore for a given pointer. | ||||
| diff --git a/src/node.h b/src/node.h
 | ||||
| index 36da93a7b41ea450a5f288ec17b61adae46ae178..09e044e86bab2cef42c86dbfc9bbcc743daf564d 100644
 | ||||
| --- a/src/node.h
 | ||||
| +++ b/src/node.h
 | ||||
| @@ -678,11 +678,23 @@ struct InspectorParentHandle {
 | ||||
|    virtual ~InspectorParentHandle() = default; | ||||
|  }; | ||||
|   | ||||
| +using EmbedderPreloadCallback =
 | ||||
| +    std::function<void(Environment* env,
 | ||||
| +                       v8::Local<v8::Value> process,
 | ||||
| +                       v8::Local<v8::Value> require)>;
 | ||||
| +
 | ||||
|  // TODO(addaleax): Maybe move per-Environment options parsing here. | ||||
|  // Returns nullptr when the Environment cannot be created e.g. there are | ||||
|  // pending JavaScript exceptions. | ||||
|  // `context` may be empty if an `EmbedderSnapshotData` instance was provided | ||||
|  // to `NewIsolate()` and `CreateIsolateData()`. | ||||
| +//
 | ||||
| +// The |preload| function will run before executing the entry point, which
 | ||||
| +// is usually used by embedders to inject scripts. The function is executed
 | ||||
| +// with preload(process, require), and the passed require function has access
 | ||||
| +// to internal Node.js modules. The |preload| function is inherited by worker
 | ||||
| +// threads and thus will run in work threads, so make sure the function is
 | ||||
| +// thread-safe.
 | ||||
|  NODE_EXTERN Environment* CreateEnvironment( | ||||
|      IsolateData* isolate_data, | ||||
|      v8::Local<v8::Context> context, | ||||
| @@ -690,7 +702,8 @@ NODE_EXTERN Environment* CreateEnvironment(
 | ||||
|      const std::vector<std::string>& exec_args, | ||||
|      EnvironmentFlags::Flags flags = EnvironmentFlags::kDefaultFlags, | ||||
|      ThreadId thread_id = {} /* allocates a thread id automatically */, | ||||
| -    std::unique_ptr<InspectorParentHandle> inspector_parent_handle = {});
 | ||||
| +    std::unique_ptr<InspectorParentHandle> inspector_parent_handle = {},
 | ||||
| +    EmbedderPreloadCallback preload = nullptr);
 | ||||
|   | ||||
|  // Returns a handle that can be passed to `LoadEnvironment()`, making the | ||||
|  // child Environment accessible to the inspector as if it were a Node.js Worker. | ||||
| diff --git a/src/node_options.cc b/src/node_options.cc
 | ||||
| index 48ce3f3b68a94fc35e5ce93a385ddbebb03741b9..39d34e18e483882a71145110962109711a1566e2 100644
 | ||||
| --- a/src/node_options.cc
 | ||||
| +++ b/src/node_options.cc
 | ||||
| @@ -1290,6 +1290,12 @@ void GetEmbedderOptions(const FunctionCallbackInfo<Value>& args) {
 | ||||
|            .IsNothing()) | ||||
|      return; | ||||
|   | ||||
| +  if (ret->Set(context,
 | ||||
| +               FIXED_ONE_BYTE_STRING(env->isolate(), "hasEmbedderPreload"),
 | ||||
| +               Boolean::New(isolate, env->embedder_preload() != nullptr))
 | ||||
| +          .IsNothing())
 | ||||
| +    return;
 | ||||
| +
 | ||||
|    args.GetReturnValue().Set(ret); | ||||
|  } | ||||
|   | ||||
| diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc
 | ||||
| index 562a47ddcc9c8e61590b7b09d84dc08ab4b3653d..325bebc1df9ad2e8b0bad468951cf1563ecefc14 100644
 | ||||
| --- a/src/node_snapshotable.cc
 | ||||
| +++ b/src/node_snapshotable.cc
 | ||||
| @@ -1369,6 +1369,13 @@ static void RunEmbedderEntryPoint(const FunctionCallbackInfo<Value>& args) {
 | ||||
|    } | ||||
|  } | ||||
|   | ||||
| +static void RunEmbedderPreload(const FunctionCallbackInfo<Value>& args) {
 | ||||
| +  Environment* env = Environment::GetCurrent(args);
 | ||||
| +  CHECK(env->embedder_preload());
 | ||||
| +  CHECK_EQ(args.Length(), 2);
 | ||||
| +  env->embedder_preload()(env, args[0], args[1]);
 | ||||
| +}
 | ||||
| +
 | ||||
|  void CompileSerializeMain(const FunctionCallbackInfo<Value>& args) { | ||||
|    CHECK(args[0]->IsString()); | ||||
|    Local<String> filename = args[0].As<String>(); | ||||
| @@ -1493,6 +1500,7 @@ void CreatePerIsolateProperties(IsolateData* isolate_data,
 | ||||
|                                  Local<ObjectTemplate> target) { | ||||
|    Isolate* isolate = isolate_data->isolate(); | ||||
|    SetMethod(isolate, target, "runEmbedderEntryPoint", RunEmbedderEntryPoint); | ||||
| +  SetMethod(isolate, target, "runEmbedderPreload", RunEmbedderPreload);
 | ||||
|    SetMethod(isolate, target, "compileSerializeMain", CompileSerializeMain); | ||||
|    SetMethod(isolate, target, "setSerializeCallback", SetSerializeCallback); | ||||
|    SetMethod(isolate, target, "setDeserializeCallback", SetDeserializeCallback); | ||||
| @@ -1506,6 +1514,7 @@ void CreatePerIsolateProperties(IsolateData* isolate_data,
 | ||||
|   | ||||
|  void RegisterExternalReferences(ExternalReferenceRegistry* registry) { | ||||
|    registry->Register(RunEmbedderEntryPoint); | ||||
| +  registry->Register(RunEmbedderPreload);
 | ||||
|    registry->Register(CompileSerializeMain); | ||||
|    registry->Register(SetSerializeCallback); | ||||
|    registry->Register(SetDeserializeCallback); | ||||
| diff --git a/src/node_worker.cc b/src/node_worker.cc
 | ||||
| index 900674bbe4c90e9aeb2013c06c9979864b06dcd5..2a22d986585e93ea00c6dcdca1f7b783ef0723f8 100644
 | ||||
| --- a/src/node_worker.cc
 | ||||
| +++ b/src/node_worker.cc
 | ||||
| @@ -63,6 +63,7 @@ Worker::Worker(Environment* env,
 | ||||
|        thread_id_(AllocateEnvironmentThreadId()), | ||||
|        name_(name), | ||||
|        env_vars_(env_vars), | ||||
| +      embedder_preload_(env->embedder_preload()),
 | ||||
|        snapshot_data_(snapshot_data) { | ||||
|    Debug(this, "Creating new worker instance with thread id %llu", | ||||
|          thread_id_.id); | ||||
| @@ -360,7 +361,8 @@ void Worker::Run() {
 | ||||
|              std::move(exec_argv_), | ||||
|              static_cast<EnvironmentFlags::Flags>(environment_flags_), | ||||
|              thread_id_, | ||||
| -            std::move(inspector_parent_handle_)));
 | ||||
| +            std::move(inspector_parent_handle_),
 | ||||
| +            std::move(embedder_preload_)));
 | ||||
|          if (is_stopped()) return; | ||||
|          CHECK_NOT_NULL(env_); | ||||
|          env_->set_env_vars(std::move(env_vars_)); | ||||
| diff --git a/src/node_worker.h b/src/node_worker.h
 | ||||
| index 531e2b5287010f9206ab4fd7f4dd0f3dec9fe55c..07fd7b460654e169e8b6822474dc3cc70fcec4c0 100644
 | ||||
| --- a/src/node_worker.h
 | ||||
| +++ b/src/node_worker.h
 | ||||
| @@ -114,6 +114,7 @@ class Worker : public AsyncWrap {
 | ||||
|   | ||||
|    std::unique_ptr<MessagePortData> child_port_data_; | ||||
|    std::shared_ptr<KVStore> env_vars_; | ||||
| +  EmbedderPreloadCallback embedder_preload_;
 | ||||
|   | ||||
|    // A raw flag that is used by creator and worker threads to | ||||
|    // sync up on pre-mature termination of worker  - while in the | ||||
| diff --git a/test/cctest/test_environment.cc b/test/cctest/test_environment.cc
 | ||||
| index 2e747c7be58922897abd0424b797f3f12a89ada1..658f8df4b01d60759e858cf5283b9be9467dd142 100644
 | ||||
| --- a/test/cctest/test_environment.cc
 | ||||
| +++ b/test/cctest/test_environment.cc
 | ||||
| @@ -773,3 +773,31 @@ TEST_F(EnvironmentTest, RequestInterruptAtExit) {
 | ||||
|   | ||||
|    context->Exit(); | ||||
|  } | ||||
| +
 | ||||
| +TEST_F(EnvironmentTest, EmbedderPreload) {
 | ||||
| +  v8::HandleScope handle_scope(isolate_);
 | ||||
| +  v8::Local<v8::Context> context = node::NewContext(isolate_);
 | ||||
| +  v8::Context::Scope context_scope(context);
 | ||||
| +
 | ||||
| +  node::EmbedderPreloadCallback preload = [](node::Environment* env,
 | ||||
| +                                             v8::Local<v8::Value> process,
 | ||||
| +                                             v8::Local<v8::Value> require) {
 | ||||
| +    CHECK(process->IsObject());
 | ||||
| +    CHECK(require->IsFunction());
 | ||||
| +    process.As<v8::Object>()->Set(
 | ||||
| +        env->context(),
 | ||||
| +        v8::String::NewFromUtf8Literal(env->isolate(), "prop"),
 | ||||
| +        v8::String::NewFromUtf8Literal(env->isolate(), "preload")).Check();
 | ||||
| +  };
 | ||||
| +
 | ||||
| +  std::unique_ptr<node::Environment, decltype(&node::FreeEnvironment)> env(
 | ||||
| +      node::CreateEnvironment(isolate_data_, context, {}, {},
 | ||||
| +                              node::EnvironmentFlags::kDefaultFlags, {}, {},
 | ||||
| +                              preload),
 | ||||
| +      node::FreeEnvironment);
 | ||||
| +
 | ||||
| +  v8::Local<v8::Value> main_ret =
 | ||||
| +      node::LoadEnvironment(env.get(), "return process.prop;").ToLocalChecked();
 | ||||
| +  node::Utf8Value main_ret_str(isolate_, main_ret);
 | ||||
| +  EXPECT_EQ(std::string(*main_ret_str), "preload");
 | ||||
| +}
 | ||||
|  | @ -38,8 +38,8 @@ const main = async () => { | |||
|       config: 'webpack.config.worker.js' | ||||
|     }, | ||||
|     { | ||||
|       name: 'asar_bundle_deps', | ||||
|       config: 'webpack.config.asar.js' | ||||
|       name: 'node_bundle_deps', | ||||
|       config: 'webpack.config.node.js' | ||||
|     }, | ||||
|     { | ||||
|       name: 'utility_bundle_deps', | ||||
|  |  | |||
|  | @ -21,7 +21,6 @@ | |||
| #include "base/task/single_thread_task_runner.h" | ||||
| #include "base/task/thread_pool/thread_pool_instance.h" | ||||
| #include "content/public/common/content_switches.h" | ||||
| #include "electron/electron_version.h" | ||||
| #include "electron/fuses.h" | ||||
| #include "gin/array_buffer.h" | ||||
| #include "gin/public/isolate_holder.h" | ||||
|  | @ -260,7 +259,8 @@ int NodeMain(int argc, char* argv[]) { | |||
|       env = node::CreateEnvironment( | ||||
|           isolate_data, isolate->GetCurrentContext(), result->args(), | ||||
|           result->exec_args(), | ||||
|           static_cast<node::EnvironmentFlags::Flags>(env_flags)); | ||||
|           static_cast<node::EnvironmentFlags::Flags>(env_flags), {}, {}, | ||||
|           &OnNodePreload); | ||||
|       CHECK_NE(nullptr, env); | ||||
| 
 | ||||
|       node::SetIsolateUpForNode(isolate); | ||||
|  | @ -282,11 +282,6 @@ int NodeMain(int argc, char* argv[]) { | |||
| #endif | ||||
| 
 | ||||
|       process.Set("crashReporter", reporter); | ||||
| 
 | ||||
|       gin_helper::Dictionary versions; | ||||
|       if (process.Get("versions", &versions)) { | ||||
|         versions.SetReadOnly(ELECTRON_PROJECT_NAME, ELECTRON_VERSION_STRING); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     v8::HandleScope scope(isolate); | ||||
|  |  | |||
|  | @ -10,7 +10,6 @@ | |||
| #include "shell/common/gin_converters/file_path_converter.h" | ||||
| #include "shell/common/gin_helper/dictionary.h" | ||||
| #include "shell/common/node_includes.h" | ||||
| #include "shell/common/node_util.h" | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
|  | @ -191,19 +190,6 @@ class Archive : public node::ObjectWrap { | |||
|   std::shared_ptr<asar::Archive> archive_; | ||||
| }; | ||||
| 
 | ||||
| static void InitAsarSupport(const v8::FunctionCallbackInfo<v8::Value>& args) { | ||||
|   auto* isolate = args.GetIsolate(); | ||||
|   auto require = args[0]; | ||||
| 
 | ||||
|   // Evaluate asar_bundle.js.
 | ||||
|   std::vector<v8::Local<v8::String>> asar_bundle_params = { | ||||
|       node::FIXED_ONE_BYTE_STRING(isolate, "require")}; | ||||
|   std::vector<v8::Local<v8::Value>> asar_bundle_args = {require}; | ||||
|   electron::util::CompileAndCall(isolate->GetCurrentContext(), | ||||
|                                  "electron/js2c/asar_bundle", | ||||
|                                  &asar_bundle_params, &asar_bundle_args); | ||||
| } | ||||
| 
 | ||||
| static void SplitPath(const v8::FunctionCallbackInfo<v8::Value>& args) { | ||||
|   auto* isolate = args.GetIsolate(); | ||||
| 
 | ||||
|  | @ -239,7 +225,6 @@ void Initialize(v8::Local<v8::Object> exports, | |||
|   exports->Set(context, node::FIXED_ONE_BYTE_STRING(isolate, "Archive"), cons) | ||||
|       .Check(); | ||||
|   NODE_SET_METHOD(exports, "splitPath", &SplitPath); | ||||
|   NODE_SET_METHOD(exports, "initAsarSupport", &InitAsarSupport); | ||||
| } | ||||
| 
 | ||||
| }  // namespace
 | ||||
|  |  | |||
|  | @ -15,8 +15,6 @@ | |||
| #include "base/process/process_handle.h" | ||||
| #include "base/process/process_metrics_iocounters.h" | ||||
| #include "base/system/sys_info.h" | ||||
| #include "chrome/common/chrome_version.h" | ||||
| #include "electron/electron_version.h" | ||||
| #include "services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.h" | ||||
| #include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h" | ||||
| #include "shell/browser/browser.h" | ||||
|  | @ -84,12 +82,6 @@ void ElectronBindings::BindTo(v8::Isolate* isolate, | |||
|   dict.SetMethod("activateUvLoop", | ||||
|                  base::BindRepeating(&ElectronBindings::ActivateUVLoop, | ||||
|                                      base::Unretained(this))); | ||||
| 
 | ||||
|   gin_helper::Dictionary versions; | ||||
|   if (dict.Get("versions", &versions)) { | ||||
|     versions.SetReadOnly(ELECTRON_PROJECT_NAME, ELECTRON_VERSION_STRING); | ||||
|     versions.SetReadOnly("chrome", CHROME_VERSION_STRING); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void ElectronBindings::EnvironmentDestroyed(node::Environment* env) { | ||||
|  |  | |||
|  | @ -20,9 +20,11 @@ | |||
| #include "base/strings/utf_string_conversions.h" | ||||
| #include "base/task/single_thread_task_runner.h" | ||||
| #include "base/trace_event/trace_event.h" | ||||
| #include "chrome/common/chrome_version.h" | ||||
| #include "content/public/browser/browser_thread.h" | ||||
| #include "content/public/common/content_paths.h" | ||||
| #include "electron/buildflags/buildflags.h" | ||||
| #include "electron/electron_version.h" | ||||
| #include "electron/fuses.h" | ||||
| #include "shell/browser/api/electron_api_app.h" | ||||
| #include "shell/common/api/electron_bindings.h" | ||||
|  | @ -34,6 +36,7 @@ | |||
| #include "shell/common/gin_helper/event_emitter_caller.h" | ||||
| #include "shell/common/gin_helper/microtasks_scope.h" | ||||
| #include "shell/common/mac/main_application_bundle.h" | ||||
| #include "shell/common/node_util.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
 | ||||
|  | @ -610,7 +613,6 @@ std::shared_ptr<node::Environment> NodeBindings::CreateEnvironment( | |||
|                          electron::fuses::IsOnlyLoadAppFromAsarEnabled())); | ||||
|   } | ||||
| 
 | ||||
|   base::FilePath resources_path = GetResourcesPath(); | ||||
|   std::string init_script = "electron/js2c/" + process_type + "_init"; | ||||
| 
 | ||||
|   args.insert(args.begin() + 1, init_script); | ||||
|  | @ -649,7 +651,8 @@ std::shared_ptr<node::Environment> NodeBindings::CreateEnvironment( | |||
|     v8::TryCatch try_catch(isolate); | ||||
|     env = node::CreateEnvironment( | ||||
|         static_cast<node::IsolateData*>(isolate_data), context, args, exec_args, | ||||
|         static_cast<node::EnvironmentFlags::Flags>(env_flags)); | ||||
|         static_cast<node::EnvironmentFlags::Flags>(env_flags), {}, {}, | ||||
|         &OnNodePreload); | ||||
| 
 | ||||
|     if (try_catch.HasCaught()) { | ||||
|       std::string err_msg = | ||||
|  | @ -735,11 +738,6 @@ std::shared_ptr<node::Environment> NodeBindings::CreateEnvironment( | |||
| 
 | ||||
|   gin_helper::Dictionary process(context->GetIsolate(), env->process_object()); | ||||
|   process.SetReadOnly("type", process_type); | ||||
|   process.Set("resourcesPath", resources_path); | ||||
|   // The path to helper app.
 | ||||
|   base::FilePath helper_exec_path; | ||||
|   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) { | ||||
|  | @ -931,4 +929,29 @@ void NodeBindings::EmbedThreadRunner(void* arg) { | |||
|   } | ||||
| } | ||||
| 
 | ||||
| void OnNodePreload(node::Environment* env, | ||||
|                    v8::Local<v8::Value> process, | ||||
|                    v8::Local<v8::Value> require) { | ||||
|   // Set custom process properties.
 | ||||
|   gin_helper::Dictionary dict(env->isolate(), process.As<v8::Object>()); | ||||
|   dict.SetReadOnly("resourcesPath", GetResourcesPath()); | ||||
|   base::FilePath helper_exec_path;  // path to the helper app.
 | ||||
|   base::PathService::Get(content::CHILD_PROCESS_EXE, &helper_exec_path); | ||||
|   dict.SetReadOnly("helperExecPath", helper_exec_path); | ||||
|   gin_helper::Dictionary versions; | ||||
|   if (dict.Get("versions", &versions)) { | ||||
|     versions.SetReadOnly(ELECTRON_PROJECT_NAME, ELECTRON_VERSION_STRING); | ||||
|     versions.SetReadOnly("chrome", CHROME_VERSION_STRING); | ||||
|   } | ||||
| 
 | ||||
|   // Execute lib/node/init.ts.
 | ||||
|   std::vector<v8::Local<v8::String>> bundle_params = { | ||||
|       node::FIXED_ONE_BYTE_STRING(env->isolate(), "process"), | ||||
|       node::FIXED_ONE_BYTE_STRING(env->isolate(), "require"), | ||||
|   }; | ||||
|   std::vector<v8::Local<v8::Value>> bundle_args = {process, require}; | ||||
|   electron::util::CompileAndCall(env->context(), "electron/js2c/node_init", | ||||
|                                  &bundle_params, &bundle_args); | ||||
| } | ||||
| 
 | ||||
| }  // namespace electron
 | ||||
|  |  | |||
|  | @ -219,6 +219,12 @@ class NodeBindings { | |||
|   base::WeakPtrFactory<NodeBindings> weak_factory_{this}; | ||||
| }; | ||||
| 
 | ||||
| // A thread-safe function responsible for loading preload script which runs for
 | ||||
| // all node environments (including child processes and workers).
 | ||||
| void OnNodePreload(node::Environment* env, | ||||
|                    v8::Local<v8::Value> process, | ||||
|                    v8::Local<v8::Value> require); | ||||
| 
 | ||||
| }  // namespace electron
 | ||||
| 
 | ||||
| #endif  // ELECTRON_SHELL_COMMON_NODE_BINDINGS_H_
 | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
| #include "shell/common/node_util.h" | ||||
| 
 | ||||
| #include "base/logging.h" | ||||
| #include "gin/converter.h" | ||||
| #include "shell/common/node_includes.h" | ||||
| 
 | ||||
| namespace electron::util { | ||||
|  | @ -31,7 +32,14 @@ v8::MaybeLocal<v8::Value> CompileAndCall( | |||
|   // This will only be caught when something has gone terrible wrong as all
 | ||||
|   // electron scripts are wrapped in a try {} catch {} by webpack
 | ||||
|   if (try_catch.HasCaught()) { | ||||
|     LOG(ERROR) << "Failed to CompileAndCall electron script: " << id; | ||||
|     std::string msg = "no error message"; | ||||
|     if (!try_catch.Message().IsEmpty()) { | ||||
|       gin::ConvertFromV8(isolate, try_catch.Message()->Get(), &msg); | ||||
|     } else if (try_catch.HasTerminated()) { | ||||
|       msg = "script execution has been terminated"; | ||||
|     } | ||||
|     LOG(ERROR) << "Failed to CompileAndCall electron script (" << id | ||||
|                << "): " << msg; | ||||
|   } | ||||
|   return ret; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										1
									
								
								typings/internal-ambient.d.ts
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								typings/internal-ambient.d.ts
									
										
									
									
										vendored
									
									
								
							|  | @ -90,7 +90,6 @@ declare namespace NodeJS { | |||
|       asarPath: string; | ||||
|       filePath: string; | ||||
|     }; | ||||
|     initAsarSupport(require: NodeJS.Require): void; | ||||
|   } | ||||
| 
 | ||||
|   interface NetBinding { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Cheng Zhao
				Cheng Zhao