electron/electron
App code enters through a package.json discovered in resources/{app.asar,app,default_app.asar}; the browser process creates a Node environment, loads the bundled browser init script which in turn loads the app's main entry. Renderer↔browser communication rides a mojo interface (mojom::ElectronApiIPC) into a C++ dispatch layer that emits events on the JS ipcMain/ipcMainInternal objects; the reverse direction emits on ipcRenderer via a hidden 'ipcNative' context binding. Network data flows through Chromium URL loader factories, with protocol.handle() bridging Fetch-API Request/Response objects and net.fetch routing through the session's network context. Preload scripts are pushed to the renderer ahead of navigation in startup data rather than fetched by sync IPC.
- App discovery: LoadAppPackage() reads package.json from resources/app.asar, then resources/app, then resources/default_app.asar (only app.asar when the only_load_app_from_asar fuse is on), applies name/productName/version/desktopName, and returns {path, main, esm, v8Flags}.
- PostEarlyInitialization() stashes the AppPackage as a v8 private value 'appPackage' on the Node context global; lib/browser/init.ts retrieves it via getHiddenValue, calls app.setAppPath, then loads the entry with Module._load (CJS) or runEntryPointWithESMLoader (ESM, when type=module or .mjs).
- node_bindings_->JoinAppCode() blocks browser startup until init.ts signals process.appCodeLoaded(), which init.ts invokes after the main module loads (or after the ESM loader settles); this is what synchronizes Chromium startup with the app's JS.
- Renderer→main IPC: the mojom::ElectronApiIPC associated interface delivers Message/Invoke/MessageSync/ReceivePostMessage/MessageHost to ElectronApiIPCHandlerImpl, which resolves the Session from the RenderFrameHost's BrowserContext, builds an api::IpcMainEvent, and calls ipc_dispatch::Message/Invoke which emit on the JS objects registered via electron_browser_ipc_dispatch.setup({ipcMain, ipcMainInternal}).
- ipcMain.handle registrations live in IpcMainImpl._invokeHandlers (a Map keyed by channel) which throws on duplicate handlers; handleOnce wraps handle + removeHandler.
- Main→renderer IPC: EmitIPCEvent in electron_ipc_native.cc looks up a hidden 'ipcNative' private binding on the v8 context (set by the renderer IPC setup), wraps {sender, ports} into an event object, and emits the channel on ipcRenderer or ipcRendererInternal inside a node::CallbackScope when a Node env exists.
- Internal control messages ride reserved channels in the IPC_MESSAGES const enum (e.g. BROWSER_PRELOAD_ERROR re-emitted as 'preload-error' on webContents, BROWSER_GET_PROCESS_MEMORY_INFO returning the calling frame's own renderer pid stats) handled by lib/browser/rpc-server.ts.
- Preload flow: the browser pushes preload paths into RendererStartupData ahead of navigation (WebContents::MaybeSendRendererStartupData); ElectronRendererClient::DidCreateScriptContext creates a per-frame Node environment, defers document loading (LoaderFreezeMode::kStrict), and lib/renderer/init.ts loads CJS preloads via Module._load and .mjs preloads via runEntryPointWithESMLoader, then calls appCodeLoaded which triggers UndeferLoad.
- protocol.handle() converts the native ProtocolRequest into a WHATWG Request — rebuilding uploadData (rawData/file/stream/blob chunk types, blob data pulled via session.defaultSession.getBlobData) into a ReadableStream body — then converts the handler's Response back, with a fast path (relayUntouchedFetch) that hands an untouched net.fetch URL loader straight to Chromium instead of streaming through JS.
- net.fetch/session.fetch go through fetchWithSession in net-fetch.ts into Chromium's network stack under the session's NetworkContext (shell/browser/net/), so requests share the session's cookies, proxy and cache.
- Node module resolution is fenced: lib/node/init.ts overrides Module._nodeModulePaths so modules inside process.resourcesPath can only resolve node_modules inside the app, and patches child_process.fork to set ELECTRON_RUN_AS_NODE=1 (refusing outright when the runAsNode fuse is off).
- The uv loop is demand-driven: lib/common/init.ts wraps process.nextTick, setImmediate, setTimeout and setInterval to call process.activateUvLoop() (bound to ElectronBindings::ActivateUVLoop, which uv_async_sends to OnCallNextTick) so Node callbacks fire even though Chromium owns the main loop.
- Guest <webview> data flow: a renderer frame registers the element, the browser's guest-view-manager maps guestInstanceId→GuestInstance (embedder WebContents + embedderFrame), and only the creating frame may drive the guest through GUEST_VIEW_MANAGER_* IPCs; webPreferences are parsed from the 'webpreferences' attribute string with security options force-inherited from the embedder.