Files
electron/CLAUDE.md
Samuel Attard 6ed3198ba8 build: migrate from eslint to oxlint (#50691)
Consolidates the root .eslintrc.json and five nested configs (build,
script, docs, default_app, spec) into a single .oxlintrc.json at the
repo root. script/lint.js now shells out to the oxlint binary from
node_modules/.bin instead of using the ESLint Node API, and emits
GitHub Actions annotations directly via --format=github in CI
(replacing the deleted eslint-stylish problem matcher).

Oxlint has no markdown processor, so the ESLint-based lint of JS code
blocks in docs/**/*.md is replaced with an inline regex check for bare
Node.js builtin imports. This preserves the rule docs/.eslintrc.json
was originally added for in #42113; the rest of the standard ruleset on
docs code blocks was already being enforced in parallel by
lint-roller-markdown-standard.
2026-04-06 09:05:13 -07:00

9.5 KiB

Electron Development Guide

Running node_modules binaries

Never use npx. It is considered dangerous because it can silently fetch and execute arbitrary packages from the registry. Always run binaries through one of these safer mechanisms instead:

  1. Preferred — spawn the executable directly from node_modules/.bin/<tool> (or the platform equivalent on Windows). This is what script/lint.js does for oxlint.
  2. Acceptable — invoke via yarn <tool> or yarn run <tool>, which resolves to the locally installed version without the registry fallback that npx performs.

This rule applies to shell commands you run yourself and to any scripts you author or modify in this repo.

Project Overview

Electron is a framework for building cross-platform desktop applications using web technologies. It embeds Chromium for rendering and Node.js for backend functionality.

Directory Structure

electron/                 # This repo (run `e` commands here)
├── shell/               # Core C++ application code
│   ├── browser/         # Main process implementation (107+ API modules)
│   ├── renderer/        # Renderer process code
│   ├── common/          # Shared code between processes
│   ├── app/             # Application entry points
│   └── services/        # Node.js service integration
├── lib/                 # TypeScript/JavaScript library code
│   ├── browser/         # Main process JS (47 API implementations)
│   ├── renderer/        # Renderer process JS
│   └── common/          # Shared JS modules
├── patches/             # Patches for upstream dependencies
│   ├── chromium/        # ~159 patches to Chromium
│   ├── node/            # ~48 patches to Node.js
│   └── ...              # Other targets (v8, boringssl, etc.)
├── spec/                # Test suite (1189+ TypeScript test files)
├── docs/                # API documentation and guides
├── build/               # Build configuration
├── script/              # Build and automation scripts
└── chromium_src/        # Chromium source overrides
../                      # Parent directory is Chromium source

Build Tools Setup

Electron uses @electron/build-tools for development. The e command is the primary CLI.

Installation:

npm i -g @electron/build-tools

Configuration location: ~/.electron_build_tools/configs/

Essential Commands

Configuration Management

Command Purpose
e init <name> --root=<path> --bootstrap testing Create new build config and sync
e use <name> Switch to a different build configuration
e show current Display active configuration name
e show configs List all available configurations

Build & Development Loop

Command Purpose
e sync Fetch/update all source code and apply patches
e sync --3 Sync with 3-way merge (required for Chromium upgrades)
e build Build Electron (runs GN + Ninja)
e build -k 999 Build and continue on errors (up to 999)
e build -t <target> Build specific target (e.g., electron:node_headers)
e start Run the built Electron executable
e start --version Verify Electron launches and print version
e test Run the test suite
e debug Run Electron in debugger (lldb on macOS, gdb on Linux)

Patch Management

Command Purpose
e patches <target> Export patches for a target (chromium, node, v8, etc.)
e patches all Export all patches from all targets
e patches --list-targets List available patch targets

Typical Development Workflow

# 1. Ensure you're on the right config
e show current

# 2. Sync to get latest code
e sync

# 3. Make your changes in shell/ or lib/ or ../

# 4. Build
e build

# 5. Test your changes (Leave the user to do this, don't run these commands unless asked)
e start
e test

# 6. If you modified patched files in Chromium:
cd ..  # Go to Chromium repo
git add <files>
git commit -m "description of change"
cd electron
e patches chromium  # Export the patch

Patches System

Electron patches upstream dependencies (Chromium, Node.js, V8, etc.) to add features or modify behavior.

How patches work:

patches/{target}/*.patch  →  [e sync --3]  →  target repo commits
                          ←  [e patches]   ←

Patch configuration: patches/config.json maps patch directories to target repos.

Key rules:

  • Fix existing patches 99% of the time rather than creating new ones
  • Preserve original authorship in TODO comments
  • Never change TODO assignees (TODO(name) must retain original name)
  • Each patch file includes commit message explaining its purpose

Creating/modifying patches:

  1. Make changes in the target repo (e.g., ../ for Chromium)
  2. Create a git commit
  3. Run e patches <target> to export

Fixing patch conflicts on an existing PR:

If asked to fix a patch conflict on a branch that already has an open PR, check the PR's failed Apply Patches CI run for an update-patches artifact before running e sync locally. CI has already performed the 3-way merge and exported the resolved patch diff — applying it is much faster than a full local sync.

# Find the failed Apply Patches run for the PR and download the artifact
gh run list --repo electron/electron --branch <pr-branch> --workflow "Apply Patches" --limit 1
gh run download <run-id> --repo electron/electron --name update-patches

# Apply the CI-generated fix, then push
git am update-patches.patch
git push

If no artifact exists (e.g. the 3-way merge itself failed), fall back to e sync --3 and resolve manually.

Testing

Test location: spec/ directory

Running tests:

e test                    # Run full test suite

Test frameworks: Mocha, Chai, Sinon

Build Configuration

GN build arguments: Located in build/args/:

  • testing.gn - Debug/testing builds
  • release.gn - Release builds
  • all.gn - Common arguments for all builds

Main build file: BUILD.gn

Feature flags: buildflags/buildflags.gni

Chromium Upgrade Workflow

When working on the roller/chromium/main branch to upgrade Chromium activate the "Electron Chromium Upgrade" skill.

Pull Requests

PR bodies must always include a Notes: section as the last line of the body. This is a consumer-facing release note for Electron app developers — describe the user-visible fix or change, not internal implementation details. Use Notes: none if there is no user-facing change.

PR Labeling (write-access only)

When the user has write access to electron/electron, add these labels when creating PRs:

Semver label — one of:

  • semver/none — build changes, refactors, CI, or anything with no end-user impact
  • semver/patch — backwards-compatible bug fixes
  • semver/minor — backwards-compatible new functionality
  • semver/major — incompatible API changes

Backport target labels — add target/{N}-x-y for each supported release branch the change should land on. Default policy:

  • Bug fixes — backport to all active release lines except the oldest
  • Security fixes — backport to all active release lines including the oldest
  • Features (semver/minor) and breaking changes (semver/major) — no backport labels; main-only by default

To find which release branches are active, check label colors — active target/* labels use color #ad244f, older/EOL ones use #ededed:

gh label list --repo electron/electron --search target/ --json name,color --jq '.[] | select(.color == "ad244f") | .name'

Code Style

C++: Follows Chromium style, enforced by clang-format TypeScript/JavaScript: oxlint configuration in .oxlintrc.json

Linting:

npm run lint              # Run all linters
npm run lint:js           # Run oxlint over all JS/TS/MJS sources
npm run lint:clang-format # C++ formatting
npm run lint:api-history  # Validate API history YAML blocks in docs

Key Files

File Purpose
BUILD.gn Main GN build configuration
DEPS Dependency versions and checkout paths
patches/config.json Patch target configuration
filenames.gni Source file lists by platform
package.json Node.js dependencies and scripts

Environment Variables

Variable Purpose
GN_EXTRA_ARGS Additional GN arguments (useful in CI)
ELECTRON_RUN_AS_NODE=1 Run Electron as Node.js

Useful Git Commands for Chromium

# Find CL that changed a file
cd ..
git log --oneline -10 -- {file}
git blame -L {start},{end} -- {file}

# Look for Chromium CL reference in commit
git log -1 {commit_sha}  # Find "Reviewed-on:" line

# Find which patch affects a file
grep -l "filename.cc" patches/chromium/*.patch

CI/CD

GitHub Actions workflows in .github/workflows/:

  • build.yml - Main build workflow
  • pipeline-electron-lint.yml - Linting
  • pipeline-segment-electron-test.yml - Testing

Common Issues

Patch conflict during sync:

  • Use e sync --3 for 3-way merge
  • Check if file was renamed/moved upstream
  • Verify patch is still needed

Build error in patched file:

  • Find the patch: grep -l "filename" patches/chromium/*.patch
  • Match existing patch style (#if 0 guards, BUILDFLAG conditionals, etc.)

Remote build issues:

  • Try e build --no-remote to build locally
  • Check reclient/siso configuration in your build config