Патчи в Electron
Electron is built on two major upstream projects: Chromium and Node.js. Each of these projects has several of their own dependencies, too. We try our best to use these dependencies exactly as they are but sometimes we can't achieve our goals without patching those upstream dependencies to fit our use cases.
Patch justification
Every patch in Electron is a maintenance burden. When upstream code changes, patches can break—sometimes without even a patch conflict or a compilation error. It's an ongoing effort to keep our patch set up-to-date and effective. So we strive to keep our patch count at a minimum. To that end, every patch must describe its reason for existence in its commit message. That reason must be one of the following:
- The patch is temporary, and is intended to be (or has been) committed upstream or otherwise eventually removed. Include a link to an upstream PR or code review if available, or a procedure for verifying whether the patch is still needed at a later date.
- The patch allows the code to compile in the Electron environment, but cannot be upstreamed because it's Electron-specific (e.g. patching out references to Chrome's
Profile
). Include reasoning about why the change cannot be implemented without a patch (e.g. by subclassing or copying the code). - The patch makes Electron-specific changes in functionality which are fundamentally incompatible with upstream.
In general, all the upstream projects we work with are friendly folks and are often happy to accept refactorings that allow the code in question to be compatible with both Electron and the upstream project. (See e.g. this change in Chromium, which allowed us to remove a patch that did the same thing, or this change in Node, which was a no-op for Node but fixed a bug in Electron.) We should aim to upstream changes whenever we can, and avoid indefinite-lifetime patches.
Patch system
If you find yourself in the unfortunate position of having to make a change which can only be made through patching an upstream project, you'll need to know how to manage patches in Electron.
All patches to upstream projects in Electron are contained in the patches/
directory. Each subdirectory of patches/
contains several patch files, along with a .patches
file which lists the order in which the patches should be applied. Think of these files as making up a series of git commits that are applied on top of the upstream project after we check it out.
patches
├── config.json <-- this describes which patchset directory is applied to what project
├── chromium
│ ├── .patches
│ ├── accelerator.patch
│ ├── add_contentgpuclient_precreatemessageloop_callback.patch
│ ⋮
├── node
│ ├── .patches
│ ├── add_openssl_is_boringssl_guard_to_oaep_hash_check.patch
│ ├── build_add_gn_build_files.patch
│ ⋮
⋮
To help manage these patch sets, we provide two tools: git-import-patches
and git-export-patches
. git-import-patches
imports a set of patch files into a git repository by applying each patch in the correct order and creating a commit for each one. git-export-patches
does the reverse; it exports a series of git commits in a repository into a set of files in a directory and an accompanying .patches
file.
Side note: the reason we use a
.patches
file to maintain the order of applied patches, rather than prepending a number like001-
to each file, is because it reduces conflicts related to patch ordering. It prevents the situation where two PRs both add a patch at the end of the series with the same numbering and end up both getting merged resulting in a duplicate identifier, and it also reduces churn when a patch is added or deleted in the middle of the series.