Upload via GUI (7543 Dateien)

This commit is contained in:
2026-10-22 06:56:47 +00:00
parent d7658c873f
commit bac355eabb
50 changed files with 2263 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) Contributors to the Electron project
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+202
View File
@@ -0,0 +1,202 @@
# @electron/rebuild
[![Test](https://github.com/electron/rebuild/actions/workflows/test.yml/badge.svg)](https://github.com/electron/rebuild/actions/workflows/test.yml)
[![NPM](https://img.shields.io/npm/v/@electron/rebuild.svg?style=flat)](https://npm.im/@electron/rebuild)
[![Coverage Status](https://codecov.io/gh/electron/rebuild/branch/main/graph/badge.svg)](https://codecov.io/gh/electron/rebuild)
[![API docs](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fregistry.npmjs.org%2F%40electron%2Frebuild%2Flatest&query=%24.version&logo=typescript&logoColor=white&label=API%20Docs)](https://packages.electronjs.org/rebuild)
This executable rebuilds native Node.js modules against the version of Node.js
that your Electron project is using. This allows you to use native Node.js
modules in Electron apps without your system version of Node.js matching exactly
(which is often not the case, and sometimes not even possible).
### How does it work?
Install the package with `--save-dev`:
```sh
npm install --save-dev @electron/rebuild
```
Then, whenever you install a new npm package, rerun electron-rebuild:
```sh
$(npm bin)/electron-rebuild
```
Or if you're on Windows:
```sh
.\node_modules\.bin\electron-rebuild.cmd
```
If you have a good node-gyp config but you see an error about a missing element on Windows like `Could not load the Visual C++ component "VCBuild.exe"`, try to launch `electron-rebuild` in an npm script:
```json
"scripts": {
"rebuild": "electron-rebuild -f -w yourmodule"
}
```
and then
```sh
npm run rebuild
```
### What are the requirements?
Node v22.12.0 or higher is required. Building native modules from source uses
[`node-gyp`](https://github.com/nodejs/node-gyp#installation). Refer to the link for its
installation/runtime requirements.
### CLI arguments
```
Usage: electron-rebuild --version [version] --module-dir [path]
Options:
-v, --version The version of Electron to build against [string]
-f, --force Force rebuilding modules, even if we would skip
it otherwise [boolean]
-a, --arch Override the target architecture to something
other than your system's [string]
-m, --module-dir The path to the node_modules directory to rebuild
[string]
-w, --which-module A specific module to build, or comma separated
list of modules. Modules will only be rebuilt if
they also match the types of dependencies being
rebuilt (see --types). [string]
-o, --only Only build specified module, or comma separated
list of modules. All others are ignored. [string]
-e, --electron-prebuilt-dir The path to the prebuilt electron module [string]
-d, --dist-url Custom header tarball URL [string]
-t, --types The types of dependencies to rebuild. Comma
separated list of "prod", "dev" and "optional".
Default is "prod,optional" [string]
-p, --parallel Rebuild in parallel, this is enabled by default
on macOS and Linux [boolean]
-s, --sequential Rebuild modules sequentially, this is enabled by
default on Windows [boolean]
-b, --debug Build debug version of modules [boolean]
-j, --jobs Number of parallel compile jobs node-gyp should
run (passed as node-gyp --jobs). Defaults to
node-gyp's own default. [number]
--prebuild-tag-prefix GitHub tag prefix passed to prebuild-install.
Default is "v" [string]
--force-abi Override the ABI version for the version of
Electron you are targeting. Only use when
targeting Nightly releases. [number]
--use-electron-clang Use the clang executable that Electron used when
building its binary. This will guarantee compiler
compatibility [boolean]
--disable-pre-gyp-copy Disables the pre-gyp copy step [boolean]
--build-from-source Skips prebuild download and rebuilds module from
source. [boolean]
-h, --help Show help [boolean]
```
> [!NOTE]
> The `--dist-url` value can also be provided via the `ELECTRON_REBUILD_DIST_URL`
> environment variable. The `--dist-url` flag takes precedence when both are set.
> [!NOTE]
> By default, only your `prod` and `optional` dependencies are rebuilt —
> `devDependencies` are **not** rebuilt. This is because the default value of
> `types` is `['prod', 'optional']`. If you have a native module in your
> `devDependencies` that you need rebuilt, you must explicitly include `dev` in
> the list of types:
>
> - CLI: `electron-rebuild --types prod,optional,dev` (or `-t prod,optional,dev`)
> - API: `rebuild({ ..., types: ['prod', 'optional', 'dev'] })`
### How can I use this with [Electron Forge](https://github.com/electron/forge)?
This package is automatically used with Electron Forge when packaging an Electron app.
### How can I integrate this into [Electron Packager](https://github.com/electron/packager)?
electron-rebuild provides a function compatible with the [`afterCopy` hook](https://packages.electronjs.org/packager/v19.0.5/interfaces/Options.html#aftercopy)
for Electron Packager. For example:
```javascript
import { packager } from "@electron/packager";
import { rebuild } from "@electron/rebuild";
packager({
// … other options
afterCopy: [
async ({ buildPath, electronVersion, arch }) => {
await rebuild({ buildPath, electronVersion, arch });
},
],
// … other options
});
```
### How can I integrate this with [prebuild](https://github.com/prebuild/prebuild)?
If your module uses [prebuild](https://github.com/prebuild/prebuild) for creating prebuilt binaries,
it also uses [prebuild-install](https://github.com/prebuild/prebuild-install) to download them. If
this is the case, then `electron-rebuild` will run `prebuild-install` to download the correct
binaries from the project's GitHub Releases instead of rebuilding them.
### How can I integrate this into my build pipeline?
electron-rebuild is also a library that you can require into your app or
build process. It has a very simple API:
```javascript
import { rebuild } from '@electron/rebuild';
// Public: Rebuilds a node_modules directory with the given Electron version.
//
// options: Object with the following properties
// buildPath - An absolute path to your app's directory. (The directory that contains your node_modules)
// electronVersion - The version of Electron to rebuild for
// arch (optional) - Default: process.arch - The arch to rebuild for
// extraModules (optional) - Default: [] - An array of modules to rebuild as well as the detected modules
// onlyModules (optional) - Default: null - An array of modules to rebuild, ONLY these module names will be rebuilt.
// The "types" property will be ignored if this option is set.
// force (optional) - Default: false - Force a rebuild of modules regardless of their current build state
// headerURL (optional) - Default: https://www.electronjs.org/headers - The URL to download Electron header files from
// types (optional) - Default: ['prod', 'optional'] - The types of modules to rebuild
// mode (optional) - The rebuild mode, either 'sequential' or 'parallel' - Default varies per platform (probably shouldn't mess with this one)
// useElectronClang (optional) - Whether to use the clang executable that Electron used when building its binary. This will guarantee compiler compatibility
// Returns a Promise indicating whether the operation succeeded or not
```
For full API usage, see the [API documentation](https://packages.electronjs.org/rebuild).
A full build process might look something like:
```javascript
// ESM
import { rebuild } from "@electron/rebuild";
rebuild({
buildPath: import.meta.dirname,
electronVersion: "35.1.5",
})
.then(() => console.info("Rebuild Successful"))
.catch((e) => {
console.error("Building modules didn't work!");
console.error(e);
});
// CommonJS
const { rebuild } = require("@electron/rebuild");
rebuild({
buildPath: __dirname,
electronVersion: "35.1.5",
})
.then(() => console.info("Rebuild Successful"))
.catch((e) => {
console.error("Building modules didn't work!");
console.error(e);
});
```
+7
View File
@@ -0,0 +1,7 @@
import { pathToFileURL } from 'node:url';
process.argv.splice(1, 1);
// This tricks prebuild-install into not validating on the
// 1.8.x and 8.x ABI collision
Object.defineProperty(process.versions, 'modules', { value: '-1', writable: false });
void import(pathToFileURL(process.argv[1]).toString());
//# sourceMappingURL=prebuild-shim.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"prebuild-shim.js","sourceRoot":"","sources":["../src/prebuild-shim.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAE1B,0DAA0D;AAC1D,8BAA8B;AAC9B,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;AAErF,KAAK,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC"}
+1
View File
@@ -0,0 +1 @@
export declare function readPackageJson(dir: string, safe?: boolean): Promise<any>;
+19
View File
@@ -0,0 +1,19 @@
import fs from 'node:fs/promises';
import path from 'node:path';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export async function readPackageJson(dir, safe = false) {
try {
return JSON.parse(await fs.readFile(path.resolve(dir, 'package.json'), {
encoding: 'utf-8',
}));
}
catch (err) {
if (safe) {
return {};
}
else {
throw err;
}
}
}
//# sourceMappingURL=read-package-json.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"read-package-json.js","sourceRoot":"","sources":["../src/read-package-json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,8DAA8D;AAC9D,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAW,EAAE,IAAI,GAAG,KAAK;IAC7D,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CACf,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE;YACnD,QAAQ,EAAE,OAAO;SAClB,CAAC,CACH,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,EAAE,CAAC;QACZ,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;AACH,CAAC"}
+155
View File
@@ -0,0 +1,155 @@
import { EventEmitter } from 'node:events';
import { BuildType, IRebuilder, RebuildMode } from './types.js';
import { ModuleType } from './module-walker.js';
export interface RebuildOptions {
/**
* The path to the `node_modules` directory to rebuild.
*/
buildPath: string;
/**
* The version of Electron to build against.
*/
electronVersion: string;
/**
* Override the target platform to something other than the host system platform.
* Note: This only applies to downloading prebuilt binaries. **It is not possible to cross-compile native modules.**
*
* @defaultValue The system {@link https://nodejs.org/api/process.html#processplatform | `process.platform`} value
*/
platform?: NodeJS.Platform;
/**
* Override the target rebuild architecture to something other than the host system architecture.
*
* @defaultValue The system {@link https://nodejs.org/api/process.html#processarch | `process.arch`} value
*/
arch?: string;
/**
* An array of module names to rebuild in addition to detected modules
* @default []
*/
extraModules?: string[];
/**
* An array of module names to rebuild. **Only** these modules will be rebuilt.
*/
onlyModules?: string[] | null;
/**
* Force a rebuild of modules regardless of their current build state.
*/
force?: boolean;
/**
* URL to download Electron header files from.
* @defaultValue `https://www.electronjs.org/headers`
*/
headerURL?: string;
/**
* Array of types of dependencies to rebuild. Possible values are `prod`, `dev`, and `optional`.
*
* @defaultValue `['prod', 'optional']`
*/
types?: ModuleType[];
/**
* Whether to rebuild modules sequentially or in parallel.
*
* @defaultValue `sequential`
*/
mode?: RebuildMode;
/**
* Rebuilds a Debug build of target modules. If this is `false`, a Release build will be generated instead.
*
* @defaultValue false
*/
debug?: boolean;
/**
* Enables hash-based caching to speed up local rebuilds.
*
* @experimental
* @defaultValue false
*/
useCache?: boolean;
/**
* Whether to use the `clang` executable that Electron uses when building.
* This will guarantee compiler compatibility.
*
* @defaultValue false
*/
useElectronClang?: boolean;
/**
* Sets a custom cache path for the {@link useCache} option.
* @experimental
* @defaultValue a `.electron-rebuild-cache` folder in the `os.homedir()` directory
*/
cachePath?: string;
/**
* GitHub tag prefix passed to {@link https://www.npmjs.com/package/prebuild-install | `prebuild-install`}.
* @defaultValue `v`
*/
prebuildTagPrefix?: string;
/**
* Path to the root of the project if using npm or yarn workspaces.
*/
projectRootPath?: string;
/**
* Override the Application Binary Interface (ABI) version for the version of Electron you are targeting.
* Only use when targeting nightly releases.
*
* @see the {@link https://github.com/electron/node-abi | electron/node-abi} repository for a list of Electron and Node.js ABIs
*/
forceABI?: number;
/**
* Disables the copying of `.node` files if not needed.
* @defaultValue false
*/
disablePreGypCopy?: boolean;
/**
* Skip prebuild download and rebuild module from source.
*
* @defaultValue false
*/
buildFromSource?: boolean;
/**
* Array of module names to ignore during the rebuild process.
*/
ignoreModules?: string[];
/**
* Number of parallel compile jobs `node-gyp` should run, passed through as node-gyp's `--jobs` flag.
*
* @defaultValue node-gyp's own default when unset
*/
jobs?: number;
}
export interface RebuilderOptions extends RebuildOptions {
lifecycle: EventEmitter;
}
export declare class Rebuilder implements IRebuilder {
private ABIVersion;
private moduleWalker;
rebuilds: (() => Promise<void>)[];
lifecycle: EventEmitter;
buildPath: string;
electronVersion: string;
platform: NodeJS.Platform;
arch: string;
force: boolean;
headerURL: string;
mode: RebuildMode;
debug: boolean;
useCache: boolean;
cachePath: string;
prebuildTagPrefix: string;
msvsVersion?: string;
useElectronClang: boolean;
disablePreGypCopy: boolean;
buildFromSource: boolean;
ignoreModules: string[];
jobs?: number;
constructor(options: RebuilderOptions);
get ABI(): string;
get buildType(): BuildType;
rebuild(): Promise<void>;
modulesToRebuild(): Promise<string[]>;
rebuildModuleAt(modulePath: string): Promise<void>;
}
export type RebuildResult = Promise<void> & {
lifecycle: EventEmitter;
};
export declare function rebuild(options: RebuildOptions): RebuildResult;
+181
View File
@@ -0,0 +1,181 @@
import debug from 'debug';
import { EventEmitter } from 'node:events';
import fs from 'node:fs';
import { getAbi } from 'node-abi';
import os from 'node:os';
import path from 'node:path';
import { generateCacheKey, lookupModuleState } from './cache.js';
import { BuildType } from './types.js';
import { ModuleRebuilder } from './module-rebuilder.js';
import { ModuleWalker } from './module-walker.js';
const d = debug('electron-rebuild');
const defaultMode = 'sequential';
const defaultTypes = ['prod', 'optional'];
export class Rebuilder {
ABIVersion;
moduleWalker;
rebuilds;
lifecycle;
buildPath;
electronVersion;
platform;
arch;
force;
headerURL;
mode;
debug;
useCache;
cachePath;
prebuildTagPrefix;
msvsVersion;
useElectronClang;
disablePreGypCopy;
buildFromSource;
ignoreModules;
jobs;
constructor(options) {
this.lifecycle = options.lifecycle;
this.buildPath = options.buildPath;
this.electronVersion = options.electronVersion;
this.platform = options.platform || process.platform;
this.arch = options.arch || process.arch;
this.force = options.force || false;
this.headerURL = options.headerURL || 'https://www.electronjs.org/headers';
this.mode = options.mode || defaultMode;
this.debug = options.debug || false;
this.useCache = options.useCache || false;
this.useElectronClang = options.useElectronClang || false;
this.cachePath = options.cachePath || path.resolve(os.homedir(), '.electron-rebuild-cache');
this.prebuildTagPrefix = options.prebuildTagPrefix ?? 'v';
this.msvsVersion = process.env.GYP_MSVS_VERSION;
this.disablePreGypCopy = options.disablePreGypCopy || false;
this.buildFromSource = options.buildFromSource || false;
this.ignoreModules = options.ignoreModules || [];
this.jobs = options.jobs;
d('ignoreModules', this.ignoreModules);
if (this.useCache && this.force) {
console.warn('[WARNING]: Electron Rebuild has force enabled and cache enabled, force take precedence and the cache will not be used.');
this.useCache = false;
}
// FIXME: this entire guard is unreachable according to the types
/* oxlint-disable typescript-eslint(restrict-template-expressions) */
if (typeof this.electronVersion === 'number') {
if (`${this.electronVersion}`.split('.').length === 1) {
this.electronVersion = `${this.electronVersion}.0.0`;
}
else {
this.electronVersion = `${this.electronVersion}.0`;
}
}
/* oxlint-enable typescript-eslint(restrict-template-expressions) */
if (typeof this.electronVersion !== 'string') {
throw new Error(`Expected a string version for electron version, got a "${typeof this.electronVersion}"`);
}
this.ABIVersion = options.forceABI?.toString();
const onlyModules = options.onlyModules || null;
const extraModules = new Set(options.extraModules);
const types = options.types || defaultTypes;
this.moduleWalker = new ModuleWalker(this.buildPath, options.projectRootPath, types, extraModules, onlyModules);
this.rebuilds = [];
d('rebuilding with args:', this.buildPath, this.electronVersion, this.platform, this.arch, extraModules, this.force, this.headerURL, types, this.debug);
}
get ABI() {
if (this.ABIVersion === undefined) {
this.ABIVersion = getAbi(this.electronVersion, 'electron');
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return this.ABIVersion;
}
get buildType() {
return this.debug ? BuildType.Debug : BuildType.Release;
}
async rebuild() {
if (!path.isAbsolute(this.buildPath)) {
throw new Error('Expected buildPath to be an absolute path');
}
this.lifecycle.emit('start');
const candidatePaths = [...(await this.modulesToRebuild()), this.buildPath];
const nativeModulePaths = candidatePaths.filter((p) => fs.existsSync(path.resolve(p, 'binding.gyp')));
this.lifecycle.emit('modules-found', nativeModulePaths.map((p) => {
const name = path.basename(p);
const parent = path.basename(path.dirname(p));
return parent !== 'node_modules' ? `${parent}/${name}` : name;
}));
for (const modulePath of nativeModulePaths) {
this.rebuilds.push(() => this.rebuildModuleAt(modulePath));
}
if (this.mode !== 'sequential') {
await Promise.all(this.rebuilds.map((fn) => fn()));
}
else {
for (const rebuildFn of this.rebuilds) {
await rebuildFn();
}
}
}
async modulesToRebuild() {
await this.moduleWalker.walkModules();
for (const nodeModulesPath of await this.moduleWalker.nodeModulesPaths) {
await this.moduleWalker.findAllModulesIn(nodeModulesPath);
}
return this.moduleWalker.modulesToRebuild;
}
async rebuildModuleAt(modulePath) {
const moduleRebuilder = new ModuleRebuilder(this, modulePath);
let moduleName = path.basename(modulePath);
const parentName = path.basename(path.dirname(modulePath));
if (parentName !== 'node_modules') {
moduleName = `${parentName}/${moduleName}`;
}
this.lifecycle.emit('module-found', moduleName);
if (!this.force && (await moduleRebuilder.alreadyBuiltByRebuild())) {
d(`skipping: ${moduleName} as it is already built`);
this.lifecycle.emit('module-done', moduleName);
this.lifecycle.emit('module-skip', moduleName);
return;
}
d('checking', moduleName, 'against', this.ignoreModules);
if (this.ignoreModules.includes(moduleName)) {
d(`skipping: ${moduleName} as it is in the ignoreModules array`);
this.lifecycle.emit('module-done', moduleName);
this.lifecycle.emit('module-skip', moduleName);
return;
}
if (await moduleRebuilder.prebuildInstallNativeModuleExists()) {
d(`skipping: ${moduleName} as it was prebuilt`);
return;
}
let cacheKey;
if (this.useCache) {
cacheKey = await generateCacheKey({
ABI: this.ABI,
arch: this.arch,
platform: this.platform,
debug: this.debug,
electronVersion: this.electronVersion,
headerURL: this.headerURL,
modulePath,
});
const applyDiffFn = await lookupModuleState(this.cachePath, cacheKey);
if (typeof applyDiffFn === 'function') {
await applyDiffFn(modulePath);
this.lifecycle.emit('module-done', moduleName);
return;
}
}
if (await moduleRebuilder.rebuild(cacheKey)) {
this.lifecycle.emit('module-done', moduleName);
}
}
}
export function rebuild(options) {
// eslint-disable-next-line prefer-rest-params
d('rebuilding with args:', arguments);
const lifecycle = new EventEmitter();
const rebuilderOptions = { ...options, lifecycle };
const rebuilder = new Rebuilder(rebuilderOptions);
const ret = rebuilder.rebuild();
ret.lifecycle = lifecycle;
return ret;
}
//# sourceMappingURL=rebuild.js.map
File diff suppressed because one or more lines are too long
+23
View File
@@ -0,0 +1,23 @@
/**
* Find all instances of a given module in node_modules subdirectories while traversing up
* ancestor directories.
*
* @param cwd the initial directory to traverse
* @param moduleName the Node module name (should work for scoped modules as well)
* @param rootPath the project's root path. If provided, the traversal will stop at this path.
*/
export declare function searchForModule(cwd: string, moduleName: string, rootPath?: string): Promise<string[]>;
/**
* Find all instances of node_modules subdirectories while traversing up ancestor directories.
*
* @param cwd the initial directory to traverse
* @param rootPath the project's root path. If provided, the traversal will stop at this path.
*/
export declare function searchForNodeModules(cwd: string, rootPath?: string): Promise<string[]>;
/**
* Determine the root directory of a given project, by looking for a directory with an
* NPM or yarn lockfile or pnpm lockfile.
*
* @param cwd the initial directory to traverse
*/
export declare function getProjectRootPath(cwd: string): Promise<string>;
+68
View File
@@ -0,0 +1,68 @@
import fs from 'node:fs';
import path from 'node:path';
async function shouldContinueSearch(traversedPath, rootPath, stopAtPackageJSON) {
if (rootPath) {
return Promise.resolve(traversedPath !== path.dirname(rootPath));
}
else if (stopAtPackageJSON) {
return fs.existsSync(path.join(traversedPath, 'package.json'));
}
else {
return true;
}
}
async function traverseAncestorDirectories(cwd, pathGenerator, rootPath, maxItems, stopAtPackageJSON) {
const paths = [];
let traversedPath = path.resolve(cwd);
while (await shouldContinueSearch(traversedPath, rootPath, stopAtPackageJSON)) {
const generatedPath = pathGenerator(traversedPath);
if (fs.existsSync(generatedPath)) {
paths.push(generatedPath);
}
const parentPath = path.dirname(traversedPath);
if (parentPath === traversedPath || (maxItems && paths.length >= maxItems)) {
break;
}
traversedPath = parentPath;
}
return paths;
}
/**
* Find all instances of a given module in node_modules subdirectories while traversing up
* ancestor directories.
*
* @param cwd the initial directory to traverse
* @param moduleName the Node module name (should work for scoped modules as well)
* @param rootPath the project's root path. If provided, the traversal will stop at this path.
*/
export async function searchForModule(cwd, moduleName, rootPath) {
const pathGenerator = (traversedPath) => path.join(traversedPath, 'node_modules', moduleName);
return traverseAncestorDirectories(cwd, pathGenerator, rootPath, undefined, true);
}
/**
* Find all instances of node_modules subdirectories while traversing up ancestor directories.
*
* @param cwd the initial directory to traverse
* @param rootPath the project's root path. If provided, the traversal will stop at this path.
*/
export async function searchForNodeModules(cwd, rootPath) {
const pathGenerator = (traversedPath) => path.join(traversedPath, 'node_modules');
return traverseAncestorDirectories(cwd, pathGenerator, rootPath, undefined, true);
}
/**
* Determine the root directory of a given project, by looking for a directory with an
* NPM or yarn lockfile or pnpm lockfile.
*
* @param cwd the initial directory to traverse
*/
export async function getProjectRootPath(cwd) {
for (const lockFilename of ['yarn.lock', 'package-lock.json', 'pnpm-lock.yaml']) {
const pathGenerator = (traversedPath) => path.join(traversedPath, lockFilename);
const lockPaths = await traverseAncestorDirectories(cwd, pathGenerator, undefined, 1);
if (lockPaths.length > 0) {
return path.dirname(lockPaths[0]);
}
}
return cwd;
}
//# sourceMappingURL=search-module.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"search-module.js","sourceRoot":"","sources":["../src/search-module.ts"],"names":[],"mappings":"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"}
+1
View File
@@ -0,0 +1 @@
export declare function downloadLinuxSysroot(electronVersion: string, targetArch: string): Promise<string>;
+39
View File
@@ -0,0 +1,39 @@
import crypto from 'node:crypto';
import debug from 'debug';
import fs from 'node:fs';
import path from 'node:path';
import { ELECTRON_GYP_DIR } from './constants.js';
import { fetchUrl } from './fetcher.js';
import { spawn } from '@malept/cross-spawn-promise';
const d = debug('electron-rebuild');
const sysrootArchAliases = {
x64: 'amd64',
ia32: 'i386',
};
const SYSROOT_BASE_URL = 'https://dev-cdn.electronjs.org/linux-sysroots';
export async function downloadLinuxSysroot(electronVersion, targetArch) {
d('fetching sysroot for Electron:', electronVersion);
const sysrootDir = path.resolve(ELECTRON_GYP_DIR, `${electronVersion}-sysroot`);
if (fs.existsSync(path.resolve(sysrootDir, 'lib')))
return sysrootDir;
await fs.promises.mkdir(sysrootDir, { recursive: true });
const linuxArch = sysrootArchAliases[targetArch] || targetArch;
const electronSysroots = JSON.parse(await fetchUrl(`https://raw.githubusercontent.com/electron/electron/v${electronVersion}/script/sysroots.json`, 'text'));
const { Sha1Sum: sha, Tarball: fileName } = electronSysroots[`sid_${linuxArch}`] || electronSysroots[`bullseye_${linuxArch}`];
const sysrootURL = `${SYSROOT_BASE_URL}/${sha}/${fileName}`;
const sysrootBuffer = await fetchUrl(sysrootURL, 'buffer');
const actualSha = crypto.createHash('SHA1').update(sysrootBuffer).digest('hex');
d('expected sha:', sha);
d('actual sha:', actualSha);
if (sha !== actualSha)
throw new Error(`Attempted to download the linux sysroot for ${electronVersion} but the SHA checksum did not match`);
d('writing sysroot to disk');
const tmpTarFile = path.resolve(ELECTRON_GYP_DIR, `${electronVersion}-${fileName}`);
if (fs.existsSync(tmpTarFile))
await fs.promises.rm(tmpTarFile, { recursive: true, force: true });
await fs.promises.writeFile(tmpTarFile, sysrootBuffer);
d('decompressing sysroot');
await spawn('tar', ['-xf', tmpTarFile, '-C', sysrootDir], { stdio: 'ignore' });
return sysrootDir;
}
//# sourceMappingURL=sysroot-fetcher.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"sysroot-fetcher.js","sourceRoot":"","sources":["../src/sysroot-fetcher.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAEpD,MAAM,CAAC,GAAG,KAAK,CAAC,kBAAkB,CAAC,CAAC;AAEpC,MAAM,kBAAkB,GAA2B;IACjD,GAAG,EAAE,OAAO;IACZ,IAAI,EAAE,MAAM;CACb,CAAC;AAEF,MAAM,gBAAgB,GAAG,+CAA+C,CAAC;AAEzE,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,eAAuB,EACvB,UAAkB;IAElB,CAAC,CAAC,gCAAgC,EAAE,eAAe,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,GAAG,eAAe,UAAU,CAAC,CAAC;IAChF,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAAE,OAAO,UAAU,CAAC;IACtE,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzD,MAAM,SAAS,GAAG,kBAAkB,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC;IAC/D,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CACjC,MAAM,QAAQ,CACZ,wDAAwD,eAAe,uBAAuB,EAC9F,MAAM,CACP,CACF,CAAC;IAEF,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,GACvC,gBAAgB,CAAC,OAAO,SAAS,EAAE,CAAC,IAAI,gBAAgB,CAAC,YAAY,SAAS,EAAE,CAAC,CAAC;IACpF,MAAM,UAAU,GAAG,GAAG,gBAAgB,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC5D,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAE3D,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAChF,CAAC,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;IACxB,CAAC,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IAC5B,IAAI,GAAG,KAAK,SAAS;QACnB,MAAM,IAAI,KAAK,CACb,+CAA+C,eAAe,qCAAqC,CACpG,CAAC;IAEJ,CAAC,CAAC,yBAAyB,CAAC,CAAC;IAC7B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,GAAG,eAAe,IAAI,QAAQ,EAAE,CAAC,CAAC;IACpF,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAClG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IAEvD,CAAC,CAAC,uBAAuB,CAAC,CAAC;IAC3B,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAE/E,OAAO,UAAU,CAAC;AACpB,CAAC"}
+27
View File
@@ -0,0 +1,27 @@
import { EventEmitter } from 'node:events';
export declare enum BuildType {
Debug = "Debug",
Release = "Release"
}
export type RebuildMode = 'sequential' | 'parallel';
export interface IRebuilder {
ABI: string;
arch: string;
buildPath: string;
buildType: BuildType;
cachePath: string;
debug: boolean;
disablePreGypCopy: boolean;
electronVersion: string;
force: boolean;
headerURL: string;
jobs?: number;
lifecycle: EventEmitter;
mode: RebuildMode;
msvsVersion?: string;
platform: NodeJS.Platform;
prebuildTagPrefix: string;
buildFromSource: boolean;
useCache: boolean;
useElectronClang: boolean;
}
+6
View File
@@ -0,0 +1,6 @@
export var BuildType;
(function (BuildType) {
BuildType["Debug"] = "Debug";
BuildType["Release"] = "Release";
})(BuildType || (BuildType = {}));
//# sourceMappingURL=types.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAN,IAAY,SAGX;AAHD,WAAY,SAAS;IACnB,4BAAe,CAAA;IACf,gCAAmB,CAAA;AACrB,CAAC,EAHW,SAAS,KAAT,SAAS,QAGpB"}
+87
View File
@@ -0,0 +1,87 @@
{
"name": "@electron/rebuild",
"version": "4.2.1",
"description": "Electron supporting package to rebuild native node modules against the currently installed electron",
"type": "module",
"exports": "./lib/main.js",
"typings": "lib/main.d.ts",
"scripts": {
"build": "tsc",
"build:docs": "typedoc src/main.ts",
"coverage": "yarn prewarm-headers && yarn spec --coverage",
"watch": "tsc -w",
"prepare": "husky && yarn build",
"lint": "oxlint && oxfmt --check",
"spec": "tsc && vitest run",
"test": "yarn prewarm-headers && yarn lint && yarn spec",
"prewarm-headers": "node-gyp install --ensure"
},
"bin": {
"electron-rebuild": "lib/cli.js"
},
"files": [
"lib"
],
"repository": {
"type": "git",
"url": "git+https://github.com/electron/rebuild.git"
},
"keywords": [
"electron"
],
"authors": [
"Ani Betts <anais@anaisbetts.org>",
"Electron Community"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/electron/rebuild/issues"
},
"homepage": "https://github.com/electron/rebuild",
"engines": {
"node": ">=22.12.0"
},
"publishConfig": {
"provenance": true
},
"dependencies": {
"@malept/cross-spawn-promise": "^2.0.0",
"debug": "^4.1.1",
"node-abi": "^4.2.0",
"node-api-version": "^0.2.1",
"node-gyp": "^12.2.0",
"read-binary-file-arch": "^1.0.6"
},
"devDependencies": {
"@tsconfig/node22": "^22.0.0",
"@types/debug": "^4.1.5",
"@types/node": "~22.12.0",
"@types/node-abi": "^3.0.0",
"@vitest/coverage-v8": "^5.0.1",
"electron": "^39.8.5",
"husky": "^9.1.7",
"lint-staged": "^17.4.1",
"oxfmt": "^0.42.0",
"oxlint": "^1.57.0",
"oxlint-tsgolint": "^0.18.1",
"typedoc": "~0.28.0",
"typescript": "^6.0.2",
"vite": "^8.0.16",
"vitest": "^5.0.1"
},
"lint-staged": {
"*.ts": [
"oxlint --fix",
"oxfmt --write"
]
},
"resolutions": {
"@typescript-eslint/typescript-estree/minimatch": "^9.0.7"
},
"packageManager": "yarn@4.10.3+sha512.c38cafb5c7bb273f3926d04e55e1d8c9dfa7d9c3ea1f36a4868fa028b9e5f72298f0b7f401ad5eb921749eb012eb1c3bb74bf7503df3ee43fd600d14a018266f",
"dependenciesMeta": {
"electron": {
"built": true
}
}
}