mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
chore: remove node patches by using the preload feature (#41115)
* chore: remove node patches by using the preload feature * chore: fix node tests caused by filename change
This commit is contained in:
22
BUILD.gn
22
BUILD.gn
@@ -164,15 +164,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" ]
|
||||
|
||||
@@ -218,6 +209,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" ]
|
||||
|
||||
@@ -229,9 +229,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",
|
||||
@@ -239,9 +239,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
|
||||
});
|
||||
@@ -331,10 +331,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
|
||||
@@ -50,3 +48,4 @@ lib_fix_broadcastchannel_initialization_location.patch
|
||||
fix_handle_possible_disabled_sharedarraybuffer.patch
|
||||
win_process_avoid_assert_after_spawning_store_app_4152.patch
|
||||
fix_avx_detection.patch
|
||||
src_preload_function_for_environment.patch
|
||||
|
||||
@@ -26,10 +26,10 @@ index 001343b74ce236f89dca030c0fc9dd0299df0b39..6f277daf4ce846f093f634c473daec07
|
||||
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 2e35cbba2ac02494c44821af395fe0195b1ab6b5..f5b6fecf6843a6204ec532a77f39a36d33bf061d 100644
|
||||
index 250a43c5455b4f9ff72dd3a34d5b0aa270f43cc6..31f5d1528c840a2926b59b2b1c82ff265588a37a 100644
|
||||
--- a/lib/internal/process/pre_execution.js
|
||||
+++ b/lib/internal/process/pre_execution.js
|
||||
@@ -149,11 +149,13 @@ function patchProcessObject(expandArgv1) {
|
||||
@@ -144,11 +144,13 @@ function patchProcessObject(expandArgv1) {
|
||||
if (expandArgv1 && process.argv[1] &&
|
||||
!StringPrototypeStartsWith(process.argv[1], '-')) {
|
||||
// Expand process.argv[1] into a full path.
|
||||
|
||||
@@ -11,7 +11,7 @@ trying to see whether or not the lines are greyed out. One possibility
|
||||
would be to upstream a changed test that doesn't hardcode line numbers.
|
||||
|
||||
diff --git a/test/fixtures/errors/force_colors.snapshot b/test/fixtures/errors/force_colors.snapshot
|
||||
index 0334a0b4faa3633aa8617b9538873e7f3540513b..fa9989f55980aeddd3fa944318488c0289e3ab6e 100644
|
||||
index 0334a0b4faa3633aa8617b9538873e7f3540513b..0d503d60931278ff9a7fb41177687688119390a3 100644
|
||||
--- a/test/fixtures/errors/force_colors.snapshot
|
||||
+++ b/test/fixtures/errors/force_colors.snapshot
|
||||
@@ -4,11 +4,12 @@ throw new Error('Should include grayed stack trace')
|
||||
@@ -27,7 +27,7 @@ index 0334a0b4faa3633aa8617b9538873e7f3540513b..fa9989f55980aeddd3fa944318488c02
|
||||
+[90m at Object..js (node:internal*modules*cjs*loader:1326:10)[39m
|
||||
+[90m at Module.load (node:internal*modules*cjs*loader:1126:32)[39m
|
||||
+[90m at node:internal*modules*cjs*loader:967:12[39m
|
||||
+[90m at Function._load (node:electron*js2c*asar_bundle:743:32)[39m
|
||||
+[90m at Function._load (node:electron*js2c*node_init:741:32)[39m
|
||||
+[90m at Function.executeUserEntryPoint [as runMain] (node:internal*modules*run_main:96:12)[39m
|
||||
[90m at node:internal*main*run_main_module:23:47[39m
|
||||
|
||||
|
||||
@@ -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 da553f6556a06d57d7490d74a3b4dd8f0132600c..168a6c72520d6540f0dbf84a62bc5e2b2f3ae022 100644
|
||||
index 59c37b97672d39a9da89ca2b78aa28a77ca78699..319d853a35d9191c64a4f21132306a774acd84e6 100644
|
||||
--- a/lib/child_process.js
|
||||
+++ b/lib/child_process.js
|
||||
@@ -60,6 +60,7 @@ let debug = require('internal/util/debuglog').debuglog(
|
||||
@@ -19,7 +19,7 @@ index da553f6556a06d57d7490d74a3b4dd8f0132600c..168a6c72520d6540f0dbf84a62bc5e2b
|
||||
|
||||
const {
|
||||
AbortError,
|
||||
@@ -163,7 +164,6 @@ function fork(modulePath, args = [], options) {
|
||||
@@ -152,7 +153,6 @@ function fork(modulePath, args = [], options) {
|
||||
ArrayPrototypeSplice(execArgv, index - 1, 2);
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ index da553f6556a06d57d7490d74a3b4dd8f0132600c..168a6c72520d6540f0dbf84a62bc5e2b
|
||||
args = [...execArgv, modulePath, ...args];
|
||||
|
||||
if (typeof options.stdio === 'string') {
|
||||
@@ -625,6 +625,21 @@ function normalizeSpawnArguments(file, args, options) {
|
||||
@@ -614,6 +614,21 @@ function normalizeSpawnArguments(file, args, options) {
|
||||
'options.windowsVerbatimArguments');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,54 +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/policy.js b/lib/internal/process/policy.js
|
||||
index 8e07cb92118c84b2bc1156532cae8b033b9a48f4..2073a024ad548fe80e84cafee012b003454d6c93 100644
|
||||
--- a/lib/internal/process/policy.js
|
||||
+++ b/lib/internal/process/policy.js
|
||||
@@ -39,9 +39,6 @@ module.exports = ObjectFreeze({
|
||||
process.binding = function binding(_module) {
|
||||
throw new ERR_ACCESS_DENIED('process.binding');
|
||||
};
|
||||
- process._linkedBinding = function _linkedBinding(_module) {
|
||||
- throw new ERR_ACCESS_DENIED('process._linkedBinding');
|
||||
- };
|
||||
},
|
||||
|
||||
get manifest() {
|
||||
diff --git a/lib/internal/process/pre_execution.js b/lib/internal/process/pre_execution.js
|
||||
index 250a43c5455b4f9ff72dd3a34d5b0aa270f43cc6..2e35cbba2ac02494c44821af395fe0195b1ab6b5 100644
|
||||
--- a/lib/internal/process/pre_execution.js
|
||||
+++ b/lib/internal/process/pre_execution.js
|
||||
@@ -117,12 +117,17 @@ function setupUserModules() {
|
||||
loadPreloadModules();
|
||||
// Need to be done after --require setup.
|
||||
initializeFrozenIntrinsics();
|
||||
+ setupAsarSupport();
|
||||
}
|
||||
|
||||
function refreshRuntimeOptions() {
|
||||
refreshOptions();
|
||||
}
|
||||
|
||||
+function setupAsarSupport() {
|
||||
+ process._linkedBinding('electron_common_asar').initAsarSupport(require);
|
||||
+}
|
||||
+
|
||||
function patchProcessObject(expandArgv1) {
|
||||
const binding = internalBinding('process_methods');
|
||||
binding.patchProcessObject(process);
|
||||
diff --git a/test/fixtures/policy/process-binding/app.js b/test/fixtures/policy/process-binding/app.js
|
||||
index 16e26d12a160286b1b6aaeb64b15668b05b9865b..a287d0a2363acbf24077eec040116f96ef18a7b3 100644
|
||||
--- a/test/fixtures/policy/process-binding/app.js
|
||||
+++ b/test/fixtures/policy/process-binding/app.js
|
||||
@@ -5,6 +5,3 @@ const assert = require('assert');
|
||||
assert.throws(() => { process.binding(); }, {
|
||||
code: 'ERR_ACCESS_DENIED'
|
||||
});
|
||||
-assert.throws(() => { process._linkedBinding(); }, {
|
||||
- code: 'ERR_ACCESS_DENIED'
|
||||
-});
|
||||
@@ -1,31 +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 59c37b97672d39a9da89ca2b78aa28a77ca78699..da553f6556a06d57d7490d74a3b4dd8f0132600c 100644
|
||||
--- a/lib/child_process.js
|
||||
+++ b/lib/child_process.js
|
||||
@@ -137,7 +137,18 @@ function fork(modulePath, args = [], options) {
|
||||
validateObject(options, 'options');
|
||||
}
|
||||
options = { ...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');
|
||||
|
||||
// Prepare arguments for fork:
|
||||
339
patches/node/src_preload_function_for_environment.patch
Normal file
339
patches/node/src_preload_function_for_environment.patch
Normal file
@@ -0,0 +1,339 @@
|
||||
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 31f5d1528c840a2926b59b2b1c82ff265588a37a..1e37bd59f53d3a194b2492c83f8e7299c42c828c 100644
|
||||
--- a/lib/internal/process/pre_execution.js
|
||||
+++ b/lib/internal/process/pre_execution.js
|
||||
@@ -114,6 +114,9 @@ function setupUserModules() {
|
||||
initializeESMLoader();
|
||||
const CJSLoader = require('internal/modules/cjs/loader');
|
||||
assert(!CJSLoader.hasLoadedAnyUserCJSModule);
|
||||
+ if (getEmbedderOptions().hasEmbedderPreload) {
|
||||
+ runEmbedderPreload();
|
||||
+ }
|
||||
loadPreloadModules();
|
||||
// Need to be done after --require setup.
|
||||
initializeFrozenIntrinsics();
|
||||
@@ -588,6 +591,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 c4caef25af670658965fc740ce03c2d2c4ed3e66..19443a9672441da5b98921eab9385083a72e3b7e 100644
|
||||
--- a/src/api/environment.cc
|
||||
+++ b/src/api/environment.cc
|
||||
@@ -404,14 +404,16 @@ 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 = context->GetIsolate();
|
||||
HandleScope handle_scope(isolate);
|
||||
Context::Scope context_scope(context);
|
||||
// TODO(addaleax): This is a much better place for parsing per-Environment
|
||||
// options than the global parse call.
|
||||
Environment* env = new Environment(
|
||||
- isolate_data, context, args, exec_args, nullptr, flags, thread_id);
|
||||
+ isolate_data, context, args, exec_args, nullptr, flags, thread_id,
|
||||
+ std::move(preload));
|
||||
|
||||
#if HAVE_INSPECTOR
|
||||
if (env->should_create_inspector()) {
|
||||
diff --git a/src/env-inl.h b/src/env-inl.h
|
||||
index debd982c75805c51ea7d01229b9d635550060503..6af9217acb6f22c89bc92708aa9ab3d021c5e5bf 100644
|
||||
--- a/src/env-inl.h
|
||||
+++ b/src/env-inl.h
|
||||
@@ -388,6 +388,10 @@ inline std::vector<double>* Environment::destroy_async_id_list() {
|
||||
return &destroy_async_id_list_;
|
||||
}
|
||||
|
||||
+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 6e8b314680c9175d8d513cc72382012ae5e70b26..e416bca327f181884ff8dad2b3a82ad826c0f3b5 100644
|
||||
--- a/src/env.cc
|
||||
+++ b/src/env.cc
|
||||
@@ -645,7 +645,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)),
|
||||
@@ -668,7 +669,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)) {
|
||||
// We'll be creating new objects so make sure we've entered the context.
|
||||
HandleScope handle_scope(isolate);
|
||||
|
||||
@@ -738,14 +740,16 @@ 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)
|
||||
: Environment(isolate_data,
|
||||
context->GetIsolate(),
|
||||
args,
|
||||
exec_args,
|
||||
env_info,
|
||||
flags,
|
||||
- thread_id) {
|
||||
+ thread_id,
|
||||
+ std::move(preload)) {
|
||||
InitializeMainContext(context, env_info);
|
||||
}
|
||||
|
||||
diff --git a/src/env.h b/src/env.h
|
||||
index c914b621f50bcd6bce2617fef9e48737235aa516..d2e7f8534498ca171986cf77ef19d2fc9b950a5b 100644
|
||||
--- a/src/env.h
|
||||
+++ b/src/env.h
|
||||
@@ -579,7 +579,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);
|
||||
// Create an Environment and initialize the provided principal context for it.
|
||||
@@ -589,7 +590,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);
|
||||
~Environment() override;
|
||||
|
||||
void InitializeLibuv();
|
||||
@@ -933,6 +935,8 @@ class Environment : public MemoryRetainer {
|
||||
|
||||
#endif // HAVE_INSPECTOR
|
||||
|
||||
+ inline const EmbedderPreloadCallback& embedder_preload() const;
|
||||
+
|
||||
inline void set_process_exit_handler(
|
||||
std::function<void(Environment*, int)>&& handler);
|
||||
|
||||
@@ -1101,6 +1105,7 @@ class Environment : public MemoryRetainer {
|
||||
DefaultProcessExitHandler };
|
||||
|
||||
std::unique_ptr<Realm> principal_realm_ = nullptr;
|
||||
+ 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 26368061a909e6abc62a4cf261a5dbbd79404f1a..bb4065e33164c3ea762a27b71606ab4ed7b1b336 100644
|
||||
--- a/src/node.h
|
||||
+++ b/src/node.h
|
||||
@@ -593,9 +593,21 @@ struct InspectorParentHandle {
|
||||
virtual ~InspectorParentHandle();
|
||||
};
|
||||
|
||||
+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.
|
||||
+//
|
||||
+// 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,
|
||||
@@ -603,7 +615,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_main_instance.cc b/src/node_main_instance.cc
|
||||
index a8661c3c2263fc62e55659310b8da12fc414361e..849442aa8c923808420cbc888befea7d3f1f4c1b 100644
|
||||
--- a/src/node_main_instance.cc
|
||||
+++ b/src/node_main_instance.cc
|
||||
@@ -157,7 +157,8 @@ NodeMainInstance::CreateMainEnvironment(int* exit_code) {
|
||||
exec_args_,
|
||||
&(snapshot_data_->env_info),
|
||||
EnvironmentFlags::kDefaultFlags,
|
||||
- {}));
|
||||
+ {},
|
||||
+ nullptr));
|
||||
context = Context::FromSnapshot(isolate_,
|
||||
SnapshotData::kNodeMainContextIndex,
|
||||
{DeserializeNodeInternalFields, env.get()})
|
||||
diff --git a/src/node_options.cc b/src/node_options.cc
|
||||
index 7ad8d80faee840e4dd224d946871b2ff08b0c23c..25842fd531fc7e1485bcd75f1f92aa9bc0640862 100644
|
||||
--- a/src/node_options.cc
|
||||
+++ b/src/node_options.cc
|
||||
@@ -1220,6 +1220,12 @@ void GetEmbedderOptions(const FunctionCallbackInfo<Value>& args) {
|
||||
Boolean::New(isolate, env->no_global_search_paths()))
|
||||
.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 bfa048a4a8aa183e747dec84b11b1c1d847db2dd..b8337e68cb946366b2dff78bbd12ce5473ee166c 100644
|
||||
--- a/src/node_snapshotable.cc
|
||||
+++ b/src/node_snapshotable.cc
|
||||
@@ -1462,6 +1462,13 @@ void SerializeSnapshotableObjects(Realm* realm,
|
||||
|
||||
namespace mksnapshot {
|
||||
|
||||
+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>();
|
||||
@@ -1515,6 +1522,7 @@ void Initialize(Local<Object> target,
|
||||
Local<Value> unused,
|
||||
Local<Context> context,
|
||||
void* priv) {
|
||||
+ SetMethod(context, target, "runEmbedderPreload", RunEmbedderPreload);
|
||||
SetMethod(context, target, "compileSerializeMain", CompileSerializeMain);
|
||||
SetMethod(context, target, "setSerializeCallback", SetSerializeCallback);
|
||||
SetMethod(context, target, "setDeserializeCallback", SetDeserializeCallback);
|
||||
@@ -1525,6 +1533,7 @@ void Initialize(Local<Object> target,
|
||||
}
|
||||
|
||||
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
||||
+ 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 6a49144ec4f2059fe75983609b0768e4c2b1817d..dc2eb247b011f9cb1945c173c49e029f068ef103 100644
|
||||
--- a/src/node_worker.cc
|
||||
+++ b/src/node_worker.cc
|
||||
@@ -60,6 +60,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);
|
||||
@@ -333,7 +334,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 a77c416735a79feb3f54e40d72a98c8903a20ccd..deab68576f6330f8bcfb4703fd05dbb9c515e473 100644
|
||||
--- a/src/node_worker.h
|
||||
+++ b/src/node_worker.h
|
||||
@@ -113,6 +113,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 547c8ddbffe243113bfe47a51072bb8f1541b94f..19ef2c2a083f908267e6a9365e77b20d46a3feec 100644
|
||||
--- a/test/cctest/test_environment.cc
|
||||
+++ b/test/cctest/test_environment.cc
|
||||
@@ -749,3 +749,31 @@ TEST_F(EnvironmentTest, RequestInterruptAtExit) {
|
||||
node::FreeIsolateData(isolate_data);
|
||||
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',
|
||||
|
||||
@@ -20,7 +20,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, nullptr);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@@ -19,9 +19,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"
|
||||
@@ -32,6 +34,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 "third_party/blink/renderer/bindings/core/v8/v8_initializer.h" // nogncheck
|
||||
#include "third_party/electron_node/src/debug_utils.h"
|
||||
|
||||
@@ -537,7 +540,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);
|
||||
@@ -576,7 +578,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>(flags));
|
||||
static_cast<node::EnvironmentFlags::Flags>(flags), {}, {},
|
||||
&OnNodePreload);
|
||||
|
||||
if (try_catch.HasCaught()) {
|
||||
std::string err_msg =
|
||||
@@ -658,11 +661,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);
|
||||
|
||||
auto env_deleter = [isolate, isolate_data,
|
||||
context = v8::Global<v8::Context>{isolate, context}](
|
||||
@@ -811,4 +809,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, env);
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
|
||||
@@ -201,6 +201,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 {
|
||||
@@ -29,7 +30,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
@@ -83,7 +83,6 @@ declare namespace NodeJS {
|
||||
asarPath: string;
|
||||
filePath: string;
|
||||
};
|
||||
initAsarSupport(require: NodeJS.Require): void;
|
||||
}
|
||||
|
||||
interface NetBinding {
|
||||
|
||||
Reference in New Issue
Block a user