Skip to content

Commit 6532e9f

Browse files
committed
feat: install-app-deps rebuilds native deps for any project structure
1 parent 1bc8d57 commit 6532e9f

File tree

6 files changed

+28
-28
lines changed

6 files changed

+28
-28
lines changed

.idea/dictionaries/develar.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@ For an app that will be shipped to production, you should sign your application.
5656
```
5757
Then you can run `npm run dist` (to package in a distributable format (e.g. dmg, windows installer, deb package)) or `npm run pack` (only generates the package directory without really packaging it. This is useful for testing purposes).
5858

59-
If you use the [two-package.json project structure](#two-packagejson-structure), you'll only have your `devDependencies` in your development `package.json` and your `dependencies` in your app `package.json`. To ensure your dependencies are always updated based on both files, simply add `"postinstall": "install-app-deps"` to your development `package.json`. This will basically automatically trigger an `npm install` within your app directory so you don't have to do this work everytime you install/update your dependencies.
60-
59+
To ensure your native dependencies are always matched electron version, simply add `"postinstall": "install-app-deps"` to your `package.json`. [Do not use Yarn.](https://github.com/yarnpkg/yarn/issues/1749)
6160

6261
5. If you have native addons of your own that are part of the application (not as a dependency), add `"nodeGypRebuild": true` to the `build` section of your development `package.json`.
6362
:bulb: Don't [use](https://github.com/electron-userland/electron-builder/issues/683#issuecomment-241214075) [npm](http://electron.atom.io/docs/tutorial/using-native-node-modules/#using-npm) (neither `.npmrc`) for configuring electron headers. Use [node-gyp-rebuild](https://github.com/electron-userland/electron-builder/issues/683#issuecomment-241488783) bin instead.

docs/Two package.json Structure.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@ Why?
1313
1. Native npm modules (those written in C, not JavaScript) need to be compiled and here we have two different compilation targets for them. Those used within the application need to be compiled against the electron runtime and all `devDependencies` need to be compiled against your local node.js environment. Thanks to the two `package.json` structure, this is trivial (see [#39](https://github.com/electron-userland/electron-builder/issues/39)).
1414
2. No need to specify which [files](https://github.com/electron-userland/electron-builder/wiki/Options#BuildMetadata-files) to include in the app (because development files reside outside the `app` directory).
1515

16-
Please see [Loading App Dependencies Manually](https://github.com/electron-userland/electron-builder/wiki/Loading-App-Dependencies-Manually) and [#379](https://github.com/electron-userland/electron-builder/issues/379#issuecomment-218503881).
16+
Please see [Loading App Dependencies Manually](https://github.com/electron-userland/electron-builder/wiki/Loading-App-Dependencies-Manually) and [#379](https://github.com/electron-userland/electron-builder/issues/379#issuecomment-218503881).
17+
18+
If you use the two-package.json project structure, you'll only have your `devDependencies` in your development `package.json` and your `dependencies` in your app `package.json`. To ensure your dependencies are always updated based on both files, simply add `"postinstall": "install-app-deps"` to your development `package.json`. This will basically automatically trigger an `npm install` within your app directory so you don't have to do this work every time you install/update your dependencies.

src/install-app-deps.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import BluebirdPromise from "bluebird-lst-c"
77
import { DevMetadata } from "./metadata"
88
import yargs from "yargs"
99
import { readPackageJson } from "./util/readPackageJson"
10-
import { installDependencies, computeExtraArgs } from "./yarn"
10+
import { installOrRebuild } from "./yarn"
1111

1212
const args: any = yargs
1313
.option("arch", {
@@ -24,11 +24,8 @@ async function main() {
2424
getElectronVersion(devMetadata, devPackageFile)
2525
])
2626

27-
if (results[0] === projectDir) {
28-
throw new Error("install-app-deps is only useful for two package.json structure")
29-
}
30-
31-
await installDependencies(results[0], results[1], args.arch, computeExtraArgs(devMetadata.build))
27+
// if two package.json — force full install (user wants to install/update app deps in addition to dev)
28+
await installOrRebuild(devMetadata.build, results[0], results[1], args.arch, results[0] !== projectDir)
3229
}
3330

3431
main()

src/packager.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as path from "path"
2-
import { computeDefaultAppDirectory, getElectronVersion, use, exec, isEmptyOrSpaces, exists } from "./util/util"
2+
import { computeDefaultAppDirectory, getElectronVersion, use, exec, isEmptyOrSpaces } from "./util/util"
33
import { all, executeFinally } from "./util/promise"
44
import { EventEmitter } from "events"
55
import BluebirdPromise from "bluebird-lst-c"
@@ -17,7 +17,7 @@ import { createTargets } from "./targets/targetFactory"
1717
import { readPackageJson } from "./util/readPackageJson"
1818
import { TmpDir } from "./util/tmp"
1919
import { BuildOptions } from "./builder"
20-
import { getGypEnv, installDependencies, rebuild, computeExtraArgs } from "./yarn"
20+
import { getGypEnv, installOrRebuild } from "./yarn"
2121

2222
function addHandler(emitter: EventEmitter, event: string, handler: Function) {
2323
emitter.on(event, handler)
@@ -229,29 +229,24 @@ export class Packager implements BuildInfo {
229229
}
230230

231231
private async installAppDependencies(platform: Platform, arch: Arch): Promise<any> {
232-
if (this.devMetadata.build.nodeGypRebuild === true) {
232+
const options = this.devMetadata.build
233+
if (options.nodeGypRebuild === true) {
233234
log(`Executing node-gyp rebuild for arch ${Arch[arch]}`)
234235
await exec(process.platform === "win32" ? "node-gyp.cmd" : "node-gyp", ["rebuild"], {
235236
env: getGypEnv(this.electronVersion, Arch[arch]),
236237
})
237238
}
238239

239-
if (this.devMetadata.build.npmRebuild === false) {
240+
if (options.npmRebuild === false) {
240241
log("Skip app dependencies rebuild because npmRebuild is set to false")
241242
return
242243
}
243244

244-
if (this.devMetadata.build.npmSkipBuildFromSource !== true && platform.nodeName !== process.platform) {
245+
if (options.npmSkipBuildFromSource !== true && platform.nodeName !== process.platform) {
245246
log("Skip app dependencies rebuild because platform is different")
246247
}
247248
else {
248-
const args = computeExtraArgs(this.devMetadata.build)
249-
if (await exists(path.join(this.appDir, "node_modules"))) {
250-
await rebuild(this.appDir, this.electronVersion, Arch[arch], args)
251-
}
252-
else if (this.isTwoPackageJsonProjectLayoutUsed) {
253-
await installDependencies(this.appDir, this.electronVersion, Arch[arch], args)
254-
}
249+
await installOrRebuild(options, this.appDir, this.electronVersion, Arch[arch])
255250
}
256251
}
257252
}

src/yarn.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
import BluebirdPromise from "bluebird-lst-c"
22
import * as path from "path"
3-
import { task, log } from "./util/log"
3+
import { log } from "./util/log"
44
import { homedir } from "os"
55
import { spawn, exists, asArray } from "./util/util"
66
import { BuildMetadata } from "./metadata"
77

8-
export function installDependencies(appDir: string, electronVersion: string, arch: string = process.arch, additionalArgs: Array<string>): Promise<any> {
9-
return task(`Installing app dependencies for arch ${arch} to ${appDir}`, spawnNpmProduction(appDir, getGypEnv(electronVersion, arch), additionalArgs))
8+
export async function installOrRebuild(options: BuildMetadata, appDir: string, electronVersion: string, arch: string, forceInstall: boolean = false) {
9+
const args = computeExtraArgs(options)
10+
if (forceInstall || !(await exists(path.join(appDir, "node_modules")))) {
11+
await installDependencies(appDir, electronVersion, arch, args)
12+
}
13+
else {
14+
await rebuild(appDir, electronVersion, arch, args)
15+
}
1016
}
1117

1218
export function getGypEnv(electronVersion: string, arch: string): any {
@@ -21,15 +27,16 @@ export function getGypEnv(electronVersion: string, arch: string): any {
2127
})
2228
}
2329

24-
export function computeExtraArgs(options: BuildMetadata) {
30+
function computeExtraArgs(options: BuildMetadata) {
2531
const args = asArray(options.npmArgs)
2632
if (options.npmSkipBuildFromSource !== true) {
2733
args.push("--build-from-source")
2834
}
2935
return args
3036
}
3137

32-
function spawnNpmProduction(appDir: string, env: any, additionalArgs: Array<string>): Promise<any> {
38+
export function installDependencies(appDir: string, electronVersion: string, arch: string = process.arch, additionalArgs: Array<string>): Promise<any> {
39+
log(`Installing app dependencies for arch ${arch} to ${appDir}`)
3340
let npmExecPath = process.env.npm_execpath || process.env.NPM_CLI_JS
3441
const npmExecArgs = ["install", "--production"]
3542

@@ -55,10 +62,9 @@ function spawnNpmProduction(appDir: string, env: any, additionalArgs: Array<stri
5562
}
5663
}
5764

58-
console.log("AAA " + npmExecPath + " " + npmExecArgs.join(" "))
5965
return spawn(npmExecPath, npmExecArgs, {
6066
cwd: appDir,
61-
env: env
67+
env: getGypEnv(electronVersion, arch),
6268
})
6369
}
6470

0 commit comments

Comments
 (0)