nw-builder 4.1.0 → 4.1.1

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/README.md CHANGED
@@ -11,6 +11,7 @@ Build [NW.js](https://github.com/nwjs/nw.js) applications for Mac, Windows and L
11
11
  - [Usage](https://github.com/nwutils/nw-builder#usage)
12
12
  - [Limitations](https://github.com/nwutils/nw-builder#limitations)
13
13
  - [API Reference](https://nwutils.io/nw-builder/global#nwbuild)
14
+ - [Migration Guide](https://github.com/nwutils/nw-builder#migration)
14
15
  - [Contributing](https://github.com/nwutils/nw-builder#contributing)
15
16
  - [License](https://github.com/nwutils/nw-builder#license)
16
17
 
@@ -112,30 +113,30 @@ For more options, check out the [API reference](https://nwutils.io/nw-builder/gl
112
113
 
113
114
  - #716 File permissions are incorrectly set for Linux or MacOS apps built on Windows platform.
114
115
 
115
- ## Migration to v4
116
+ ## Migration
117
+
118
+ Migrate from v3 to v4
116
119
 
117
120
  ### Update `nw-builder`
118
121
 
119
122
  With npm:
120
123
 
121
124
  ```shell
122
- npm update nw-builder@^4.0.3
125
+ npm update nw-builder@^4.1.1
123
126
  ```
124
127
 
125
128
  With yarn:
126
129
 
127
130
  ```shell
128
- yarn upgrade nw-builder@^4.0.3
131
+ yarn upgrade nw-builder@^4.1.1
129
132
  ```
130
133
 
131
134
  With pnpm:
132
135
 
133
136
  ```shell
134
- pnpm update nw-builder@^4.0.3
137
+ pnpm update nw-builder@^4.1.1
135
138
  ```
136
139
 
137
- > Note: `nw-builder` has been tested on Node 16 and 18 only.
138
-
139
140
  ### Update options
140
141
 
141
142
  Let's take an example of v3 code and migrate it to v4.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nw-builder",
3
- "version": "4.1.0",
3
+ "version": "4.1.1",
4
4
  "description": "Build NW.js desktop applications for MacOS, Windows and Linux.",
5
5
  "keywords": [
6
6
  "NW.js",
@@ -8,7 +8,16 @@
8
8
  "Desktop",
9
9
  "Application"
10
10
  ],
11
- "author": "nw-builder Authors",
11
+ "author": {
12
+ "name": "Steffen Müller",
13
+ "url": "https://www.mllrsohn.com/"
14
+ },
15
+ "contributors": [
16
+ {
17
+ "name": "The nw-builder Authors",
18
+ "url": "https://github.com/nwutil/nw-builder/graphs/contributors"
19
+ }
20
+ ],
12
21
  "license": "MIT",
13
22
  "exports": {
14
23
  "default": "./src/nwbuild.js"
@@ -31,7 +40,7 @@
31
40
  "test:unit": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
32
41
  "demo:esm": "cd e2e && node demo.js",
33
42
  "demo:cjs": "cd e2e && node demo.cjs",
34
- "demo:cli": "cd ./test && nwbuild ./nwapp/* --mode=build --version=latest --flavor=normal --platform=linux --arch=x64 --outDir=./build/cli"
43
+ "demo:cli": "cd e2e && nwbuild ./app/* --mode=build --version=0.73.0 --flavor=normal --platform=win --arch=x64 --outDir=./out --cacheDir=./tmp"
35
44
  },
36
45
  "devDependencies": {
37
46
  "eslint": "^8.34.0",
@@ -20,7 +20,7 @@ import { setWinConfig } from "./winCfg.js";
20
20
  * @param {object} app Multi platform configuration options
21
21
  * @return {Promise<undefined>}
22
22
  */
23
- const packager = async (
23
+ export const build = async (
24
24
  files,
25
25
  nwDir,
26
26
  outDir,
@@ -34,8 +34,14 @@ const packager = async (
34
34
  log.debug(`Copy ${nwDir} files to ${outDir} directory`);
35
35
  await cp(nwDir, outDir, { recursive: true });
36
36
 
37
- log.debug(`Copy ${nwDir} files to ${outDir} directory`);
37
+ log.debug(`Copy files in srcDir to ${outDir} directory`);
38
38
  for (let file of files) {
39
+ let filePath = "";
40
+ if (file.split("/").length === 2) {
41
+ filePath = file;
42
+ } else {
43
+ filePath = file.split("/").splice(2).join("/")
44
+ }
39
45
  log.debug(`Copy ${file} file to ${outDir} directory`);
40
46
  await cp(
41
47
  file,
@@ -44,10 +50,8 @@ const packager = async (
44
50
  platform !== "osx"
45
51
  ? "package.nw"
46
52
  : "nwjs.app/Contents/Resources/app.nw",
47
- ),
48
- {
49
- recursive: true,
50
- },
53
+ filePath,
54
+ )
51
55
  );
52
56
  }
53
57
 
@@ -72,5 +76,3 @@ const packager = async (
72
76
  await compress(outDir, zip);
73
77
  }
74
78
  };
75
-
76
- export { packager };
@@ -7,9 +7,9 @@ import { log } from "../log.js";
7
7
  * Generates a Desktop Entry file for Linux
8
8
  * https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html
9
9
  *
10
- * @param {object} app Multi platform configuration options
11
- * @param {string} outDir Directory which stores build artifacts
12
- * @return {undefined}
10
+ * @param {object} app Multi platform configuration options
11
+ * @param {string} outDir Directory which stores build artifacts
12
+ * @return {Promise<void>}
13
13
  */
14
14
  export const setLinuxConfig = async (app, outDir) => {
15
15
  if (platform === "win32") {
package/src/bld/winCfg.js CHANGED
@@ -37,17 +37,20 @@ const setWinConfig = async (app, outDir) => {
37
37
  });
38
38
 
39
39
  try {
40
- await rename(`${outDir}/nw.exe`, `${outDir}/${app.name}.exe`);
41
-
42
- await rcedit(`${outDir}/${app.name}.exe`, {
43
- "file-version": app.version,
44
- "icon": app.icon,
45
- "product-version": app.version,
46
- "version-string": versionString,
47
- });
40
+ const outDirAppExe = resolve(outDir, `${app.name}.exe`);
41
+ await rename(resolve(outDir, 'nw.exe'), outDirAppExe);
42
+ await rcedit(
43
+ outDirAppExe,
44
+ {
45
+ "file-version": app.version,
46
+ "icon": app.icon,
47
+ "product-version": app.version,
48
+ "version-string": versionString,
49
+ },
50
+ );
48
51
  } catch (error) {
49
52
  log.warn(
50
- "Unable to modify EXE. Ensure WINE is installed or build in Windows",
53
+ "Renaming EXE failed or unable to modify EXE. If it's the latter, ensure WINE is installed or build in Windows",
51
54
  );
52
55
  log.error(error);
53
56
  }
@@ -14,12 +14,21 @@ import { log } from "../log.js";
14
14
  */
15
15
  const decompress = async (platform, cacheDir, downloadUrl) => {
16
16
  try {
17
- if (downloadUrl === "https://dl.nwjs.io") {
17
+ if (
18
+ downloadUrl === "https://dl.nwjs.io" ||
19
+ downloadUrl === "https://npm.taobao.org/mirrors/nwjs" ||
20
+ downloadUrl === "https://npmmirror.com/mirrors/nwjs"
21
+ ) {
18
22
  if (platform === "linux") {
19
23
  await Decompress(resolve(cacheDir, "nw.tar.gz"), cacheDir);
20
24
  } else {
21
25
  await Decompress(resolve(cacheDir, "nw.zip"), cacheDir);
22
26
  }
27
+ } else if (
28
+ downloadUrl ===
29
+ "https://github.com/corwin-of-amber/nw.js/releases/download"
30
+ ) {
31
+ await Decompress(resolve(cacheDir, "nw.zip"), cacheDir);
23
32
  } else if (
24
33
  downloadUrl ===
25
34
  "https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download"
@@ -28,13 +28,25 @@ const download = (
28
28
  let url;
29
29
  let out;
30
30
  return new Promise((res, rej) => {
31
- if (downloadUrl === "https://dl.nwjs.io") {
31
+ if (
32
+ downloadUrl === "https://dl.nwjs.io" ||
33
+ downloadUrl === "https://npm.taobao.org/mirrors/nwjs" ||
34
+ downloadUrl === "https://npmmirror.com/mirrors/nwjs"
35
+ ) {
32
36
  url = `${downloadUrl}/v${version}/nwjs${
33
37
  flavor === "sdk" ? "-sdk" : ""
34
38
  }-v${version}-${platform}-${architecture}.${
35
39
  platform === "linux" ? "tar.gz" : "zip"
36
40
  }`;
37
41
  out = resolve(cacheDir, `nw.${platform === "linux" ? "tar.gz" : "zip"}`);
42
+ } else if (
43
+ downloadUrl ===
44
+ "https://github.com/corwin-of-amber/nw.js/releases/download"
45
+ ) {
46
+ url = `${downloadUrl}/nw-v${version}/nwjs-${
47
+ flavor === "sdk" ? "sdk-" : ""
48
+ }v${version}-${platform}-${architecture}.zip`;
49
+ out = resolve(cacheDir, `nw.zip`);
38
50
  } else if (
39
51
  downloadUrl ===
40
52
  "https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download"
@@ -46,9 +58,14 @@ const download = (
46
58
  }
47
59
 
48
60
  https.get(url, (response) => {
61
+ // For GitHub releases, we need to follow the redirect
49
62
  if (
50
63
  downloadUrl ===
51
- "https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download"
64
+ "https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download" ||
65
+ downloadUrl ===
66
+ "https://github.com/corwin-of-amber/nw.js/releases/download" ||
67
+ downloadUrl === "https://npm.taobao.org/mirrors/nwjs" ||
68
+ downloadUrl === "https://npmmirror.com/mirrors/nwjs"
52
69
  ) {
53
70
  url = response.headers.location;
54
71
  }
@@ -9,25 +9,37 @@ import { getManifest } from "./getManifest.js";
9
9
  * Get version specific release metadata
10
10
  *
11
11
  * @param {string} version NW version
12
+ * @param {string} platform NW platform
13
+ * @param {string} arch NW architecture
12
14
  * @param {string} cacheDir Directory to store NW binaries
13
15
  * @param {string} manifestUrl Url to manifest
14
16
  * @return {object} Version specific release info
15
17
  */
16
- export const getReleaseInfo = async (version, cacheDir, manifestUrl) => {
18
+ export const getReleaseInfo = async (
19
+ version,
20
+ platform,
21
+ arch,
22
+ cacheDir,
23
+ manifestUrl,
24
+ ) => {
17
25
  let releaseData = undefined;
26
+ let manifestPath = undefined;
27
+ if (platform === "osx" && arch === "arm64") {
28
+ manifestPath = resolve(cacheDir, "manifest.mac.arm.json");
29
+ } else {
30
+ manifestPath = resolve(cacheDir, "manifest.json");
31
+ }
18
32
  try {
19
- await access(resolve(cacheDir, "manifest.json"));
33
+ await access(manifestPath);
20
34
  log.debug(`Manifest file already exists locally under ${cacheDir}`);
21
35
  } catch (e) {
22
36
  log.debug(`Manifest file does not exist locally`);
23
37
  log.debug(`Downloading latest manifest file under ${cacheDir}`);
24
38
  const data = await getManifest(manifestUrl);
25
- await writeFile(resolve(cacheDir, "manifest.json"), data.slice(9));
39
+ await writeFile(manifestPath, data.slice(9));
26
40
  } finally {
27
41
  log.debug("Store manifest metadata in memory");
28
- let manifest = JSON.parse(
29
- await readFile(resolve(cacheDir, "manifest.json")),
30
- );
42
+ let manifest = JSON.parse(await readFile(resolve(manifestPath)));
31
43
  log.debug(`Search for ${version} specific release data`);
32
44
  if (version === "latest" || version === "stable" || version === "lts") {
33
45
  // Remove leading "v" from version string
package/src/nwbuild.js CHANGED
@@ -5,13 +5,14 @@ import { decompress } from "./get/decompress.js";
5
5
  import { download } from "./get/download.js";
6
6
  import { getReleaseInfo } from "./get/getReleaseInfo.js";
7
7
  import { remove } from "./get/remove.js";
8
- import { packager } from "./bld/package.js";
8
+ import { build } from "./bld/build.js";
9
9
  import { develop } from "./run/develop.js";
10
10
  import { isCached } from "./util/cache.js";
11
11
  import { replaceFfmpeg } from "./util/ffmpeg.js";
12
12
  import { getOptions } from "./util/options.js";
13
13
  import { parse } from "./util/parse.js";
14
14
  import { validate } from "./util/validate.js";
15
+ import { xattr } from "./util/xattr.js";
15
16
 
16
17
  import { log } from "./log.js";
17
18
 
@@ -62,7 +63,7 @@ import { log } from "./log.js";
62
63
  * @property {"latest" | "stable" | string} [version="latest"] NW runtime version
63
64
  * @property {"normal" | "sdk"} [flavor="normal"] NW runtime build flavor
64
65
  * @property {"linux" | "osx" | "win"} platform NW supported platforms
65
- * @property {"ia32" | "x64"} arch NW supported architectures
66
+ * @property {"ia32" | "x64" | "arm64"} arch NW supported architectures
66
67
  * @property {string} [outDir="./out"] Directory to store build artifacts
67
68
  * @property {"./cache" | string} [cacheDir="./cache"] Directory to store NW binaries
68
69
  * @property {"https://dl.nwjs.io"} [downloadUrl="https://dl.nwjs.io"] URI to download NW binaries from
@@ -110,6 +111,8 @@ const nwbuild = async (options) => {
110
111
  // Validate options.version to get the version specific release info
111
112
  releaseInfo = await getReleaseInfo(
112
113
  options.version,
114
+ options.platform,
115
+ options.arch,
113
116
  options.cacheDir,
114
117
  options.manifestUrl,
115
118
  );
@@ -121,7 +124,8 @@ const nwbuild = async (options) => {
121
124
  // Variable to store nwDir file path
122
125
  nwDir = resolve(
123
126
  options.cacheDir,
124
- `nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${options.platform
127
+ `nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${
128
+ options.platform
125
129
  }-${options.arch}`,
126
130
  );
127
131
 
@@ -147,7 +151,9 @@ const nwbuild = async (options) => {
147
151
  }
148
152
 
149
153
  if (options.ffmpeg === true) {
150
- log.warn("Using MP3 and H.264 codecs requires you to pay attention to the patent royalties and the license of the source code. Consult a lawyer if you do not understand the licensing constraints and using patented media formats in your app. See https://chromium.googlesource.com/chromium/third_party/ffmpeg.git/+/master/CREDITS.chromium for more information.");
154
+ log.warn(
155
+ "Using MP3 and H.264 codecs requires you to pay attention to the patent royalties and the license of the source code. Consult a lawyer if you do not understand the licensing constraints and using patented media formats in your app. See https://chromium.googlesource.com/chromium/third_party/ffmpeg.git/+/master/CREDITS.chromium for more information.",
156
+ );
151
157
  if (options.platform === "win") {
152
158
  ffmpegFile = "libffmpeg.dll";
153
159
  } else if (options.platform === "osx") {
@@ -189,11 +195,13 @@ const nwbuild = async (options) => {
189
195
  }
190
196
  }
191
197
 
198
+ await xattr(options.platform, options.arch, nwDir);
199
+
192
200
  if (options.mode === "run") {
193
201
  await develop(options.srcDir, nwDir, options.platform, options.argv);
194
202
  }
195
203
  if (options.mode === "build") {
196
- await packager(
204
+ await build(
197
205
  files,
198
206
  nwDir,
199
207
  options.outDir,
package/src/util/arch.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Get user's computer architecture
3
3
  *
4
- * @param {string} arch Node's process.arch
5
- * @return {"ia32"| "x64" | "string"} NW.js supported architectures
4
+ * @param {string} arch Node's process.arch
5
+ * @return {"ia32"| "x64" | "arm64" | "string"} NW.js supported architectures
6
6
  */
7
7
  export const getArch = (arch) => {
8
8
  return arch;
@@ -1,5 +1,5 @@
1
1
  import { readFile } from "node:fs/promises";
2
- import { basename, resolve } from "node:path";
2
+ import { basename } from "node:path";
3
3
 
4
4
  import glob from "glob-promise";
5
5
 
@@ -26,10 +26,6 @@ export const getOptions = async (opts) => {
26
26
  files = [...patterns];
27
27
  }
28
28
 
29
- files.forEach((file, index) => {
30
- files[index] = resolve(file);
31
- });
32
-
33
29
  // Try to find the first instance of the package.json
34
30
  for (const file of files) {
35
31
  if (basename(file) === "package.json" && nwPkg === undefined) {
@@ -0,0 +1,17 @@
1
+ {
2
+ "latest": "v0.70.0",
3
+ "stable": "v0.70.0",
4
+ "lts": "v0.70.0",
5
+ "versions": [
6
+ {
7
+ "version": "v0.70.0",
8
+ "date": "2022/11/30",
9
+ "files": ["osx-arm64"],
10
+ "flavors": ["normal", "sdk"],
11
+ "components": {
12
+ "node": "19.0.0",
13
+ "chromium": "107.0.5304.88"
14
+ }
15
+ }
16
+ ]
17
+ }
package/src/util/parse.js CHANGED
@@ -16,17 +16,19 @@ export const parse = async (options, pkg) => {
16
16
  options = { ...pkg.nwbuild };
17
17
  }
18
18
 
19
- options.srcDir = resolve(options.srcDir) ?? resolve("./*");
19
+ console.log(options.cacheDir);
20
+
21
+ options.srcDir = resolve(options.srcDir ?? "./*");
20
22
  options.mode = options.mode ?? "build";
21
23
  options.version = options.version ?? "latest";
22
24
  options.flavor = options.flavor || "normal";
23
25
  options.platform = options.platform ?? getPlatform(platform);
24
26
  options.arch = options.arch ?? getArch(arch);
25
- options.outDir = resolve(options.outDir) ?? resolve("./out");
26
- options.cacheDir = resolve(options.cacheDir) ?? resolve("./cache");
27
+ options.outDir = resolve(options.outDir ?? "./out");
28
+ options.cacheDir = resolve(options.cacheDir ?? "./cache");
27
29
  options.downloadUrl = options.downloadUrl ?? "https://dl.nwjs.io";
28
30
  options.manifestUrl = options.manifestUrl ?? "https://nwjs.io/versions";
29
- options.app = {};
31
+ options.app = options.app ?? {};
30
32
  options.argv = options.argv ?? [];
31
33
  // linux desktop entry file configurations options
32
34
  options.app.name = options.app.name ?? pkg.name;
@@ -0,0 +1,30 @@
1
+ import { exec } from "node:child_process";
2
+ import { resolve } from "node:path";
3
+
4
+ import { log } from "../log.js";
5
+
6
+ /**
7
+ * Remove the quarantine attribute from the app bundle
8
+ *
9
+ * @param {string} platform - The platform to build for
10
+ * @param {string} arch - The arch to build for
11
+ * @param {string} nwDir - The path to the nw directory
12
+ * @return {Promise<void>} - A promise that resolves when the attribute is removed
13
+ */
14
+ export const xattr = (platform, arch, nwDir) => {
15
+ return new Promise((res, rej) => {
16
+ if (platform === "osx" && arch === "arm64") {
17
+ let app = resolve(nwDir, "nwjs.app");
18
+ exec(`sudo xattr -d com.apple.quarantine ${app}`, (err, stdout) => {
19
+ log.debug(stdout);
20
+ if (err) {
21
+ rej(err);
22
+ } else {
23
+ res();
24
+ }
25
+ });
26
+ } else {
27
+ res();
28
+ }
29
+ });
30
+ };