mirror of
https://github.com/electron/electron.git
synced 2026-10-29 04:04:54 +08:00
* build: bundle lib/ with rolldown instead of webpack
Replace the webpack + ts-loader pipeline that builds Electron's internal
JavaScript bundles with a small rolldown driver (build/bundle/bundle.mjs).
- build/bundle/targets.mjs describes the seven bundles (browser, renderer,
worker, webview, isolated_renderer, node, utility) and the per-target
behaviour that used to live in one webpack config each.
- BUILDFLAG(...) folding, the `electron` aliases, the Promise/process/
Buffer/global providers and the profiling/try-catch wrappers are kept
with the same semantics. Node built-ins imported from lazily evaluated
modules stay lazy via a one line CommonJS shim so that load order
matches the old bundles.
- Type checking moves out of the bundling step into a single
electron_lib_typecheck action (build/bundle/typecheck.mjs) that every
bundle depends on, instead of running seven times.
- gen-filenames.ts asks bundle.mjs for the module graph directly and
emits a lib_typecheck_sources list for the new action.
- A few lib/ modules are adjusted for an ESM-first bundler: net.ts uses
a plain module.exports object, web-contents.ts keeps its session
side-effect import explicitly, and defineProperties caches the loaded
module so each electron.* getter keeps returning the same object.
Drops webpack, webpack-cli and ts-loader from devDependencies.
* chore: wrap comment for clang-format
* build: keep bundle declarations out of the wrapper's parameter scope
node_mksnapshot compiles the js2c bundles with Node's built-in module
parameters (exports, require, module, process, internalBinding,
primordials), and a hoisted top-level `const { internalBinding } = ...`
from lib/node redeclared one of them. Wrap the bundle body in an IIFE, as
the webpack output was.
---------
Co-authored-by: Claude <noreply@anthropic.com>
94 lines
3.8 KiB
TypeScript
94 lines
3.8 KiB
TypeScript
// Initialize ASAR support in fs module.
|
|
import { wrapFsWithAsar } from './asar-fs-wrapper';
|
|
wrapFsWithAsar(require('fs'));
|
|
|
|
// Hook child_process.fork.
|
|
import cp = require('child_process'); // oxlint-disable-line import/first
|
|
const originalFork = cp.fork;
|
|
cp.fork = (modulePath, args?, options?: cp.ForkOptions) => {
|
|
// Parse optional args.
|
|
if (args == null) {
|
|
args = [];
|
|
} else if (typeof args === 'object' && !Array.isArray(args)) {
|
|
options = args as cp.ForkOptions;
|
|
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. With the runAsNode fuse
|
|
// disabled that environment is ignored and the child would start another
|
|
// copy of the app instead, so refuse up front.
|
|
if (!process._linkedBinding('electron_common_features').isRunAsNodeEnabled()) {
|
|
throw new Error(
|
|
'child_process.fork() is not supported when the runAsNode fuse is disabled; use utilityProcess.fork() instead'
|
|
);
|
|
}
|
|
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);
|
|
};
|
|
|
|
// Hand crashpad's handler to ELECTRON_RUN_AS_NODE children so their crashes are
|
|
// reported too; shell/app/node_main.cc reads these back. Every async spawn goes
|
|
// through ChildProcess.prototype.spawn and every sync one through spawnSync,
|
|
// both with the normalized file and envPairs.
|
|
if (process.platform === 'linux') {
|
|
const { getCrashdumpSignalFD, getCrashpadHandlerPID } = process._linkedBinding('electron_common_crashpad_support');
|
|
const childProcess = require('internal/child_process') as typeof import('@node/lib/internal/child_process');
|
|
// Invalid options are left for Node's own validation to reject.
|
|
const addCrashpadEnv = (options: any) => {
|
|
if (
|
|
options?.file !== process.execPath ||
|
|
!Array.isArray(options.envPairs) ||
|
|
!options.envPairs.some((pair: unknown) => typeof pair === 'string' && pair.startsWith('ELECTRON_RUN_AS_NODE='))
|
|
) {
|
|
return;
|
|
}
|
|
const fd = getCrashdumpSignalFD();
|
|
const pid = getCrashpadHandlerPID();
|
|
if (fd !== -1 && pid !== -1) {
|
|
options.envPairs.push(`CRASHDUMP_SIGNAL_FD=${fd}`, `CRASHPAD_HANDLER_PID=${pid}`);
|
|
}
|
|
};
|
|
const { spawn } = childProcess.ChildProcess.prototype;
|
|
childProcess.ChildProcess.prototype.spawn = function (options: any) {
|
|
addCrashpadEnv(options);
|
|
return spawn.call(this, options);
|
|
};
|
|
const { spawnSync } = childProcess;
|
|
childProcess.spawnSync = (options: any) => {
|
|
addCrashpadEnv(options);
|
|
return spawnSync(options);
|
|
};
|
|
}
|
|
|
|
// Prevent Node from adding paths outside this app to search paths.
|
|
import path = require('path'); // oxlint-disable-line import/first
|
|
const Module = require('module') as NodeJS.ModuleInternal;
|
|
const resourcesPathWithTrailingSlash = process.resourcesPath + path.sep;
|
|
const originalNodeModulePaths = Module._nodeModulePaths;
|
|
Module._nodeModulePaths = function (from) {
|
|
const paths: string[] = originalNodeModulePaths(from);
|
|
const fromPath = path.resolve(from) + path.sep;
|
|
// If "from" is outside the app then we do nothing.
|
|
if (fromPath.startsWith(resourcesPathWithTrailingSlash)) {
|
|
return paths.filter(function (candidate) {
|
|
return candidate.startsWith(resourcesPathWithTrailingSlash);
|
|
});
|
|
} else {
|
|
return paths;
|
|
}
|
|
};
|