nw-builder 4.9.0 → 4.11.0
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 +1 -1
- package/README.md +1 -2
- package/package.json +16 -20
- package/src/bld/osx.js +190 -0
- package/src/bld.js +73 -147
- package/src/cli.js +23 -86
- package/src/get/decompress.js +10 -13
- package/src/get/ffmpeg.js +3 -5
- package/src/get/index.js +33 -46
- package/src/get/node.js +4 -8
- package/src/get/nw.js +5 -9
- package/src/get/request.js +6 -8
- package/src/get/verify.js +2 -3
- package/src/index.d.ts +2 -0
- package/src/index.js +13 -14
- package/src/run.js +16 -19
- package/src/util.js +88 -96
- package/src/get/decompress.test.js +0 -56
- package/src/get/ffmpeg.test.js +0 -28
- package/src/get/node.test.js +0 -25
- package/src/get/nw.test.js +0 -29
- package/src/get/request.test.js +0 -16
- package/src/get/verify.test.js +0 -15
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -286,6 +286,7 @@ This object defines additional properties used for building for a specific platf
|
|
|
286
286
|
| CFBundleVersion | `string` | The version of the build that identifies an iteration of the bundle. |
|
|
287
287
|
| CFBundleShortVersionString | `string` | The release or version number of the bundle. |
|
|
288
288
|
| NSHumanReadableCopyright | `string` | A human-readable copyright notice for the bundle. |
|
|
289
|
+
| NSLocalNetworkUsageDescription | `string` | A human-readable description of why the application needs access to the local network. |
|
|
289
290
|
|
|
290
291
|
|
|
291
292
|
## Guides
|
|
@@ -375,7 +376,6 @@ nwbuild({
|
|
|
375
376
|
### Features
|
|
376
377
|
|
|
377
378
|
- feat(get): support canary releases
|
|
378
|
-
- feat(bld): rename MacOS Helper apps
|
|
379
379
|
- feat(pkg): add `AppImage` installer
|
|
380
380
|
- feat(pkg): add `NSIS` installer
|
|
381
381
|
- feat(pkg): add `DMG` installer
|
|
@@ -389,7 +389,6 @@ nwbuild({
|
|
|
389
389
|
- chore: annotate file paths as `fs.PathLike` instead of `string`.
|
|
390
390
|
- chore(bld): factor out core build step
|
|
391
391
|
- chore(bld): factor out linux config
|
|
392
|
-
- chore(bld): factor out macos config
|
|
393
392
|
- chore(bld): factor out windows config
|
|
394
393
|
- chore(bld): factor out native addon
|
|
395
394
|
- chore(bld): factor out compressing
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nw-builder",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.11.0",
|
|
4
4
|
"description": "Build NW.js desktop applications for MacOS, Windows and Linux.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"NW.js",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"Application"
|
|
10
10
|
],
|
|
11
11
|
"author": {
|
|
12
|
-
"name": "Steffen
|
|
12
|
+
"name": "Steffen Muller",
|
|
13
13
|
"url": "https://www.mllrsohn.com/"
|
|
14
14
|
},
|
|
15
15
|
"maintainers": [
|
|
@@ -42,39 +42,35 @@
|
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"postinstall": "node ./src/postinstall.js",
|
|
45
|
-
"lint": "eslint ./src
|
|
46
|
-
"lint:fix": "eslint --fix ./src
|
|
47
|
-
"markdown:fix": "markdownlint --fix ./README.md",
|
|
48
|
-
"docs": "jsdoc -d docs ./README.md ./src/index.js ./src/get.js ./src/run.js ./src/bld.js",
|
|
45
|
+
"lint": "eslint ./src ./tests",
|
|
46
|
+
"lint:fix": "eslint --fix ./src ./tests",
|
|
49
47
|
"test": "vitest run --coverage",
|
|
50
48
|
"test:cov": "vitest --coverage.enabled true",
|
|
51
|
-
"demo": "
|
|
52
|
-
"
|
|
49
|
+
"demo:bld": "node ./tests/fixtures/demo.js",
|
|
50
|
+
"demo:exe": "./tests/fixtures/out/nwapp.app/Contents/MacOS/nwapp",
|
|
51
|
+
"demo:cli": "nwbuild --mode run ./src ./app/**"
|
|
53
52
|
},
|
|
54
53
|
"devDependencies": {
|
|
55
|
-
"@
|
|
56
|
-
"@vitest/coverage-v8": "^2.
|
|
54
|
+
"@eslint/js": "^9.10.0",
|
|
55
|
+
"@vitest/coverage-v8": "^2.1.1",
|
|
57
56
|
"base-volta-off-of-nwjs": "^1.0.5",
|
|
58
|
-
"eslint": "^9.
|
|
59
|
-
"eslint-
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"jsdoc": "^4.0.3",
|
|
64
|
-
"nw": "^0.90.0",
|
|
65
|
-
"selenium-webdriver": "^4.23.0",
|
|
57
|
+
"eslint": "^9.10.0",
|
|
58
|
+
"eslint-plugin-jsdoc": "^50.2.4",
|
|
59
|
+
"globals": "^15.9.0",
|
|
60
|
+
"nw": "^0.91.0",
|
|
61
|
+
"selenium-webdriver": "^4.24.1",
|
|
66
62
|
"vitest": "^2.0.4"
|
|
67
63
|
},
|
|
68
64
|
"dependencies": {
|
|
69
65
|
"archiver": "^7.0.1",
|
|
70
|
-
"axios": "^1.7.
|
|
66
|
+
"axios": "^1.7.7",
|
|
67
|
+
"commander": "^12.1.0",
|
|
71
68
|
"glob": "^11.0.0",
|
|
72
69
|
"node-gyp": "^10.2.0",
|
|
73
70
|
"plist": "^3.1.0",
|
|
74
71
|
"resedit": "^2.0.2",
|
|
75
72
|
"semver": "^7.6.3",
|
|
76
73
|
"tar": "^7.4.3",
|
|
77
|
-
"yargs": "^17.7.2",
|
|
78
74
|
"yauzl-promise": "^4.0.0"
|
|
79
75
|
},
|
|
80
76
|
"volta": {
|
package/src/bld/osx.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import console from 'node:console';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import process from 'node:process';
|
|
5
|
+
|
|
6
|
+
import plist from 'plist';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Function to update Helper App Plist Files
|
|
10
|
+
* @param {string} plistPath - Path to Helper App Plist File
|
|
11
|
+
* @param {string} helperName - Helper App Name
|
|
12
|
+
* @param {string} helperId - Helper App ID
|
|
13
|
+
* @param {string} appCFBundleIdentifier - options.app.CFBundleIdentifier
|
|
14
|
+
*/
|
|
15
|
+
async function updateHelperPlist (plistPath, helperName, helperId, appCFBundleIdentifier) {
|
|
16
|
+
const plistFullPath = path.resolve(plistPath, 'Contents/Info.plist');
|
|
17
|
+
const plistJson = plist.parse(await fs.promises.readFile(plistFullPath, 'utf-8'));
|
|
18
|
+
plistJson.CFBundleDisplayName = helperName;
|
|
19
|
+
plistJson.CFBundleName = helperName;
|
|
20
|
+
plistJson.CFBundleExecutable = helperName;
|
|
21
|
+
plistJson.CFBundleIdentifier = `${appCFBundleIdentifier}.${helperId}`;
|
|
22
|
+
await fs.promises.writeFile(plistFullPath, plist.build(plistJson));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
*
|
|
27
|
+
* @param {object} options - Options.
|
|
28
|
+
* @param {object} options.app - Application configuration.
|
|
29
|
+
* @param {string} options.outDir - Output directory.
|
|
30
|
+
* @param {string} options.releaseInfo - Release information.
|
|
31
|
+
* @returns {Promise<void>} - Promise.
|
|
32
|
+
*/
|
|
33
|
+
export default async function setOsxConfig({ app, outDir, releaseInfo }) {
|
|
34
|
+
if (process.platform === 'win32') {
|
|
35
|
+
console.warn(
|
|
36
|
+
'MacOS apps built on Windows platform do not preserve all file permissions. See #716',
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
/**
|
|
42
|
+
* @type {string | null}
|
|
43
|
+
*/
|
|
44
|
+
const chromiumVersion = releaseInfo?.components?.chromium;
|
|
45
|
+
if (!chromiumVersion) {
|
|
46
|
+
throw new Error('Chromium version is missing.');
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Path to MacOS application.
|
|
50
|
+
* @type {string}
|
|
51
|
+
*/
|
|
52
|
+
const nwjsApp = path.resolve(outDir, 'nwjs.app');
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Path to renamed MacOS application.
|
|
56
|
+
* @type {string}
|
|
57
|
+
*/
|
|
58
|
+
const outApp = path.resolve(outDir, `${app.name}.app`);
|
|
59
|
+
|
|
60
|
+
/* Rename `nwjs.app` to `${app.name}.app` */
|
|
61
|
+
await fs.promises.rename(nwjsApp, outApp);
|
|
62
|
+
|
|
63
|
+
/* Rename `Contents/MacOS/nwjs` to `Contents/MacOS/${app.name}` */
|
|
64
|
+
await fs.promises.rename(
|
|
65
|
+
path.resolve(outApp, 'Contents', 'MacOS', 'nwjs'),
|
|
66
|
+
path.resolve(outApp, 'Contents', 'MacOS', app.name),
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
/* Rename all Helper apps */
|
|
70
|
+
const helperBaseDir = path.resolve(
|
|
71
|
+
outApp,
|
|
72
|
+
'Contents/Frameworks/nwjs Framework.framework/Versions',
|
|
73
|
+
chromiumVersion,
|
|
74
|
+
'Helpers/'
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const helperApps = [
|
|
78
|
+
{ name: 'nwjs Helper (Alerts).app', id: 'helper.alert' },
|
|
79
|
+
{ name: 'nwjs Helper (GPU).app', id: 'helper.gpu' },
|
|
80
|
+
{ name: 'nwjs Helper (Plugin).app', id: 'helper.plugin' },
|
|
81
|
+
{ name: 'nwjs Helper (Renderer).app', id: 'helper.renderer' },
|
|
82
|
+
{ name: 'nwjs Helper.app', id: 'helper' },
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
for (const helperApp of helperApps) {
|
|
86
|
+
const newHelperAppName = helperApp.name.replace(/^nwjs/, app.name);
|
|
87
|
+
const oldPath = path.resolve(helperBaseDir, helperApp.name);
|
|
88
|
+
const newPath = path.resolve(helperBaseDir, newHelperAppName);
|
|
89
|
+
|
|
90
|
+
// Rename Helper base directory
|
|
91
|
+
await fs.promises.rename(oldPath, newPath);
|
|
92
|
+
|
|
93
|
+
// Rename Helper sub-directory
|
|
94
|
+
const helperBaseName = helperApp.name.replace(/.app$/, '');
|
|
95
|
+
const subPathBase = path.resolve(newPath, 'Contents/MacOS/');
|
|
96
|
+
const oldSubPath = path.resolve(subPathBase, helperBaseName);
|
|
97
|
+
const newSubPath = path.resolve(subPathBase, helperBaseName.replace(/^nwjs/, app.name));
|
|
98
|
+
await fs.promises.rename(oldSubPath, newSubPath);
|
|
99
|
+
|
|
100
|
+
// Update Helper Plist file
|
|
101
|
+
await updateHelperPlist(newPath, newHelperAppName.replace(/.app$/, ''), helperApp.id, app.CFBundleIdentifier);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Replace default icon with user defined icon if specified. */
|
|
105
|
+
if (app.icon !== undefined) {
|
|
106
|
+
await fs.promises.copyFile(
|
|
107
|
+
path.resolve(app.icon),
|
|
108
|
+
path.resolve(outApp, 'Contents', 'Resources', 'app.icns'),
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Path to `nwjs.app/Contents/Info.plist`
|
|
114
|
+
* @type {string}
|
|
115
|
+
*/
|
|
116
|
+
const contentsInfoPlistPath = path.resolve(
|
|
117
|
+
outApp,
|
|
118
|
+
'Contents',
|
|
119
|
+
'Info.plist'
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Path to `nwjs.app/Contents/Resources/en.lproj/InfoPlist.settings`
|
|
124
|
+
* @type {string}
|
|
125
|
+
*/
|
|
126
|
+
const contentsResourcesEnLprojInfoPlistStringsPath = path.resolve(
|
|
127
|
+
outApp,
|
|
128
|
+
'Contents',
|
|
129
|
+
'Resources',
|
|
130
|
+
'en.lproj',
|
|
131
|
+
'InfoPlist.strings',
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* JSON from `nwjs.app/Contents/Info.plist`
|
|
136
|
+
* @type {object}
|
|
137
|
+
*/
|
|
138
|
+
const contentsInfoPlistJson = plist.parse(
|
|
139
|
+
await fs.promises.readFile(
|
|
140
|
+
contentsInfoPlistPath,
|
|
141
|
+
'utf-8'
|
|
142
|
+
)
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
/* Update Plist with user defined values. */
|
|
146
|
+
contentsInfoPlistJson.LSApplicationCategoryType = app.LSApplicationCategoryType;
|
|
147
|
+
contentsInfoPlistJson.CFBundleIdentifier = app.CFBundleIdentifier;
|
|
148
|
+
contentsInfoPlistJson.CFBundleName = app.CFBundleName;
|
|
149
|
+
contentsInfoPlistJson.CFBundleDisplayName = app.CFBundleDisplayName;
|
|
150
|
+
contentsInfoPlistJson.CFBundleSpokenName = app.CFBundleSpokenName;
|
|
151
|
+
contentsInfoPlistJson.CFBundleVersion = app.CFBundleVersion;
|
|
152
|
+
contentsInfoPlistJson.CFBundleShortVersionString = app.CFBundleShortVersionString;
|
|
153
|
+
contentsInfoPlistJson.CFBundleExecutable = app.name;
|
|
154
|
+
contentsInfoPlistJson.NSLocalNetworkUsageDescription = app.NSLocalNetworkUsageDescription;
|
|
155
|
+
|
|
156
|
+
/* Remove properties that were not updated by the user. */
|
|
157
|
+
Object.keys(contentsInfoPlistJson).forEach((option) => {
|
|
158
|
+
if (contentsInfoPlistJson[option] === undefined) {
|
|
159
|
+
delete contentsInfoPlistJson[option];
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Data from `nwjs.app/Contents/Resources/en.lproj/InfoPlist.settings`
|
|
165
|
+
* @type {string[]}
|
|
166
|
+
*/
|
|
167
|
+
const contentsResourcesEnLprojInfoPlistStringsArray = (await fs.promises.readFile(
|
|
168
|
+
contentsResourcesEnLprojInfoPlistStringsPath,
|
|
169
|
+
'utf-8',
|
|
170
|
+
)).split('\n');
|
|
171
|
+
contentsResourcesEnLprojInfoPlistStringsArray.forEach((line, idx, arr) => {
|
|
172
|
+
if (line.includes('NSHumanReadableCopyright')) {
|
|
173
|
+
arr[idx] =
|
|
174
|
+
`NSHumanReadableCopyright = "${app.NSHumanReadableCopyright}";`;
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
/* Write the updated values to their config files. */
|
|
179
|
+
await fs.promises.writeFile(
|
|
180
|
+
contentsInfoPlistPath,
|
|
181
|
+
plist.build(contentsInfoPlistJson));
|
|
182
|
+
await fs.promises.writeFile(
|
|
183
|
+
contentsResourcesEnLprojInfoPlistStringsPath,
|
|
184
|
+
contentsResourcesEnLprojInfoPlistStringsArray.toString().replace(/,/g, '\n'),
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
} catch (error) {
|
|
188
|
+
console.error(error);
|
|
189
|
+
}
|
|
190
|
+
};
|
package/src/bld.js
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
import child_process from
|
|
2
|
-
import console from
|
|
3
|
-
import fs from
|
|
4
|
-
import path from
|
|
5
|
-
import process from
|
|
6
|
-
|
|
7
|
-
import archiver from
|
|
8
|
-
import * as resedit from
|
|
1
|
+
import child_process from 'node:child_process';
|
|
2
|
+
import console from 'node:console';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import process from 'node:process';
|
|
6
|
+
|
|
7
|
+
import archiver from 'archiver';
|
|
8
|
+
import * as resedit from 'resedit';
|
|
9
9
|
// pe-library is a direct dependency of resedit
|
|
10
10
|
import * as peLibrary from 'pe-library';
|
|
11
|
-
import plist from "plist";
|
|
12
11
|
import * as tar from 'tar';
|
|
13
12
|
|
|
14
|
-
import util from
|
|
13
|
+
import util from './util.js';
|
|
14
|
+
import setOsxConfig from './bld/osx.js';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* References:
|
|
18
18
|
* https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html
|
|
19
|
-
*
|
|
20
19
|
* @typedef {object} LinuxRc Linux configuration options
|
|
21
20
|
* @property {string} name Name of the application
|
|
22
21
|
* @property {string} genericName Generic name of the application
|
|
@@ -45,18 +44,18 @@ import util from "./util.js";
|
|
|
45
44
|
/**
|
|
46
45
|
* References:
|
|
47
46
|
* https://developer.apple.com/documentation/bundleresources/information_property_list
|
|
48
|
-
*
|
|
49
|
-
* @
|
|
50
|
-
* @property {string}
|
|
51
|
-
* @property {string}
|
|
52
|
-
* @property {string}
|
|
53
|
-
* @property {string}
|
|
54
|
-
* @property {string}
|
|
55
|
-
* @property {string}
|
|
56
|
-
* @property {string}
|
|
57
|
-
* @property {string}
|
|
58
|
-
* @property {string}
|
|
59
|
-
* @property {string}
|
|
47
|
+
* @typedef {object} OsxRc OSX resource configuration options
|
|
48
|
+
* @property {string} name The name of the application
|
|
49
|
+
* @property {string} icon The path to the icon file. It should be a .icns file.
|
|
50
|
+
* @property {string} LSApplicationCategoryType The category that best describes your app for the App Store.
|
|
51
|
+
* @property {string} CFBundleIdentifier A unique identifier for a bundle usually in reverse DNS format.
|
|
52
|
+
* @property {string} CFBundleName A user-visible short name for the bundle.
|
|
53
|
+
* @property {string} CFBundleDisplayName The user-visible name for the bundle.
|
|
54
|
+
* @property {string} CFBundleSpokenName A replacement for the app name in text-to-speech operations.
|
|
55
|
+
* @property {string} CFBundleVersion The version of the build that identifies an iteration of the bundle.
|
|
56
|
+
* @property {string} CFBundleShortVersionString The release or version number of the bundle.
|
|
57
|
+
* @property {string} NSHumanReadableCopyright A human-readable copyright notice for the bundle.
|
|
58
|
+
* @property {string} NSLocalNetworkUsageDescription A human-readable description of why the application needs access to the local network.
|
|
60
59
|
*/
|
|
61
60
|
|
|
62
61
|
/**
|
|
@@ -65,7 +64,6 @@ import util from "./util.js";
|
|
|
65
64
|
* https://learn.microsoft.com/en-gb/windows/win32/sbscs/application-manifests
|
|
66
65
|
* https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2015/deployment/trustinfo-element-clickonce-application?view=vs-2015#requestedexecutionlevel
|
|
67
66
|
* https://learn.microsoft.com/en-gb/windows/win32/menurc/versioninfo-resource
|
|
68
|
-
*
|
|
69
67
|
* @typedef {object} WinRc Windows configuration options. More info
|
|
70
68
|
* @property {string} name The name of the application
|
|
71
69
|
* @property {string} version @deprecated Use {@link fileVersion} instead. The version of the application
|
|
@@ -100,34 +98,34 @@ import util from "./util.js";
|
|
|
100
98
|
* @property {boolean | string | object} [managedManifest = false] Manage manifest
|
|
101
99
|
* @property {false | "gyp"} [nativeAddon = false] Rebuild native modules
|
|
102
100
|
* @property {false | "zip" | "tar" | "tgz"} [zip = false] Compress built artifacts
|
|
101
|
+
* @property {object} [releaseInfo = {}] Version specific release metadata.
|
|
103
102
|
*/
|
|
104
103
|
|
|
105
104
|
/**
|
|
106
105
|
* Build NW.js application.
|
|
107
|
-
*
|
|
108
106
|
* @async
|
|
109
107
|
* @function
|
|
110
108
|
* @param {BuildOptions} options - Build options
|
|
111
|
-
* @
|
|
109
|
+
* @returns {Promise<void>}
|
|
112
110
|
*/
|
|
113
111
|
async function bld({
|
|
114
|
-
version =
|
|
115
|
-
flavor =
|
|
112
|
+
version = 'latest',
|
|
113
|
+
flavor = 'normal',
|
|
116
114
|
platform = util.PLATFORM_KV[process.platform],
|
|
117
115
|
arch = util.ARCH_KV[process.arch],
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
outDir = "./out",
|
|
116
|
+
srcDir = './src',
|
|
117
|
+
cacheDir = './cache',
|
|
118
|
+
outDir = './out',
|
|
122
119
|
app,
|
|
123
120
|
glob = true,
|
|
124
121
|
managedManifest = false,
|
|
125
122
|
nativeAddon = false,
|
|
126
123
|
zip = false,
|
|
124
|
+
releaseInfo = {},
|
|
127
125
|
}) {
|
|
128
126
|
const nwDir = path.resolve(
|
|
129
127
|
cacheDir,
|
|
130
|
-
`nwjs${flavor ===
|
|
128
|
+
`nwjs${flavor === 'sdk' ? '-sdk' : ''}-v${version}-${platform
|
|
131
129
|
}-${arch}`,
|
|
132
130
|
);
|
|
133
131
|
|
|
@@ -143,9 +141,9 @@ async function bld({
|
|
|
143
141
|
file,
|
|
144
142
|
path.resolve(
|
|
145
143
|
outDir,
|
|
146
|
-
platform !==
|
|
147
|
-
?
|
|
148
|
-
:
|
|
144
|
+
platform !== 'osx'
|
|
145
|
+
? 'package.nw'
|
|
146
|
+
: 'nwjs.app/Contents/Resources/app.nw',
|
|
149
147
|
file,
|
|
150
148
|
),
|
|
151
149
|
{ recursive: true, verbatimSymlinks: true },
|
|
@@ -156,40 +154,33 @@ async function bld({
|
|
|
156
154
|
files,
|
|
157
155
|
path.resolve(
|
|
158
156
|
outDir,
|
|
159
|
-
platform !==
|
|
160
|
-
?
|
|
161
|
-
:
|
|
157
|
+
platform !== 'osx'
|
|
158
|
+
? 'package.nw'
|
|
159
|
+
: 'nwjs.app/Contents/Resources/app.nw',
|
|
162
160
|
),
|
|
163
161
|
{ recursive: true, verbatimSymlinks: true },
|
|
164
162
|
);
|
|
165
163
|
}
|
|
166
164
|
|
|
167
|
-
const releaseInfo = await util.getReleaseInfo(
|
|
168
|
-
version,
|
|
169
|
-
platform,
|
|
170
|
-
arch,
|
|
171
|
-
cacheDir,
|
|
172
|
-
manifestUrl,
|
|
173
|
-
);
|
|
174
165
|
const nodeVersion = releaseInfo.components.node;
|
|
175
166
|
|
|
176
167
|
if (
|
|
177
168
|
managedManifest === true ||
|
|
178
|
-
typeof managedManifest ===
|
|
179
|
-
typeof managedManifest ===
|
|
169
|
+
typeof managedManifest === 'object' ||
|
|
170
|
+
typeof managedManifest === 'string'
|
|
180
171
|
) {
|
|
181
172
|
await manageManifest({ nwPkg: manifest, managedManifest, outDir, platform });
|
|
182
173
|
}
|
|
183
174
|
|
|
184
|
-
if (platform ===
|
|
175
|
+
if (platform === 'linux') {
|
|
185
176
|
await setLinuxConfig({ app, outDir });
|
|
186
|
-
} else if (platform ===
|
|
177
|
+
} else if (platform === 'win') {
|
|
187
178
|
await setWinConfig({ app, outDir });
|
|
188
|
-
} else if (platform ===
|
|
189
|
-
await setOsxConfig({
|
|
179
|
+
} else if (platform === 'osx') {
|
|
180
|
+
await setOsxConfig({ app, outDir, releaseInfo });
|
|
190
181
|
}
|
|
191
182
|
|
|
192
|
-
if (nativeAddon ===
|
|
183
|
+
if (nativeAddon === 'gyp') {
|
|
193
184
|
buildNativeAddon({ cacheDir, version, platform, arch, outDir, nodeVersion });
|
|
194
185
|
}
|
|
195
186
|
|
|
@@ -205,56 +196,56 @@ const manageManifest = async ({ nwPkg, managedManifest, outDir, platform }) => {
|
|
|
205
196
|
manifest = nwPkg;
|
|
206
197
|
}
|
|
207
198
|
|
|
208
|
-
if (typeof managedManifest ===
|
|
199
|
+
if (typeof managedManifest === 'object') {
|
|
209
200
|
manifest = managedManifest;
|
|
210
201
|
}
|
|
211
202
|
|
|
212
|
-
if (typeof managedManifest ===
|
|
203
|
+
if (typeof managedManifest === 'string') {
|
|
213
204
|
manifest = JSON.parse(await fs.promises.readFile(managedManifest));
|
|
214
205
|
}
|
|
215
206
|
|
|
216
207
|
if (manifest.devDependencies) {
|
|
217
208
|
manifest.devDependencies = undefined;
|
|
218
209
|
}
|
|
219
|
-
manifest.packageManager = manifest.packageManager ??
|
|
210
|
+
manifest.packageManager = manifest.packageManager ?? 'npm@*';
|
|
220
211
|
|
|
221
212
|
await fs.promises.writeFile(
|
|
222
213
|
path.resolve(
|
|
223
214
|
outDir,
|
|
224
|
-
platform !==
|
|
225
|
-
?
|
|
226
|
-
:
|
|
227
|
-
|
|
215
|
+
platform !== 'osx'
|
|
216
|
+
? 'package.nw'
|
|
217
|
+
: 'nwjs.app/Contents/Resources/app.nw',
|
|
218
|
+
'package.json',
|
|
228
219
|
),
|
|
229
220
|
JSON.stringify(manifest, null, 2),
|
|
230
|
-
|
|
221
|
+
'utf8',
|
|
231
222
|
);
|
|
232
223
|
|
|
233
224
|
const cwd = path.resolve(
|
|
234
225
|
outDir,
|
|
235
|
-
platform !==
|
|
236
|
-
?
|
|
237
|
-
:
|
|
226
|
+
platform !== 'osx'
|
|
227
|
+
? 'package.nw'
|
|
228
|
+
: 'nwjs.app/Contents/Resources/app.nw',
|
|
238
229
|
);
|
|
239
230
|
|
|
240
|
-
if (manifest.packageManager.startsWith(
|
|
241
|
-
child_process.execSync(
|
|
242
|
-
} else if (manifest.packageManager.startsWith(
|
|
243
|
-
child_process.execSync(
|
|
244
|
-
} else if (manifest.packageManager.startsWith(
|
|
245
|
-
child_process.execSync(
|
|
231
|
+
if (manifest.packageManager.startsWith('npm')) {
|
|
232
|
+
child_process.execSync('npm install', { cwd });
|
|
233
|
+
} else if (manifest.packageManager.startsWith('yarn')) {
|
|
234
|
+
child_process.execSync('yarn install', { cwd });
|
|
235
|
+
} else if (manifest.packageManager.startsWith('pnpm')) {
|
|
236
|
+
child_process.execSync('pnpm install', { cwd });
|
|
246
237
|
}
|
|
247
238
|
};
|
|
248
239
|
|
|
249
240
|
const setLinuxConfig = async ({ app, outDir }) => {
|
|
250
|
-
if (process.platform ===
|
|
241
|
+
if (process.platform === 'win32') {
|
|
251
242
|
console.warn(
|
|
252
|
-
|
|
243
|
+
'Linux apps built on Windows platform do not preserve all file permissions. See #716',
|
|
253
244
|
);
|
|
254
245
|
}
|
|
255
246
|
let desktopEntryFile = {
|
|
256
|
-
Type:
|
|
257
|
-
Version:
|
|
247
|
+
Type: 'Application',
|
|
248
|
+
Version: '1.5',
|
|
258
249
|
Name: app.name,
|
|
259
250
|
GenericName: app.genericName,
|
|
260
251
|
NoDisplay: app.noDisplay,
|
|
@@ -281,7 +272,7 @@ const setLinuxConfig = async ({ app, outDir }) => {
|
|
|
281
272
|
|
|
282
273
|
await fs.promises.rename(`${outDir}/nw`, `${outDir}/${app.name}`);
|
|
283
274
|
|
|
284
|
-
let fileContent =
|
|
275
|
+
let fileContent = '[Desktop Entry]\n';
|
|
285
276
|
Object.keys(desktopEntryFile).forEach((key) => {
|
|
286
277
|
if (desktopEntryFile[key] !== undefined) {
|
|
287
278
|
fileContent += `${key}=${desktopEntryFile[key]}\n`;
|
|
@@ -314,7 +305,7 @@ const setWinConfig = async ({ app, outDir }) => {
|
|
|
314
305
|
});
|
|
315
306
|
|
|
316
307
|
const outDirAppExe = path.resolve(outDir, `${app.name}.exe`);
|
|
317
|
-
await fs.promises.rename(path.resolve(outDir,
|
|
308
|
+
await fs.promises.rename(path.resolve(outDir, 'nw.exe'), outDirAppExe);
|
|
318
309
|
const exe = peLibrary.NtExecutable.from(await fs.promises.readFile(outDirAppExe));
|
|
319
310
|
const res = peLibrary.NtExecutableResource.from(exe);
|
|
320
311
|
// English (United States)
|
|
@@ -351,78 +342,13 @@ const setWinConfig = async ({ app, outDir }) => {
|
|
|
351
342
|
await fs.promises.writeFile(outDirAppExe, outBuffer);
|
|
352
343
|
};
|
|
353
344
|
|
|
354
|
-
const setOsxConfig = async ({ outDir, app }) => {
|
|
355
|
-
if (process.platform === "win32") {
|
|
356
|
-
console.warn(
|
|
357
|
-
"MacOS apps built on Windows platform do not preserve all file permissions. See #716",
|
|
358
|
-
);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
try {
|
|
362
|
-
const outApp = path.resolve(outDir, `${app.name}.app`);
|
|
363
|
-
await fs.promises.rename(path.resolve(outDir, "nwjs.app"), outApp);
|
|
364
|
-
if (app.icon !== undefined) {
|
|
365
|
-
await fs.promises.copyFile(
|
|
366
|
-
path.resolve(app.icon),
|
|
367
|
-
path.resolve(outApp, "Contents", "Resources", "app.icns"),
|
|
368
|
-
);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const infoPlistPath = path.resolve(outApp, "Contents", "Info.plist");
|
|
372
|
-
const infoPlistJson = plist.parse(await fs.promises.readFile(infoPlistPath, "utf-8"));
|
|
373
|
-
|
|
374
|
-
const infoPlistStringsPath = path.resolve(
|
|
375
|
-
outApp,
|
|
376
|
-
"Contents",
|
|
377
|
-
"Resources",
|
|
378
|
-
"en.lproj",
|
|
379
|
-
"InfoPlist.strings",
|
|
380
|
-
);
|
|
381
|
-
const infoPlistStringsData = await fs.promises.readFile(
|
|
382
|
-
infoPlistStringsPath,
|
|
383
|
-
"utf-8",
|
|
384
|
-
);
|
|
385
|
-
|
|
386
|
-
let infoPlistStringsDataArray = infoPlistStringsData.split("\n");
|
|
387
|
-
|
|
388
|
-
infoPlistStringsDataArray.forEach((line, idx, arr) => {
|
|
389
|
-
if (line.includes("NSHumanReadableCopyright")) {
|
|
390
|
-
arr[idx] =
|
|
391
|
-
`NSHumanReadableCopyright = "${app.NSHumanReadableCopyright}";`;
|
|
392
|
-
}
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
infoPlistJson.LSApplicationCategoryType = app.LSApplicationCategoryType;
|
|
396
|
-
infoPlistJson.CFBundleIdentifier = app.CFBundleIdentifier;
|
|
397
|
-
infoPlistJson.CFBundleName = app.CFBundleName;
|
|
398
|
-
infoPlistJson.CFBundleDisplayName = app.CFBundleDisplayName;
|
|
399
|
-
infoPlistJson.CFBundleSpokenName = app.CFBundleSpokenName;
|
|
400
|
-
infoPlistJson.CFBundleVersion = app.CFBundleVersion;
|
|
401
|
-
infoPlistJson.CFBundleShortVersionString = app.CFBundleShortVersionString;
|
|
402
|
-
|
|
403
|
-
Object.keys(infoPlistJson).forEach((option) => {
|
|
404
|
-
if (infoPlistJson[option] === undefined) {
|
|
405
|
-
delete infoPlistJson[option];
|
|
406
|
-
}
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
await fs.promises.writeFile(infoPlistPath, plist.build(infoPlistJson));
|
|
410
|
-
await fs.promises.writeFile(
|
|
411
|
-
infoPlistStringsPath,
|
|
412
|
-
infoPlistStringsDataArray.toString().replace(/,/g, "\n"),
|
|
413
|
-
);
|
|
414
|
-
} catch (error) {
|
|
415
|
-
console.error(error);
|
|
416
|
-
}
|
|
417
|
-
};
|
|
418
|
-
|
|
419
345
|
const buildNativeAddon = ({ cacheDir, version, platform, arch, outDir, nodeVersion }) => {
|
|
420
346
|
let nodePath = path.resolve(cacheDir, `node-v${version}-${platform}-${arch}`);
|
|
421
347
|
const cwd = path.resolve(
|
|
422
348
|
outDir,
|
|
423
|
-
platform !==
|
|
424
|
-
?
|
|
425
|
-
:
|
|
349
|
+
platform !== 'osx'
|
|
350
|
+
? 'package.nw'
|
|
351
|
+
: 'nwjs.app/Contents/Resources/app.nw',
|
|
426
352
|
);
|
|
427
353
|
|
|
428
354
|
child_process.execSync(`node-gyp rebuild --target=${nodeVersion} --nodedir=${nodePath}`, { cwd });
|
|
@@ -432,18 +358,18 @@ const compress = async ({
|
|
|
432
358
|
zip,
|
|
433
359
|
outDir,
|
|
434
360
|
}) => {
|
|
435
|
-
if (zip === true || zip ===
|
|
361
|
+
if (zip === true || zip === 'zip') {
|
|
436
362
|
const archive = archiver('zip');
|
|
437
363
|
const writeStream = fs.createWriteStream(`${outDir}.zip`);
|
|
438
364
|
archive.pipe(writeStream);
|
|
439
365
|
archive.directory(outDir, false);
|
|
440
366
|
archive.finalize();
|
|
441
|
-
} else if (zip ===
|
|
367
|
+
} else if (zip === 'tar') {
|
|
442
368
|
await tar.create({
|
|
443
369
|
gzip: false,
|
|
444
370
|
file: `${outDir}.tar`,
|
|
445
371
|
}, [outDir]);
|
|
446
|
-
} else if (zip ===
|
|
372
|
+
} else if (zip === 'tgz') {
|
|
447
373
|
await tar.create({
|
|
448
374
|
gzip: true,
|
|
449
375
|
file: `${outDir}.tgz`,
|