script/spec-runner.js parsed the JUnit report after a failed run and re-ran
each failing test on its own (--enableRerun=3), so a test that failed all of
its in-suite retries but passed once alone still left the job green. That hid
tests that only pass in isolation. Drop the rerun, the JUnit parsing and its
@xmldom/xmldom dependency, and stop passing --enableRerun=3 in the test
workflow. A leftover --enableRerun is now rejected instead of being forwarded
to Electron, where it would silently do nothing. vitest's in-suite retry is
unchanged.
Claude-Session: https://claude.ai/code/session_01LPMvJBQiyP6b7QjatACmnS
Co-authored-by: Claude <noreply@anthropic.com>
* docs: narrow clipboardItem.getType() return type from its MIME type
Type getType() with a generic MIME type parameter and a conditional
return type so a literal `electron application/bookmark` resolves to a
ClipboardBookmark, any other literal MIME type resolves to a Blob, and
a non-literal string still resolves to the union. Adds ts-smoke cases
for all three and drops the now-unneeded `instanceof Blob` check from
the `text/uri-list` example.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HmVsAQiHawruFHijTtkzV9
* build: bump @electron/docs-parser to 3.0.2
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HmVsAQiHawruFHijTtkzV9
---------
Co-authored-by: Claude <noreply@anthropic.com>
TypeScript 7.0 is the native compiler and ships no JavaScript API. The
earlier changes in this series already moved everything that transpiled
on the fly (script/ and spec/) onto Node's own type stripping, so what
is left here is the compiler swap itself:
* typescript ^5.8.3 -> ^7.0.2.
* build/bundle/typecheck.mjs spawns tsc instead of driving the compiler
API (the rootDir/private-field diagnostics it used to filter out are
handled by tsconfig.electron.json setting rootDir to the parent
checkout instead).
* tsconfig.json drops the removed baseUrl option and anchors the paths
mapping explicitly; tsconfig.default_app.json moves off the removed
"node" module resolution; `declare module NodeJS` becomes a namespace.
* A few lib/, spec and docs snippets wrap Buffers for the stricter
Buffer/ArrayBuffer typings that Blob now expects.
Co-authored-by: Claude <noreply@anthropic.com>
The last user of ts-node was the spec runner, which registered it as a
require hook so spec/**/*.ts could be loaded inside Electron (the
utility-process net fixture did the same).
Both now register a small local hook, spec/ts-register.js, that
transpiles each .ts file on its own with the TypeScript compiler API
using tsconfig.spec.json and inlines a source map so stack traces still
point at the .ts lines. ts-node also type checked specs as it loaded
them; that check now runs once in the lint job via
`tsc -p tsconfig.spec.json` instead, so type errors in specs fail lint
rather than surfacing part-way through a test shard.
Drops ts-node 6.2.0 and its transitive arrify, buffer-from, diff@3,
make-error, mkdirp@0.5, source-map-support and yn entries from
yarn.lock.
Co-authored-by: Claude <noreply@anthropic.com>
ts-node was used as a CLI for a handful of TypeScript scripts under
script/. Those now rely on the type stripping built into Node.js instead:
- script/gen-filenames, check-patch-diff, run-clang-tidy and the release
helpers (find-github-release, upload-to-github, github-token, types)
are renamed to .mts and invoked with `node`. They use
import.meta.dirname and explicit .mts / .js specifiers, and
tsconfig.script.json moves to nodenext with verbatimModuleSyntax so
tsc checks them the way Node runs them.
- The documented minimum Node.js for building goes from 22.12 to 22.18,
the first 22.x release with type stripping on by default.
- script/codesign/gen-trust.ts and its trust.xml template are deleted;
nothing has invoked them since generate-identity.sh switched to a
user-scoped keychain in #50058.
- oxfmt, oxlint, lint-staged and .gitattributes learn about .mts.
ts-node itself stays for now because the spec runner still loads specs
through its require hook.
Co-authored-by: Claude <noreply@anthropic.com>
* build: update yarn from 4.12.0 to 4.18.0
Bumps the vendored yarn release (and the DEPS hook, .yarnrc.yml,
script/yarn.js and packageManager references to it) to 4.18.0.
.yarn/releases/yarn-4.18.0.cjs is bin/yarn.js from @yarnpkg/cli-dist@4.18.0
unmodified. The lockfile only changes its metadata version.
Among other fixes, 4.18's built-in TypeScript compatibility patch knows
about the TypeScript 7 package layout; 4.12 fails the fetch step with
ENOENT on lib/_tsc.js when asked to install typescript@7.
* build: bump the nan test lockfile to yarn 4.18's metadata version
The nan spec runner installs nan's test dependencies with the vendored
yarn in immutable mode, and yarn 4.18 refuses the install because it
wants to rewrite the lockfile's metadata version from 8 to 10. Regenerate
the lockfile in the nan patch with 4.18 so the install is a no-op again.
---------
Co-authored-by: Claude <noreply@anthropic.com>
* build: check the formatting of docs code blocks with oxfmt
lint-roller 4 splits the old `lint-roller-markdown-standard` into an
oxlint half and an oxfmt half. This wires up the second one:
`lint:fmt-in-markdown` runs `lint-roller-markdown-oxfmt` over docs/ as
part of `lint:docs`, using docs/.oxfmtrc.json, which matches the repo's
.oxfmtrc.json except that docs snippets keep their semicolon-free style.
`--fix` writes the formatted blocks back, and a block can opt out with
`@noformat` in its info string.
* docs: format code blocks with oxfmt
Result of `lint-roller-markdown-oxfmt --fix` with docs/.oxfmtrc.json, plus
the @ts-expect-error line anchors (and one Docusaurus highlight marker)
that moved with the reformat. The Babel output sample in the ESM guide and
the two excerpts of repo source in creating-api.md are marked @noformat,
and the contentTracing example passes an async callback instead of
wrapping an IIFE so that it does not need a leading semicolon.
---------
Co-authored-by: Claude <noreply@anthropic.com>
lint-roller 4 drops `lint-roller-markdown-standard` (and with it the
transitive eslint/standard dependency tree, roughly 1,900 lines of
yarn.lock) in favour of `lint-roller-markdown-oxlint`, which lints the JS
code blocks in docs/ with the repo's own oxlint and .oxlintrc.json. It
also makes `lint-roller-markdown-ts-check` work with TypeScript 6 and 7.
- `lint:js-in-markdown` now runs `lint-roller-markdown-oxlint`.
- `lint:docs-fiddles` ran the `standard` binary, which was only ever
installed as a dependency of lint-roller 3, so it now runs oxlint over
docs/fiddles instead. The dozen findings that surfaced (unused trailing
callback parameters, one `require('path')`, one stale eslint-disable
comment) are fixed in the fiddles, and the one tutorial that inlines an
affected fiddle is kept in sync.
- The `<!-- eslint-... -->` HTML comments in docs were directives for
lint-roller-markdown-standard and are removed, and the docs style guide
no longer points at standard-markdown.
Co-authored-by: Claude <noreply@anthropic.com>
- Remove @types/semver and @types/w3c-web-serial, which no TypeScript
code uses any more.
- Remove the @electron-ci/osr-gpu native addon fixture, which no spec
requires.
- Update @electron/fiddle-core to ^2.2.2 in the root and workflows
workspaces.
- Run `yarn dedupe` over the lockfile.
Co-authored-by: Claude <noreply@anthropic.com>
* 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>
Sandboxed renderers and service worker preload realms ran a webpack bundle
(sandbox_bundle / preload_realm_bundle) that built the preload scripts'
`process` object and `require`, assembled the `electron` module from the
JavaScript API wrappers, registered the <webview> element and then compiled
and ran each preload script. With the API modules now provided by their
bindings, the rest moves to C++ (shell/renderer/preload_environment.cc):
- `process` is a native EventEmitter carrying the same properties as
before, plus getProcessMemoryInfo(); 'loaded', 'exit', 'document-start'
and 'document-end' are emitted on it directly.
- `require('electron')` returns a module object whose properties load their
binding on first access.
- Preload scripts are compiled with CreatePreloadScript() and called with
(require, process, exports, module, global); failures are logged and
reported as 'preload-error' as before.
The only JavaScript Electron still evaluates in a sandboxed renderer is the
<webview> element implementation, now its own `webview_bundle`, and only in
renderers that enable `webviewTag`. The `process` npm polyfill is no longer
needed.
* refactor: implement EventEmitter natively for sandboxed preload bundles
Adds a C++ implementation of the `EventEmitter` class
(shell/common/gin_helper/node_event_emitter.cc, exposed through the
`electron_common_events` binding) and resolves `events` to it in the
bundles that run without a Node.js environment, so `ipcRenderer`,
`webFrame` and the sandboxed preload `process` object no longer pull the
`events` npm package into every sandboxed renderer.
The class provides the same instance API the `events` package did and
nothing more: on/once/off/emit/addListener/removeListener/prependListener/
prependOnceListener/removeAllListeners/listeners/rawListeners/
listenerCount/eventNames/setMaxListeners/getMaxListeners, the
'newListener' and 'removeListener' events, the max-listener console
warning and `EventEmitter.defaultMaxListeners`. As in lib/events.js the
listener state lives in `_events` / `_eventsCount` / `_maxListeners` on
the instance, so the methods are generic over their receiver and classes
can extend it. A spec runs the same scenarios against Node's EventEmitter
and this one and requires identical results.
* perf: dispatch IPC messages to listeners without going through JS
The native EventEmitter keeps `_events`, `_eventsCount` and
`_maxListeners` in internal fields on real instances (still surfaced as
the usual own data properties), caches its property keys, builds once()
wrappers by binding one shared native function instead of minting a new
function per call, and calls straight into its own C++ bodies for the
internal `this.emit()` / `this.on()` / `this.removeListener()` calls when
those methods are not overridden.
It also exports EmitEvent(), and ipc_native::EmitIPCEvent() now builds the
event object and emits on ipcRenderer / ipcRendererInternal from C++
instead of calling a JS `onMessage` trampoline that called `emit()`. In a
renderer with Node.js integration the emitters are Node's and EmitEvent()
calls their `emit` method.
* perf: call multiple listeners for one event from a JS loop
Calling N listeners through N v8::Function::Call() entries from C++ costs
about four times per listener what a JIT-compiled loop does. When an
event has more than one listener, hand the listener array to a one-line
`for (...) Reflect.apply(listener, self, args)` function compiled once per
context instead. The single-listener case is still one direct call from
C++. Also pins the listener-throws semantics (later listeners skipped,
emit rethrows) against Node's in the spec.
* fix: handle object event names and large removeAllListeners in the native EventEmitter
Deleting an event whose name is an arbitrary object asked v8::Object::Delete
to convert it to a property key, which needs to run script and is not
allowed there; convert it first. Emitting 'removeListener' for every
listener of an event kept all the temporary handles of the loop alive until
it finished; give each iteration its own HandleScope.
* fix: address review comments on the native EventEmitter
- removeListener() searches the listener array in place from the back
instead of copying it first, so removing the newest listener (what once()
wrappers and removeAllListeners() do) no longer costs a full copy each time.
- The 'removeListener' event reports the originally registered function when
a once() wrapper is removed from a multi-listener event, as events@3 did.
- A once() wrapper is only marked fired after its removeListener() call
succeeded, matching events@3's order.
* refactor: remove Node.js shims from sandboxed preload scripts
BREAKING CHANGE. Sandboxed preload scripts and service worker preload
scripts no longer get the `events`, `timers` and `url` module shims from
`require`, and are no longer run with `Buffer`, `setImmediate` and
`clearImmediate` in scope. `require` only loads `electron`; `process` and
`global` are still provided.
These were npm browser polyfills compiled into the bundle that every
sandboxed renderer evaluates, and made up about two thirds of it. With them
gone the preload wrapper's parameter list is fixed again, so the code cache
no longer needs to be keyed on the wrapper shape.
* docs: tabulate the removed preload shims and their replacements
The build-siso job needs the siso commit that our pinned Chromium expects. It
used to curl Chromium's DEPS from raw.githubusercontent.com on every run to find
it, and that fetch has failed main several times (HTTP errors / TLS resets that
took out all three siso jobs at once). The value only changes when Chromium
rolls, so record it in the repo and stop fetching:
- build/siso_revision holds the sha; pipeline-segment-build-siso reads it from a
sparse checkout and no longer touches the network to resolve it.
- script/gen-siso-revision.js derives it from the synced Chromium tree
(src/DEPS siso_version). A gen_siso_revision gclient hook runs it after every
sync, lint-staged runs it when DEPS changes, and gn-check runs it with --check
so a roll that forgets to commit the file fails with a clear message.
- The roller commit linter accepts "chore: update siso revision" (only that
file), and the Chromium upgrade skill tells you to commit it after a
successful sync, mirroring how filenames.libcxx.gni is handled.
* build: drop unused dev dependencies and the abstract-socket native module
Removes dependencies that nothing in the tree uses any more:
* sinon / @types/sinon: no spec imports them.
* check-for-leaks: only wired to `prepack`, and the root package is
private and never packed.
* null-loader: the only rule using it matched against an always-empty
`ignoredModules` list in the webpack config.
* @types/uuid: uuid ships its own types since well before the version
we depend on.
* q, coffeescript, mkdirp: each backed a single test of third-party
module behaviour. The `require` app-directory test now uses
dirty-chai (any module that only lives in spec/node_modules works,
it is exercising module.paths, not the module), and the mkdirp asar
test is replaced by a `fs.mkdirSync(..., { recursive: true })` case
next to the existing mkdirSync test.
Also drops abstract-socket. dbus-native only used it to connect to
`unix:abstract=` bus addresses, and Node.js has supported abstract
sockets natively via a leading NUL byte since 20.8, so dbus-native is
now patched to use net.createConnection instead. That lets us delete
the abstract-socket patch, its resolutions entry, the dependenciesMeta
`built` opt-in, the packageExtensions block in .yarnrc.yml and the
Linux-only `npm rebuild abstract-socket` step in the spec runner.
abstract-socket itself still appears in the lockfile as dbus-native's
optional dependency (patches cannot change resolution), but it is no
longer built or required by anything.
No-Verification-Needed: dependency, test and build-tooling changes only; no product source touched
* build: replace uuid, basic-auth and temp with Node.js built-ins
* uuid -> crypto.randomUUID() across the specs.
* basic-auth -> a small parseBasicAuth() helper in spec/lib/net-helpers,
used by the two specs that need to read Basic credentials.
* temp -> fs.mkdtempSync in release.ts and in the asar copyFile specs.
Also removes script/doc-only-change.js, whose last caller went away with
the AppVeyor configs.
No-Verification-Needed: spec, release-tooling and manifest changes only; no product source touched
* build: use webpack's BannerPlugin instead of wrapper-webpack-plugin
wrapper-webpack-plugin is a webpack 4 era plugin that still hooks the
deprecated optimizeChunkAssets hook. webpack 5's built-in BannerPlugin
can prepend a raw header and (with `footer: true`) append a raw footer,
and instances run in registration order, so the profiling wrapper and
the try/catch wrapper nest exactly as before. The only difference in the
emitted bundles is a newline between each wrapper and the bundle body.
No-Verification-Needed: webpack build config only; emitted bundle diffed against the previous plugin's output (whitespace-only), production output checked for nesting and syntax
* build: vendor the default app's octicons
The default app uses five icons and an 88 byte stylesheet out of
@primer/octicons, and pulling them out of node_modules was the only
place the GN build reached into node_modules for shipped content. Copy
the files (MIT licensed, notice included alongside) into
default_app/octicon so they are plain static sources like the rest of
the default app, and drop the dependency and the extra copy target. The
files end up at the same paths inside default_app.asar as before.
No-Verification-Needed: vendored files are byte-identical to the octicon files the existing build already ships at the same asar paths
* build: drop got and dedupe @electron/fiddle-core
The release scripts were the only direct users of got, and every call
was a plain GET/HEAD/POST that global fetch covers: HEAD requests use
`redirect: 'manual'` in place of `followRedirect: false`, and the
non-2xx handling that previously relied on `throwHttpErrors: false` now
checks `response.status` explicitly. The asset manifest in release.ts is
untouched.
got@11 was also still being kept alive by @electron/fiddle-core@1, which
the root package depended on while .github/workflows already used ^2.
Aligning the root on ^2 removes the second copy of fiddle-core and
@electron/get along with the whole got@11 dependency chain (41 packages).
fiddle-core 2 is ESM-only; the CommonJS spec runner loads it through
require(esm), which is available on the Node 22.21 CI uses and anything
newer than 22.12.
No-Verification-Needed: release tooling, spec runner and manifest changes only; no product source touched
* test: replace express in the autoUpdater specs with a small router
The two autoUpdater specs were the only users of express, and between
them they use `use()`, `get()` with one `:param` route, `res.status()`,
`res.send()`, `res.json()` and `res.download()`. spec/lib/http-server-
helpers.ts provides exactly that surface on top of node:http, with file
responses still going through `send` (what express uses internally) so
HEAD, Range and content-type behaviour towards the updaters is unchanged.
`send` is bumped to the 1.x line express 5 was already using, since 0.x
serves .msix files as application/octet-stream rather than
application/msix.
Removes express, @types/express and 43 transitive packages.
No-Verification-Needed: spec-only change; helper exercised over HTTP for GET/HEAD/Range/json/204/404 routing
* test: depend on resedit directly instead of @electron/packager
The asar integrity spec only used @electron/packager for its resedit
wrapper, and only the branch of that wrapper which embeds the integrity
resource on Windows. Do that directly with resedit (the library the
wrapper is built on), which is a dozen lines, and drop packager along
with the 24 signing/notarizing/downloading packages it brings in.
No-Verification-Needed: spec-only change; resource embedding round-tripped against a real PE locally
* test: replace the last temp usage in the protocol code cache spec
The `temp` package was dropped from the root package.json but
api-protocol-spec.ts still required it inline, so every test shard
that loads that file failed at spec-runner startup.
No-Verification-Needed: test-only change
* build: fix dependabot alerts
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test: use pdfjs-dist legacy build in pdf-reader fixture
The modern build of pdfjs-dist 4.10.x logs a "please use the legacy
build" warning via console.log, which corrupts the JSON that
pdf-helpers.ts parses from the fixture's stdout.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Removes the chalk devDependency in favor of the built-in styleText
API from node:util, which is available in all Node versions used by
the project's scripts and CI.
Co-authored-by: Claude <svc-devxp-claude@slack-corp.com>
* chore: bump simple-git to 3.36.0 and basic-ftp to 5.3.1
Both lockfile-pinned versions have known vulnerabilities:
- simple-git@3.33.0: GHSA-hffm-xvc3-vprc, pinned exactly by
@datadog/datadog-ci (still pinned in their latest release), so this
adds a root resolutions override to the patched 3.36.0
- basic-ftp@5.3.0: GHSA-rpmf-866q-6p89, transitive via get-uri@^5.0.2,
re-resolved within range to the patched 5.3.1
* chore: bump @datadog/datadog-ci to ^5.17.0 instead of overriding simple-git
Per review feedback: datadog-ci-base 5.16.1+ pins simple-git ^3.36.0,
so bumping @datadog/datadog-ci removes the need for the resolutions
override. simple-git still resolves to the patched 3.36.0 (via
@electron/fiddle-core's ^3.5.0), and the vulnerable basic-ftp version
drops out of the tree entirely since 5.17.0 bundles its dependencies.
Adds a workflow_dispatch pipeline that builds PGO-instrumented Electron
for every published platform/arch combo, collects optimization profiles
by running benchmark and app-style workloads against each build, and
publishes merged profiles to https://dev-cdn.electronjs.org/pgo/.
Why: Electron release builds apply Chrome's published PGO profile, which
matches functions by symbol name and control-flow hash. Every function
that differs from Chrome - all of Node.js, patched Chromium code, V8
built with Node's flags, and the shell/ code - silently gets no
optimization guidance and is laid out as cold. The same applies to V8's
builtins profile: Chrome's published profiles reject Electron's
promise/async builtins because the Node integration changes their
codegen. Measured on Linux x64, an Electron-collected profile is worth
+9.5% on Speedometer 3.1 and +16% geomean across 22 app-operation
benchmarks (contextBridge calls +44-51%) versus Chrome's profile.
The pipeline:
- Instrumented builds (chrome_pgo_phase = 1) for linux x64/arm/arm64,
win x64/x86/arm64, and macos x64/arm64, each collecting on hosts that
can run its own binaries.
- Collection workloads: Speedometer 3 (x3), JetStream 2, and MotionMark
(the same set Chromium's PGO recipe uses), plus Electron-specific
phases browser benchmarks cannot cover: main-process Node.js
(Buffer/crypto/fs/JSON), contextBridge and ipcRenderer.invoke
marshaling, and renderer/Node networking over HTTPS + HTTP/2 with real
certificate verification via an ephemeral CA installed in the
collection host's trust store.
- A V8 builtins profile generated from an instrumented d8 built with
Electron's exact V8 configuration; one x64 profile covers x64 and
arm64 (builtin block graphs are arch-independent, mirroring upstream).
- Per-platform profraw sets merged with in-tree llvm-profdata tooling,
then uploaded via OIDC through the pgo-upload GitHub environment
(manual approval, no long-lived credentials).
Build-system changes:
- build/args/pgo-instrument.gn and pgo-builtins-instrument.gn
instrumented build configurations (symbol_level = 0, no dSYMs -
instrumented binaries are never shipped and do not fit on macOS
runners with debug info).
- A Chromium patch fixing profile-runtime resolution for instrumented
builds on Linux arm32 (clang package ships the armv7 triple; the
driver resolves the arm triple) and Windows cross-compiles (objects
embed the per-target runtime lib name; the Windows package ships the
legacy layout). Chrome never builds these configurations; the patch is
upstreamable.
- generate-chromedriver and generate-test-artifacts flags on the build
segment and build-electron action (default true, no behavior change
for existing callers) so instrumented builds skip artifacts only
consumed by test jobs.
Release builds do not consume these profiles yet; that is a follow-up
change.
* build: dedupe get-intrinsic to shrink the sandboxed renderer bundle
The hoisted get-intrinsic resolved to 1.2.1 (satisfying the older
^1.0.2..^1.2.0 consumers), so side-channel-weakmap, side-channel-map,
call-bound and es-set-tostringtag — which need ^1.2.5/^1.3.0 — each
pulled a nested get-intrinsic@1.3.0 copy. webpack bundled three of
those nested copies into sandbox_bundle.js (~16.5 KB each).
1.3.0 satisfies every range in the tree (all ^1.x), so pin it via
resolutions to collapse to a single copy. Drops sandbox_bundle.js
from 364,762 to 323,116 bytes (-41,646, -11.4%) — that bundle is
parsed/preparsed in every sandboxed renderer before the HTML parser,
so this is a direct per-renderer startup win on top of the IPC and
code-cache changes.
* perf: build-time V8 code cache for the electron/js2c framework bundles
Generate a V8 code cache for Electron's embedded electron/js2c/* bundles
at build time and embed it in the binary, so each process deserializes
its framework bundle (kConsumeCodeCache) instead of parsing and compiling
it from source at startup.
V8's code-cache key includes FlagList::Hash() over non-default flags and
the snapshot's read-only checksum, both of which differ per process type,
so one cache variant is generated per flavor and each process consumes
the matching one:
sandbox : sandboxed renderer, no Node env (+SAB)
renderer : normal renderer, has Node env (+SAB +rehash +no-freeze)
browser : main process (+rehash +no-freeze)
utility : utility process (+rehash +no-freeze)
worker : node/web worker (+rehash +no-freeze)
All flavors create their isolate from the v8 context snapshot. The flag
deltas are deterministic; --no-freeze-flags-after-init (present iff the
process has a Node Environment) lets V8 recompute the flag-hash after
init, so the consume-time hash of every node-env process includes
--rehash-snapshot. A sandboxed renderer has no Node env (flags stay
frozen) so it is a distinct flavor, discriminated at runtime by
node::Environment::GetCurrent(context).
The generator compiles each bundle with kEagerCompile so the cache
covers the inner functions, not just the top-level wrapper -- the
framework bundles run in full at startup, so this front-loads the lazy
compiles to build time. Cross-arch is supported (the generator is built
in v8_snapshot_toolchain so it links V8 with V8_TARGET_ARCH set to the
target and reads the target's snapshot blob); cross-OS is untested and
gated off.
- electron_natives_codecache_main.cc: per-flavor build-time generator
compiling each bundle through the same BuiltinLoader path its runtime
consumer uses.
- shell/common/js2c_bundle_ids.h: shared bundle ids and wrapper-function
param names used by the generator and the runtime CompileAndCall call
sites, so the source/params hash matches by construction.
- node_util.cc feeds the standalone loader; FeedEnvironmentCodeCache
feeds the per-Environment loader before LoadEnvironment so the *_init
bundles are consumed.
- Test-only (DCHECK builds, compiled out of production): a per-process
id->accepted status map exposed via v8_util.getJs2cCodeCacheStatus, a
sandboxed-preload shim, and spec/api-js2c-code-cache-spec.ts which
spawns a clean app and asserts every bundle is consumed in
browser/sandbox/renderer/utility.
DidClearWindowObject (sandboxed renderer, pre-HTML-parser): ~9.8 ms
(cache rejected/absent) -> ~6.4 ms (eager cache consumed), a ~3.4 ms /
~35% cold-start win on every launch. No V8 patch.
* chore: export node patch for the js2c build-time code cache
The deepak1556/node-abstractsocket fork carries an N-API rewrite and
cross-OS install support on top of the unpublished upstream v2.1.1.
Neither change exists on npm (latest is 2.0.0) or in upstream git, so
vendoring the diff as a yarn patch removes the external git dependency
while keeping the same code.
Yarn's patch: protocol ignores dependency and os edits in the patched
manifest, so node-addon-api is added via packageExtensions instead. The
original os=linux condition is left in place; under Yarn Berry it simply
skips linking on other platforms, which is what we want for a Linux-only
dbus test dep.
* build: bump node-gyp to 12.3.0
Picks up Visual Studio 2026 (18.x) detection support added in
node-gyp 12.1.0, so building native addons against this Electron's
node headers works on Windows installs that only have VS 2026.
* build: dedupe node-gyp on 12.3.0 across workspaces
Forces re-resolution of the `node-gyp: latest` entries in spec/ and
the native-addon fixtures (which yarn had cached at 11.5.0) onto the
same 12.3.0 the root devDep is using, so VS 2026 detection is
consistent everywhere we shell out to node-gyp.
* build: add oxfmt for code formatting and import sorting
Adds oxfmt as a devDependency alongside oxlint and wires it into the
lint pipeline. The .oxfmtrc.json config matches Electron's current JS
style (single quotes, semicolons, 2-space indent, trailing commas off,
printWidth 100) and configures sortImports with custom groups that
mirror the import/order pathGroups previously enforced by ESLint:
@electron/internal, @electron/*, and {electron,electron/**} each get
their own ordered group ahead of external modules.
- `yarn lint:fmt` runs `oxfmt --check` over JS/TS sources and is
chained into `yarn lint` so CI enforces it automatically.
- `yarn format` runs `oxfmt --write` for local fix-up.
- lint-staged invokes `oxfmt --write` on staged .js/.ts/.mjs/.cjs
files before oxlint, so formatting is applied at commit time.
The next commit applies the formatter to the existing codebase so the
check actually passes.
* chore: apply oxfmt formatting to JS and TS sources
Runs `yarn format` across lib/, spec/, script/, build/, default_app/,
and npm/ to bring the codebase in line with the .oxfmtrc.json settings
added in the previous commit. This is a pure formatting pass: import
statements are sorted into the groups defined by the config, method
chains longer than printWidth are broken, single-quoted strings
containing apostrophes are switched to double quotes, and a handful of
single-statement `if` bodies are re-wrapped and get braces added by
`oxlint --fix` to satisfy the `curly: multi-line` rule.
No behavior changes.
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.
* build: replace npx with lockfile-pinned binaries
- nan-spec-runner: reorder yarn install first, invoke nan node-gyp bin directly
- publish-to-npm: use host npm with E404 try/catch (closes existing TODO)
- upload-symbols: add @sentry/cli devDep, invoke from node_modules/.bin
- remove script/lib/npx.py (dead since #48243)
* build: bump @sentry/cli to 1.70.0 for arm support
* build: bump @sentry/cli to 1.72.0, skip CDN download on test jobs
@sentry/cli fetches its platform binary from Sentry CDN at postinstall.
Only upload-symbols.py (release pipeline) needs the binary; set
SENTRYCLI_SKIP_DOWNLOAD=1 in the two test-segment workflows that
call install-dependencies. The 64k variant uses pre-built artifacts
and does not install deps.
* build(deps-dev): replace timers-browserify
Co-Authored-By: Claude <noreply@anthropic.com>
Generated-By: GitHub Copilot
* update shim from js to ts
Co-Authored-By: Claude <noreply@anthropic.com>
Generated-By: GitHub Copilot
* remove timers-shim.js
* remove refs from package json and yarn lock
* update process in yarn lock
---------
Co-authored-by: Claude <noreply@anthropic.com>
* build: lint commits on Chromium roller branches
Assisted-By: Claude Opus 4.5
* chore: add ability to skip linting CLs by adding #nolint
* chore: only exit with non-zero exit code in CI