Repository: electron-userland/electron-forge
Pull request #392 (2017-12-21 00:23:32)

feat(rebuilder): allow configuration of electron-rebuild
* [x] I have read the [contribution documentation](https://github.com/electron-userland/electron-forge/blob/master/CONTRIBUTING.md) for this project.
* [x] I agree to follow the [code of conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project follows, as appropriate.
* [x] The changes are appropriately documented (if applicable).
* [x] The changes have sufficient test coverage (if applicable).
* [x] The testsuite passes successfully on my local machine (if applicable).

**Summarize your changes:**
Put an electronRebuildConfig in the forge config and pass it through to electron-rebuild.

MarshallOfSound: Seems OK to me 👍 

Patch:
diff --git a/README.md b/README.md
index d3ba824ee..c14aa0f81 100644
--- a/README.md
+++ b/README.md
@@ -155,6 +155,7 @@ config object:
     "linux": ["deb", "rpm", "flatpak"] // An array of linux make targets
   },
   "electronPackagerConfig": {},
+  "electronRebuildConfig": {},
   "electronWinstallerConfig": {},
   "electronInstallerDMG": {},
   "electronInstallerFlatpak": {},
@@ -188,6 +189,13 @@ You can set `electronPackagerConfig` with any of the options from
 * `platform` (use the `--platform` Forge command line argument instead, so it's available to all of Forge)
 * `quiet`
 
+You can set `electronRebuildConfig` with any of the options from
+[Electron Rebuild](https://github.com/electron/electron-rebuild#how-can-i-integrate-this-into-grunt--gulp--whatever), except:
+
+* `electronVersion`/`--version` (uses the exact version specified for `electron-prebuilt-compile` in your `devDependencies`)
+* `arch`/`--arch` (use the `--arch` Forge command line argument instead, so it's available to all of Forge)
+* `buildPath`/`--module-dir` (uses your project's `node_modules`)
+
 **NOTE:** You can also set your `forge` config property of your package.json to point to a JS file that exports the config object:
 
 ```js
diff --git a/src/api/package.js b/src/api/package.js
index 4fa0dea02..d6b68832b 100644
--- a/src/api/package.js
+++ b/src/api/package.js
@@ -89,7 +89,7 @@ export default async (providedOptions = {}) => {
   const pruneEnabled = !('prune' in forgeConfig.electronPackagerConfig) || forgeConfig.electronPackagerConfig.prune;
 
   const rebuildHookFn = async (buildPath, electronVersion, pPlatform, pArch, done) => {
-    await rebuildHook(buildPath, electronVersion, pPlatform, pArch);
+    await rebuildHook(buildPath, electronVersion, pPlatform, pArch, forgeConfig.electronRebuildConfig);
     packagerSpinner = ora('Packaging Application').start();
     done();
   };
diff --git a/src/api/start.js b/src/api/start.js
index e9305c4f6..3915f4f4d 100644
--- a/src/api/start.js
+++ b/src/api/start.js
@@ -50,7 +50,9 @@ export default async (providedOptions = {}) => {
     throw `Please set your application's 'version' in '${dir}/package.json'.`;
   }
 
-  await rebuild(dir, packageJSON.devDependencies['electron-prebuilt-compile'], process.platform, process.arch);
+  const forgeConfig = await getForgeConfig(dir);
+
+  await rebuild(dir, packageJSON.devDependencies['electron-prebuilt-compile'], process.platform, process.arch, forgeConfig.electronRebuildConfig);
 
   const spawnOpts = {
     cwd: dir,
@@ -73,7 +75,6 @@ export default async (providedOptions = {}) => {
 
   let spawned;
 
-  const forgeConfig = await getForgeConfig(dir);
   await runHook(forgeConfig, 'generateAssets');
 
   await asyncOra('Launching Application', async () => {
diff --git a/src/util/forge-config.js b/src/util/forge-config.js
index 53abb3d6b..74c998f52 100644
--- a/src/util/forge-config.js
+++ b/src/util/forge-config.js
@@ -68,6 +68,7 @@ export default async (dir) => {
     make_targets: {},
     publish_targets: {},
     electronPackagerConfig: {},
+    electronRebuildConfig: {},
     electronWinstallerConfig: {},
     electronInstallerDebian: {},
     electronInstallerDMG: {},
diff --git a/src/util/rebuild.js b/src/util/rebuild.js
index c750bf670..4d8c29f27 100644
--- a/src/util/rebuild.js
+++ b/src/util/rebuild.js
@@ -2,9 +2,13 @@ import rebuild from 'electron-rebuild';
 
 import asyncOra from '../util/ora-handler';
 
-export default async (buildPath, electronVersion, platform, arch) => {
+export default async (buildPath, electronVersion, platform, arch, config = {}) => {
   await asyncOra('Preparing native dependencies', async (rebuildSpinner) => {
-    const rebuilder = rebuild({ buildPath, electronVersion, arch });
+    const rebuilder = rebuild(Object.assign({}, config, {
+      buildPath,
+      electronVersion,
+      arch,
+    }));
     const { lifecycle } = rebuilder;
 
     let found = 0;


Test patch:
diff --git a/test/fast/forge-config_spec.js b/test/fast/forge-config_spec.js
index 1ced60fa4..939a99ba1 100644
--- a/test/fast/forge-config_spec.js
+++ b/test/fast/forge-config_spec.js
@@ -12,6 +12,7 @@ const defaults = {
   },
   electronInstallerDMG: {},
   electronPackagerConfig: {},
+  electronRebuildConfig: {},
   electronWinstallerConfig: {},
   electronInstallerDebian: {},
   electronInstallerRedhat: {},
diff --git a/test/slow/rebuild_spec_slow.js b/test/slow/rebuild_spec_slow.js
index d69c7cac2..b679af153 100644
--- a/test/slow/rebuild_spec_slow.js
+++ b/test/slow/rebuild_spec_slow.js
@@ -10,7 +10,7 @@ import { yarnOrNpmSpawn, hasYarn } from '../../src/util/yarn-or-npm';
 describe('rebuilder', () => {
   const testModulePath = path.resolve(os.tmpdir(), 'electron-forge-rebuild-test');
 
-  before(async () => {
+  async function setupProject() {
     await fs.remove(testModulePath);
     await fs.mkdirs(testModulePath);
     await fs.writeFile(path.resolve(testModulePath, 'package.json'), await fs.readFile(path.resolve(__dirname, '../fixture/native_app/package.json'), 'utf8'));
@@ -18,35 +18,59 @@ describe('rebuilder', () => {
       cwd: testModulePath,
       stdio: process.platform === 'win32' ? 'inherit' : 'pipe',
     });
-  });
+  }
 
-  before(async () => {
-    await rebuild(testModulePath, '1.4.12', process.platform, process.arch);
-  });
+  async function doRebuild(config) {
+    await rebuild(testModulePath, '1.4.12', process.platform, process.arch, config);
+  }
 
-  it('should have rebuilt top level prod dependencies', async () => {
-    const forgeMeta = path.resolve(testModulePath, 'node_modules', 'ref', 'build', 'Release', '.forge-meta');
-    expect(await fs.pathExists(forgeMeta), 'ref build meta should exist').to.equal(true);
-  });
+  describe('no config', () => {
+    before(async () => {
+      await setupProject();
+      await doRebuild();
+    });
 
-  it('should have rebuilt children of top level prod dependencies', async () => {
-    const forgeMeta = path.resolve(testModulePath, 'node_modules', 'microtime', 'build', 'Release', '.forge-meta');
-    expect(await fs.pathExists(forgeMeta), 'microtime build meta should exist').to.equal(true);
-  });
+    it('should have rebuilt top level prod dependencies', async () => {
+      const forgeMeta = path.resolve(testModulePath, 'node_modules', 'ref', 'build', 'Release', '.forge-meta');
+      expect(await fs.pathExists(forgeMeta), 'ref build meta should exist').to.equal(true);
+    });
 
-  it('should have rebuilt children of scoped top level prod dependencies', async () => {
-    const forgeMeta = path.resolve(testModulePath, 'node_modules', '@newrelic/native-metrics', 'build', 'Release', '.forge-meta');
-    expect(await fs.pathExists(forgeMeta), '@newrelic/native-metrics build meta should exist').to.equal(true);
-  });
+    it('should have rebuilt children of top level prod dependencies', async () => {
+      const forgeMeta = path.resolve(testModulePath, 'node_modules', 'microtime', 'build', 'Release', '.forge-meta');
+      expect(await fs.pathExists(forgeMeta), 'microtime build meta should exist').to.equal(true);
+    });
+
+    it('should have rebuilt children of scoped top level prod dependencies', async () => {
+      const forgeMeta = path.resolve(testModulePath, 'node_modules', '@newrelic/native-metrics', 'build', 'Release', '.forge-meta');
+      expect(await fs.pathExists(forgeMeta), '@newrelic/native-metrics build meta should exist').to.equal(true);
+    });
+
+    it('should have rebuilt top level optional dependencies', async () => {
+      const forgeMeta = path.resolve(testModulePath, 'node_modules', 'zipfile', 'build', 'Release', '.forge-meta');
+      expect(await fs.pathExists(forgeMeta), 'zipfile build meta should exist').to.equal(true);
+    });
 
-  it('should have rebuilt top level optional dependencies', async () => {
-    const forgeMeta = path.resolve(testModulePath, 'node_modules', 'zipfile', 'build', 'Release', '.forge-meta');
-    expect(await fs.pathExists(forgeMeta), 'zipfile build meta should exist').to.equal(true);
+    it('should not have rebuilt top level devDependencies', async () => {
+      const forgeMeta = path.resolve(testModulePath, 'node_modules', 'ffi', 'build', 'Release', '.forge-meta');
+      expect(await fs.pathExists(forgeMeta), 'ffi build meta should not exist').to.equal(false);
+    });
   });
 
-  it('should not have rebuilt top level devDependencies', async () => {
-    const forgeMeta = path.resolve(testModulePath, 'node_modules', 'ffi', 'build', 'Release', '.forge-meta');
-    expect(await fs.pathExists(forgeMeta), 'ffi build meta should not exist').to.equal(false);
+  describe('with config', () => {
+    before(async () => {
+      await setupProject();
+      await doRebuild({ onlyModules: ['ref'] });
+    });
+
+    it('should have rebuilt module in onlyModules', async () => {
+      const forgeMeta = path.resolve(testModulePath, 'node_modules', 'ref', 'build', 'Release', '.forge-meta');
+      expect(await fs.pathExists(forgeMeta), 'ref build meta should exist').to.equal(true);
+    });
+
+    it('should not have rebuilt module not in onlyModules', async () => {
+      const forgeMeta = path.resolve(testModulePath, 'node_modules', 'zipfile', 'build', 'Release', '.forge-meta');
+      expect(await fs.pathExists(forgeMeta), 'zipfile build meta should not exist').to.equal(false);
+    });
   });
 
   after(async () => {