nw-builder 4.4.0 → 4.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +2 -1
- package/README.md +204 -3
- package/package.json +19 -17
- package/src/build.js +318 -0
- package/src/{get_nwjs.js → get.js} +169 -7
- package/src/index.d.ts +173 -21
- package/src/index.js +51 -23
- package/src/run.js +1 -1
- package/src/util.js +54 -1
- package/src/bld/build.js +0 -85
- package/src/bld/linuxCfg.js +0 -85
- package/src/bld/osxCfg.js +0 -94
- package/src/bld/winCfg.js +0 -81
- package/src/get_ffmpeg.js +0 -134
- package/src/util/ffmpeg.js +0 -48
package/LICENSE
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
The MIT License (MIT)
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2021-2023 NW.js Utilities
|
|
4
|
+
Copyright (c) 2014-2021 Steffen Müller
|
|
4
5
|
|
|
5
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
7
|
this software and associated documentation files (the "Software"), to deal in
|
package/README.md
CHANGED
|
@@ -9,10 +9,10 @@ For version 3, please go to the [corresponding branch](https://github.com/nwutil
|
|
|
9
9
|
|
|
10
10
|
## Major Features
|
|
11
11
|
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
- Integrate [`nwjs-ffmpeg-prebuilt`](https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt)
|
|
12
|
+
- Get, run or build applications.
|
|
13
|
+
- Integrate [FFmpeg community builds](https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt)
|
|
15
14
|
- Configure executable fields and icons
|
|
15
|
+
- Support downloading from mirrors
|
|
16
16
|
|
|
17
17
|
Check out the [documentation](https://nwutils.io/nw-builder/) if you wish to give `nw-builder` a try.
|
|
18
18
|
|
|
@@ -22,3 +22,204 @@ Check out the [documentation](https://nwutils.io/nw-builder/) if you wish to giv
|
|
|
22
22
|
|
|
23
23
|
- [nw-builder-platforms](https://github.com/naviapps/nw-builder-platforms) - Fork of this repo with platform specific build options
|
|
24
24
|
- [nwjs-builder-phoenix](https://github.com/evshiron/nwjs-builder-phoenix) - Previously the most used build tool, however it is no longer maintained
|
|
25
|
+
|
|
26
|
+
## Migration Guide (v3 -> v4)
|
|
27
|
+
|
|
28
|
+
> We are working on making the migration process smoother. If you encounter any issues with the current guide, please open an issue or start a discussion.
|
|
29
|
+
|
|
30
|
+
### Update `nw-builder`
|
|
31
|
+
|
|
32
|
+
With npm:
|
|
33
|
+
|
|
34
|
+
```shell
|
|
35
|
+
npm update nw-builder@latest
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
With yarn:
|
|
39
|
+
|
|
40
|
+
```shell
|
|
41
|
+
yarn upgrade nw-builder@latest
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
With pnpm:
|
|
45
|
+
|
|
46
|
+
```shell
|
|
47
|
+
pnpm update nw-builder@latest
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Update options
|
|
51
|
+
|
|
52
|
+
Let's take an example of v3 code and migrate it to v4.
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
const NwBuilder = require("nw-builder");
|
|
56
|
+
|
|
57
|
+
const nw = new NwBuilder({
|
|
58
|
+
files: ["./nwapp/**/*", "./other/**/*.js"],
|
|
59
|
+
version: "latest",
|
|
60
|
+
flavor: "normal",
|
|
61
|
+
platforms: ["win32", "win64", "osx32", "osx64", "linux32", "linux64"],
|
|
62
|
+
cacheDir: "./cache",
|
|
63
|
+
buildDir: "./build",
|
|
64
|
+
buildType: "versioned",
|
|
65
|
+
forceDownload: true,
|
|
66
|
+
appName: "nwdemo",
|
|
67
|
+
appVersion: "0.1.0",
|
|
68
|
+
argv: "--nw-stderr-logging",
|
|
69
|
+
macCredits: "./nwapp/credits.html",
|
|
70
|
+
macIcns: "./nwapp/mac.icns",
|
|
71
|
+
macPlist: { ... },
|
|
72
|
+
winVersionString: { ... },
|
|
73
|
+
winIco: "./nwapp/win.ico",
|
|
74
|
+
zip: true,
|
|
75
|
+
macZip: false,
|
|
76
|
+
mergeZip: false,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
nw.build();
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Update the import path
|
|
83
|
+
|
|
84
|
+
```diff
|
|
85
|
+
-const NwBuilder = require("nw-builder");
|
|
86
|
+
+const nwbuild = require("nw-builder");
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Replace the `NwBuilder` initialization with a function
|
|
90
|
+
|
|
91
|
+
```diff
|
|
92
|
+
-const nw = new NwBuilder({
|
|
93
|
+
+await nwbuild({
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The `files` property has been renamed to `srcDir`.
|
|
97
|
+
|
|
98
|
+
```diff
|
|
99
|
+
- files: ["./nwapp/**/*", "./other/**/*.js"],
|
|
100
|
+
+ srcDir: "./nwapp/**/* ./other/**/*.js",
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Add the `mode` option and remove the now redundant `nw.build` function call. The `build` call is made by `nwbuild` internally.
|
|
104
|
+
|
|
105
|
+
```diff
|
|
106
|
+
+ mode: "build",
|
|
107
|
+
|
|
108
|
+
-nw.build();
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The `platforms` option has been removed and replaced with `platform` and `arch`. Notice that one `nwbuild` function call now creates one build for one platform and one arch only.
|
|
112
|
+
|
|
113
|
+
```diff
|
|
114
|
+
- platforms: ["win32", "win64", "osx32", "osx64", "linux32", "linux64"],
|
|
115
|
+
+ platform: "linux", // "osx" for MacOS "win", for Windows
|
|
116
|
+
+ arch: "x64", // "ia32" for 32 bit or "arm64" for arm based 65 bit architectures
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The `buildDir` option has been rename to `outDir`.
|
|
120
|
+
|
|
121
|
+
```diff
|
|
122
|
+
- buildDir: "./build",
|
|
123
|
+
+ outDir: "./build",
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The `buildType` option has been removed.
|
|
127
|
+
|
|
128
|
+
```diff
|
|
129
|
+
- buildType: "versioned",
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The `forceDownload` option has been changed to `cache`.
|
|
133
|
+
|
|
134
|
+
```diff
|
|
135
|
+
- forceDownload: true,
|
|
136
|
+
+ cache: false,
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The `appName` option has been changed to `app.name`.
|
|
140
|
+
|
|
141
|
+
```diff
|
|
142
|
+
- appName: "nwdemo",
|
|
143
|
+
+ app: { name: "nwdemo" },
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The `appVersion` option has been changed to `app.version`.
|
|
147
|
+
|
|
148
|
+
```diff
|
|
149
|
+
- appVersion: "0.1.0",
|
|
150
|
+
+ app: { version: "0.1.0" },
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The `macCredit` option has been removed.
|
|
154
|
+
|
|
155
|
+
```diff
|
|
156
|
+
- macCredits: "./nwapp/credits.html",
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The `macIcns` option has been replaced with `icon`.
|
|
160
|
+
|
|
161
|
+
```diff
|
|
162
|
+
- macIcns: "./nwapp/mac.icns",
|
|
163
|
+
+ icon: "./nwapp/mac.icns",
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The `macPlist` option has been replaced by `app.*` options. Consult the [documentation](https://nwutils.io/nw-builder/mode-build.html#osxrc-object) for valid properties.
|
|
167
|
+
|
|
168
|
+
```diff
|
|
169
|
+
- macPlist: { ... },
|
|
170
|
+
+ app: { ... },
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
The `winVersionString` option has been replaced with `app`. Consult the [documentation](https://nwutils.io/nw-builder/mode-build.html#winrc-object) for valid properties.
|
|
174
|
+
|
|
175
|
+
```diff
|
|
176
|
+
- winVersionString: {
|
|
177
|
+
- 'CompanyName': 'Some Company',
|
|
178
|
+
- 'FileDescription': 'Process Name',
|
|
179
|
+
- 'ProductName': 'Some Product',
|
|
180
|
+
- 'LegalCopyright': 'Copyright 2017',
|
|
181
|
+
- }
|
|
182
|
+
+ app: {
|
|
183
|
+
+ company: "Some Company",
|
|
184
|
+
+ fileDescription: "Process Name",
|
|
185
|
+
+ productName: "Some Product",
|
|
186
|
+
+ legalCopyright: "Copyright (c) 2023",
|
|
187
|
+
+ }
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The `winIco` option has been replaced by `app.icon`.
|
|
191
|
+
|
|
192
|
+
```diff
|
|
193
|
+
- winIco: "./nwapp/win.ico",
|
|
194
|
+
+ app: { icon: "./nwapp/win.ico" },
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The `macZip` option has been removed.
|
|
198
|
+
|
|
199
|
+
```diff
|
|
200
|
+
- macZip: false,
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The `mergeZip` option has been removed.
|
|
204
|
+
|
|
205
|
+
```diff
|
|
206
|
+
- mergeZip: false,
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The final code should look like this.
|
|
210
|
+
|
|
211
|
+
```javascript
|
|
212
|
+
const { nwbuild } = require("nw-builder");
|
|
213
|
+
|
|
214
|
+
await nwbuild({
|
|
215
|
+
srcDir: "./nwapp/**/* ./other/**/*.js",
|
|
216
|
+
mode: "build",
|
|
217
|
+
version: "latest",
|
|
218
|
+
flavor: "normal",
|
|
219
|
+
platform: "linux",
|
|
220
|
+
arch: "x64",
|
|
221
|
+
outDir: "./build",
|
|
222
|
+
cache: false,
|
|
223
|
+
app: { ... },
|
|
224
|
+
});
|
|
225
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nw-builder",
|
|
3
|
-
"version": "4.4.
|
|
3
|
+
"version": "4.4.2",
|
|
4
4
|
"description": "Build NW.js desktop applications for MacOS, Windows and Linux.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"NW.js",
|
|
@@ -41,35 +41,37 @@
|
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"ci:fmt": "prettier --check \"./**/*.{css,html,js,json,md,yml}\"",
|
|
44
|
-
"ci:lnt": "eslint --config
|
|
44
|
+
"ci:lnt": "eslint --config=.github/eslint.config.cjs .github src test",
|
|
45
45
|
"fmt": "prettier --write \"./**/*.{css,html,js,json,md,yml}\"",
|
|
46
|
-
"lnt": "eslint --config
|
|
47
|
-
"doc:dev": "concurrently --kill-others \"node
|
|
48
|
-
"doc:bld": "vitepress build doc",
|
|
46
|
+
"lnt": "eslint --config=.github/eslint.config.cjs --fix src test",
|
|
47
|
+
"doc:dev": "concurrently --kill-others \"node .github/fswatch.config.js\" \"vitepress dev doc\"",
|
|
48
|
+
"doc:bld": "node .github/jsdoc.config.cjs && vitepress build doc",
|
|
49
49
|
"test:unit": "node --test test/unit/index.js",
|
|
50
50
|
"test:e2e": "node --test test/e2e/index.js",
|
|
51
|
-
"
|
|
52
|
-
"test:cli": "cd test/fixture && nwbuild --platform win --arch x64 --outDir out --no-glob app"
|
|
51
|
+
"demo": "cd test/fixture && node demo.js"
|
|
53
52
|
},
|
|
54
53
|
"devDependencies": {
|
|
55
|
-
"concurrently": "^8.2.
|
|
56
|
-
"eslint": "^8.
|
|
57
|
-
"eslint-config-tjw-jsdoc": "^1.0.
|
|
54
|
+
"concurrently": "^8.2.1",
|
|
55
|
+
"eslint": "^8.51.0",
|
|
56
|
+
"eslint-config-tjw-jsdoc": "^1.0.4",
|
|
58
57
|
"gh-pages": "^6.0.0",
|
|
59
58
|
"jsdoc": "^4.0.2",
|
|
60
59
|
"jsdoc-to-markdown": "^8.0.0",
|
|
61
|
-
"prettier": "^3.0.
|
|
62
|
-
"selenium-webdriver": "^4.
|
|
63
|
-
"vitepress": "^1.0.0-
|
|
60
|
+
"prettier": "^3.0.3",
|
|
61
|
+
"selenium-webdriver": "^4.14.0",
|
|
62
|
+
"vitepress": "^1.0.0-rc.21"
|
|
64
63
|
},
|
|
65
64
|
"dependencies": {
|
|
66
65
|
"cli-progress": "^3.12.0",
|
|
67
|
-
"compressing": "^1.
|
|
68
|
-
"glob": "^10.3.
|
|
66
|
+
"compressing": "^1.10.0",
|
|
67
|
+
"glob": "^10.3.10",
|
|
69
68
|
"plist": "^3.1.0",
|
|
70
69
|
"rcedit": "^4.0.0",
|
|
71
|
-
"winston": "^3.
|
|
70
|
+
"winston": "^3.11.0",
|
|
72
71
|
"yargs": "^17.7.2"
|
|
73
72
|
},
|
|
74
|
-
"packageManager": "npm@9.8.1"
|
|
73
|
+
"packageManager": "npm@9.8.1",
|
|
74
|
+
"engines": {
|
|
75
|
+
"node": "^16.20.1 || ^18.18.2 || >= 20.8.1"
|
|
76
|
+
}
|
|
75
77
|
}
|
package/src/build.js
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { platform as PLATFORM } from "node:process";
|
|
3
|
+
import {
|
|
4
|
+
cp,
|
|
5
|
+
copyFile,
|
|
6
|
+
rename,
|
|
7
|
+
readFile,
|
|
8
|
+
rm,
|
|
9
|
+
writeFile,
|
|
10
|
+
} from "node:fs/promises";
|
|
11
|
+
|
|
12
|
+
import compressing from "compressing";
|
|
13
|
+
import rcedit from "rcedit";
|
|
14
|
+
import plist from "plist";
|
|
15
|
+
|
|
16
|
+
import { log } from "./log.js";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* References:
|
|
20
|
+
* https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html
|
|
21
|
+
*
|
|
22
|
+
* @typedef {object} LinuxRc Linux configuration options
|
|
23
|
+
* @property {string} name Name of the application
|
|
24
|
+
* @property {string} genericName Generic name of the application
|
|
25
|
+
* @property {boolean} noDisplay If true the application is not displayed
|
|
26
|
+
* @property {string} comment Tooltip for the entry, for example "View sites on the Internet".
|
|
27
|
+
* @property {string} icon Icon to display in file manager, menus, etc.
|
|
28
|
+
* @property {boolean} hidden TBD
|
|
29
|
+
* @property {string[]} onlyShowIn A list of strings identifying the desktop environments that should (/not) display a given desktop entry
|
|
30
|
+
* @property {string[]} notShowIn A list of strings identifying the desktop environments that should (/not) display a given desktop entry
|
|
31
|
+
* @property {boolean} dBusActivatable A boolean value specifying if D-Bus activation is supported for this application
|
|
32
|
+
* @property {string} tryExec Path to an executable file on disk used to determine if the program is actually installed
|
|
33
|
+
* @property {string} exec Program to execute, possibly with arguments.
|
|
34
|
+
* @property {string} path If entry is of type Application, the working directory to run the program in.
|
|
35
|
+
* @property {boolean} terminal Whether the program runs in a terminal window.
|
|
36
|
+
* @property {string[]} actions Identifiers for application actions.
|
|
37
|
+
* @property {string[]} mimeType The MIME type(s) supported by this application.
|
|
38
|
+
* @property {string[]} categories Categories in which the entry should be shown in a menu
|
|
39
|
+
* @property {string[]} implements A list of interfaces that this application implements.
|
|
40
|
+
* @property {string[]} keywords A list of strings which may be used in addition to other metadata to describe this entry.
|
|
41
|
+
* @property {boolean} startupNotify If true, it is KNOWN that the application will send a "remove" message when started with the DESKTOP_STARTUP_ID environment variable set. If false, it is KNOWN that the application does not work with startup notification at all.
|
|
42
|
+
* @property {string} startupWMClass If specified, it is known that the application will map at least one window with the given string as its WM class or WM name hin
|
|
43
|
+
* @property {boolean} prefersNonDefaultGPU If true, the application prefers to be run on a more powerful discrete GPU if available.
|
|
44
|
+
* @property {string} singleMainWindow If true, the application has a single main window, and does not support having an additional one opened.
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* References:
|
|
49
|
+
* https://developer.apple.com/documentation/bundleresources/information_property_list
|
|
50
|
+
*
|
|
51
|
+
* @typedef {object} OsxRc OSX resource configuration options
|
|
52
|
+
* @property {string} name The name of the application
|
|
53
|
+
* @property {string} icon The path to the icon file. It should be a .icns file.
|
|
54
|
+
* @property {string} LSApplicationCategoryType The category that best describes your app for the App Store.
|
|
55
|
+
* @property {string} CFBundleIdentifier A unique identifier for a bundle usually in reverse DNS format.
|
|
56
|
+
* @property {string} CFBundleName A user-visible short name for the bundle.
|
|
57
|
+
* @property {string} CFBundleDisplayName The user-visible name for the bundle.
|
|
58
|
+
* @property {string} CFBundleSpokenName A replacement for the app name in text-to-speech operations.
|
|
59
|
+
* @property {string} CFBundleVersion The version of the build that identifies an iteration of the bundle.
|
|
60
|
+
* @property {string} CFBundleShortVersionString The release or version number of the bundle.
|
|
61
|
+
* @property {string} NSHumanReadableCopyright A human-readable copyright notice for the bundle.
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* References:
|
|
66
|
+
* https://learn.microsoft.com/en-us/windows/win32/msi/version
|
|
67
|
+
* https://learn.microsoft.com/en-gb/windows/win32/sbscs/application-manifests
|
|
68
|
+
* https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2015/deployment/trustinfo-element-clickonce-application?view=vs-2015#requestedexecutionlevel
|
|
69
|
+
* https://learn.microsoft.com/en-gb/windows/win32/menurc/versioninfo-resource
|
|
70
|
+
*
|
|
71
|
+
* @typedef {object} WinRc Windows configuration options. More info
|
|
72
|
+
* @property {string} name The name of the application
|
|
73
|
+
* @property {string} version The version of the application
|
|
74
|
+
* @property {string} comments Additional information that should be displayed for diagnostic purposes.
|
|
75
|
+
* @property {string} company Company that produced the file—for example, Microsoft Corporation or Standard Microsystems Corporation, Inc. This string is required.
|
|
76
|
+
* @property {string} fileDescription File description to be presented to users. This string may be displayed in a list box when the user is choosing files to install. For example, Keyboard Driver for AT-Style Keyboards. This string is required.
|
|
77
|
+
* @property {string} fileVersion Version number of the file. For example, 3.10 or 5.00.RC2. This string is required.
|
|
78
|
+
* @property {string} icon The path to the icon file. It should be a .ico file.
|
|
79
|
+
* @property {string} internalName Internal name of the file, if one exists—for example, a module name if the file is a dynamic-link library. If the file has no internal name, this string should be the original filename, without extension. This string is required.
|
|
80
|
+
* @property {string} legalCopyright Copyright notices that apply to the file. This should include the full text of all notices, legal symbols, copyright dates, and so on. This string is optional.
|
|
81
|
+
* @property {string} legalTrademark Trademarks and registered trademarks that apply to the file. This should include the full text of all notices, legal symbols, trademark numbers, and so on. This string is optional.
|
|
82
|
+
* @property {string} originalFilename Original name of the file, not including a path. This information enables an application to determine whether a file has been renamed by a user. The format of the name depends on the file system for which the file was created. This string is required.
|
|
83
|
+
* @property {string} privateBuild Information about a private version of the file—for example, Built by TESTER1 on \\TESTBED. This string should be present only if VS_FF_PRIVATEBUILD is specified in the fileflags parameter of the root block.
|
|
84
|
+
* @property {string} productName Name of the product with which the file is distributed. This string is required.
|
|
85
|
+
* @property {string} productVersion Version of the product with which the file is distributed—for example, 3.10 or 5.00.RC2. This string is required.
|
|
86
|
+
* @property {string} specialBuild Text that specifies how this version of the file differs from the standard version—for example, Private build for TESTER1 solving mouse problems on M250 and M250E computers. This string should be present only if VS_FF_SPECIALBUILD is specified in the fileflags parameter of the root block.
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Generate NW build artifacts
|
|
91
|
+
*
|
|
92
|
+
* Note: File permissions are incorrectly set for Linux or MacOS apps built on Windows platform. For more info: https://www.geeksforgeeks.org/node-js-fs-chmod-method
|
|
93
|
+
*
|
|
94
|
+
* Note: To edit Windows executable resources, we use [`rcedit`](https://github.com/electron/node-rcedit). To use rcedit on non-Windows platforms, you will have to install [Wine](https://www.winehq.org/).
|
|
95
|
+
*
|
|
96
|
+
* Note: We recursively glob the file patterns given by the user. The first `package.json` parsed is taken to be the NW.js manifest file. If you have multiple manifest files, the first glob pattern should be the path to the NW.js manifest. Choosing a Node manifest at `./package.json` is the most convenient option.
|
|
97
|
+
*
|
|
98
|
+
* Note: If you are using the MacOS ARM unofficial builds, you will need to [remove the `com.apple.qurantine` flag](https://github.com/corwin-of-amber/nw.js/releases/tag/nw-v0.75.0):
|
|
99
|
+
*
|
|
100
|
+
* `sudo xattr -r -d com.apple.quarantine nwjs.app`
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* // Minimal Usage (uses default values)
|
|
104
|
+
* nwbuild({
|
|
105
|
+
* mode: "build",
|
|
106
|
+
* });
|
|
107
|
+
*
|
|
108
|
+
* @param {string | string[]} files Array of NW app files
|
|
109
|
+
* @param {string} nwDir Directory to hold NW binaries
|
|
110
|
+
* @param {string} outDir Directory to store build artifacts
|
|
111
|
+
* @param {"linux" | "osx" | "win"} platform Platform is the operating system type
|
|
112
|
+
* @param {"zip" | boolean} zip Specify if the build artifacts are to be zipped
|
|
113
|
+
* @param {LinuxRc | OsxRc | WinRc} app Multi platform configuration options
|
|
114
|
+
* @return {Promise<undefined>}
|
|
115
|
+
*/
|
|
116
|
+
export async function build(files, nwDir, outDir, platform, zip, app) {
|
|
117
|
+
log.debug(`Remove any files at ${outDir} directory`);
|
|
118
|
+
await rm(outDir, { force: true, recursive: true });
|
|
119
|
+
log.debug(`Copy ${nwDir} files to ${outDir} directory`);
|
|
120
|
+
await cp(nwDir, outDir, { recursive: true, verbatimSymlinks: true });
|
|
121
|
+
|
|
122
|
+
log.debug(`Copy files in srcDir to ${outDir} directory`);
|
|
123
|
+
|
|
124
|
+
if (typeof files === "string") {
|
|
125
|
+
await cp(
|
|
126
|
+
files,
|
|
127
|
+
resolve(
|
|
128
|
+
outDir,
|
|
129
|
+
platform !== "osx"
|
|
130
|
+
? "package.nw"
|
|
131
|
+
: "nwjs.app/Contents/Resources/app.nw",
|
|
132
|
+
),
|
|
133
|
+
{ recursive: true, verbatimSymlinks: true },
|
|
134
|
+
);
|
|
135
|
+
} else {
|
|
136
|
+
for (let file of files) {
|
|
137
|
+
log.debug(`Copy ${file} file to ${outDir} directory`);
|
|
138
|
+
await cp(
|
|
139
|
+
file,
|
|
140
|
+
resolve(
|
|
141
|
+
outDir,
|
|
142
|
+
platform !== "osx"
|
|
143
|
+
? "package.nw"
|
|
144
|
+
: "nwjs.app/Contents/Resources/app.nw",
|
|
145
|
+
file,
|
|
146
|
+
),
|
|
147
|
+
{ recursive: true, verbatimSymlinks: true },
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
log.debug(`Starting platform specific config steps for ${platform}`);
|
|
153
|
+
|
|
154
|
+
if (platform === "linux") {
|
|
155
|
+
if (PLATFORM === "win32") {
|
|
156
|
+
log.warn(
|
|
157
|
+
"Linux apps built on Windows platform do not preserve all file permissions. See #716",
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
let desktopEntryFile = {
|
|
161
|
+
Type: "Application",
|
|
162
|
+
Version: "1.5",
|
|
163
|
+
Name: app.name,
|
|
164
|
+
GenericName: app.genericName,
|
|
165
|
+
NoDisplay: app.noDisplay,
|
|
166
|
+
Comment: app.comment,
|
|
167
|
+
Icon: app.icon,
|
|
168
|
+
Hidden: app.hidden,
|
|
169
|
+
OnlyShowIn: app.onlyShowIn,
|
|
170
|
+
NotShowIn: app.notShowIn,
|
|
171
|
+
DBusActivatable: app.dBusActivatable,
|
|
172
|
+
TryExec: app.tryExec,
|
|
173
|
+
Exec: app.name,
|
|
174
|
+
Path: app.path,
|
|
175
|
+
Terminal: app.terminal,
|
|
176
|
+
Actions: app.actions,
|
|
177
|
+
MimeType: app.mimeType,
|
|
178
|
+
Categories: app.categories,
|
|
179
|
+
Implements: app.implements,
|
|
180
|
+
Keywords: app.keywords,
|
|
181
|
+
StartupNotify: app.startupNotify,
|
|
182
|
+
StartupWMClass: app.startupWMClass,
|
|
183
|
+
PrefersNonDefaultGPU: app.prefersNonDefaultGPU,
|
|
184
|
+
SingleMainWindow: app.singleMainWindow,
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
await rename(`${outDir}/nw`, `${outDir}/${app.name}`);
|
|
188
|
+
|
|
189
|
+
let fileContent = `[Desktop Entry]\n`;
|
|
190
|
+
Object.keys(desktopEntryFile).forEach((key) => {
|
|
191
|
+
if (desktopEntryFile[key] !== undefined) {
|
|
192
|
+
fileContent += `${key}=${desktopEntryFile[key]}\n`;
|
|
193
|
+
log.debug(`Add ${key}=${desktopEntryFile[key]} to Desktop Entry File`);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
let filePath = `${outDir}/${app.name}.desktop`;
|
|
197
|
+
await writeFile(filePath, fileContent);
|
|
198
|
+
log.debug("Desktop Entry file generated");
|
|
199
|
+
} else if (platform === "win") {
|
|
200
|
+
let versionString = {
|
|
201
|
+
Comments: app.comments,
|
|
202
|
+
CompanyName: app.author,
|
|
203
|
+
FileDescription: app.fileDescription,
|
|
204
|
+
FileVersion: app.fileVersion,
|
|
205
|
+
InternalName: app.name,
|
|
206
|
+
LegalCopyright: app.legalCopyright,
|
|
207
|
+
LegalTrademarks: app.legalTrademark,
|
|
208
|
+
OriginalFilename: app.name,
|
|
209
|
+
PrivateBuild: app.name,
|
|
210
|
+
ProductName: app.name,
|
|
211
|
+
ProductVersion: app.version,
|
|
212
|
+
SpecialBuild: app.name,
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
Object.keys(versionString).forEach((option) => {
|
|
216
|
+
if (versionString[option] === undefined) {
|
|
217
|
+
delete versionString[option];
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const rcEditOptions = {
|
|
222
|
+
"file-version": app.version,
|
|
223
|
+
"product-version": app.version,
|
|
224
|
+
"version-string": versionString,
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
if (app.icon) {
|
|
228
|
+
rcEditOptions.icon = app.icon;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
try {
|
|
232
|
+
const outDirAppExe = resolve(outDir, `${app.name}.exe`);
|
|
233
|
+
await rename(resolve(outDir, "nw.exe"), outDirAppExe);
|
|
234
|
+
await rcedit(outDirAppExe, rcEditOptions);
|
|
235
|
+
} catch (error) {
|
|
236
|
+
log.warn(
|
|
237
|
+
"Renaming EXE failed or unable to modify EXE. If it's the latter, ensure WINE is installed or build your application Windows platform",
|
|
238
|
+
);
|
|
239
|
+
log.error(error);
|
|
240
|
+
}
|
|
241
|
+
} else if (platform === "osx") {
|
|
242
|
+
if (PLATFORM === "win32") {
|
|
243
|
+
log.warn(
|
|
244
|
+
"MacOS apps built on Windows platform do not preserve all file permissions. See #716",
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
const outApp = resolve(outDir, `${app.name}.app`);
|
|
250
|
+
await rename(resolve(outDir, "nwjs.app"), outApp);
|
|
251
|
+
if (app.icon !== undefined) {
|
|
252
|
+
await copyFile(
|
|
253
|
+
resolve(app.icon),
|
|
254
|
+
resolve(outApp, "Contents", "Resources", "app.icns"),
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const infoPlistPath = resolve(outApp, "Contents", "Info.plist");
|
|
259
|
+
const infoPlistJson = plist.parse(await readFile(infoPlistPath, "utf-8"));
|
|
260
|
+
|
|
261
|
+
const infoPlistStringsPath = resolve(
|
|
262
|
+
outApp,
|
|
263
|
+
"Contents",
|
|
264
|
+
"Resources",
|
|
265
|
+
"en.lproj",
|
|
266
|
+
"InfoPlist.strings",
|
|
267
|
+
);
|
|
268
|
+
const infoPlistStringsData = await readFile(
|
|
269
|
+
infoPlistStringsPath,
|
|
270
|
+
"utf-8",
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
let infoPlistStringsDataArray = infoPlistStringsData.split("\n");
|
|
274
|
+
|
|
275
|
+
infoPlistStringsDataArray.forEach((line, idx, arr) => {
|
|
276
|
+
if (line.includes("NSHumanReadableCopyright")) {
|
|
277
|
+
arr[
|
|
278
|
+
idx
|
|
279
|
+
] = `NSHumanReadableCopyright = "${app.NSHumanReadableCopyright}";`;
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
infoPlistJson.LSApplicationCategoryType = app.LSApplicationCategoryType;
|
|
284
|
+
infoPlistJson.CFBundleIdentifier = app.CFBundleIdentifier;
|
|
285
|
+
infoPlistJson.CFBundleName = app.CFBundleName;
|
|
286
|
+
infoPlistJson.CFBundleDisplayName = app.CFBundleDisplayName;
|
|
287
|
+
infoPlistJson.CFBundleSpokenName = app.CFBundleSpokenName;
|
|
288
|
+
infoPlistJson.CFBundleVersion = app.CFBundleVersion;
|
|
289
|
+
infoPlistJson.CFBundleShortVersionString = app.CFBundleShortVersionString;
|
|
290
|
+
|
|
291
|
+
Object.keys(infoPlistJson).forEach((option) => {
|
|
292
|
+
if (infoPlistJson[option] === undefined) {
|
|
293
|
+
delete infoPlistJson[option];
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
await writeFile(infoPlistPath, plist.build(infoPlistJson));
|
|
298
|
+
await writeFile(
|
|
299
|
+
infoPlistStringsPath,
|
|
300
|
+
infoPlistStringsDataArray.toString().replace(/,/g, "\n"),
|
|
301
|
+
);
|
|
302
|
+
} catch (error) {
|
|
303
|
+
log.error(error);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (zip !== false) {
|
|
308
|
+
if (zip === true || zip === "zip") {
|
|
309
|
+
await compressing.zip.compressDir(outDir, `${outDir}.zip`);
|
|
310
|
+
} else if (zip === "tar") {
|
|
311
|
+
await compressing.tar.compressDir(outDir, `${outDir}.tar`);
|
|
312
|
+
} else if (zip === "tgz") {
|
|
313
|
+
await compressing.tgz.compressDir(outDir, `${outDir}.tgz`);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
await rm(outDir, { recursive: true, force: true });
|
|
317
|
+
}
|
|
318
|
+
}
|