Getting NW.js to run on Windows

by | Oct 22, 2020 | Development | 0 comments

I recently convinced my boss to sign me up for Davide Barranca‘s Native Photoshop Apps video course. It was made primarily with macOS users in mind, but I perform all of my development on Windows. I thought it wouldn’t be a big deal, since I use Ubuntu with WSL for most of my dev work, which means I can still use all of the same command-line tools such as apt, git, Node.js, etc. I don’t even have to modify most of the instructions in online tutorials to get them to work on my machine.

Almost halfway through the video course, however, I ran into a problem getting NW.js to run.

If, like me, you need to get NW.js to run and display your app from Windows—whether or not you’re watching Davide’s course—then this article may help you.


Context Matters

TL;DR:
Don’t use WSL. Do all your work from Windows (PowerShell recommended).

I had been following along with Davide’s course diligently and everything was working fine. Since I do all of my web development work from WSL, I didn’t have much of a concern that it would pose a problem on this project.

During video #11—NWjs Setup—I discovered that I would be wrong. I got to the point where I should attempt to run nwjs-builder-phoenix, but was greeted with an error.

$ ./node_modules/.bin/run ./nwdev
Fetching NW.js binary... { platform: 'linux', arch: 'x64', version: '0.49.0', flavor: 'sdk' }
Launching NW.js app...
NW.js app exited with 127.
Time: 0h:00m:03s

I contacted Davide to see if he knew how to avoid this error, but as a macOS developer, he did not. He only suggested that I make sure my manifest (package.json file) was correct, try an earlier version of NW.js, manually build and package the app (avoiding nwjs-builder-phoenix for the time being), and remove a <a href="http://docs.nwjs.io/en/latest/References/Manifest%20Format/#product_string" data-type="URL" data-id="http://docs.nwjs.io/en/latest/References/Manifest%20Format/#product_string" target="_blank" rel="noreferrer noopener">product_string</a> option from my manifest if it was there (since it had caused him problems on macOS).

None of those suggestions seemed to help. He did ask a question, however, that I didn’t think much about at the time: “By the way, how can you make a Linux app and then connect to PS on Win/Mac?” Turns out, I should have given that more thought.

You see, I had completely glossed over parts of that output of nwjs-builder-phoenix. Specifically, platform: 'linux' and Launching NW.js app...

It was attempting to launch a Windows app from Linux.


Solution #1 – Use WSL for development, Windows for running NW.js

Once I came to this realization, I knew I had to run that Node command from Windows. So, I launched PowerShell, navigated to \\wsl$\Ubuntu-20.04\home\<username>\dev\projects\js-ps-app, and tried to run it from there:

PS> .\node_modules\.bin\run .\nwdev

However, this just launched a dialog asking how I wanted to open “this” file. It was not running the “run” file with Node, it was trying to open “run” somehow. By the way, that “run” file is just a symlink to ../nwjs-builder-phoenix/dist/bin/run.js, so I tried accessing that directly:

PS> .\node_modules\nwjs-builder-phoenix\dist\bin\run.js .\nwdev

And it just opened up that run.js file in my default text editor. So I tried using Node directly to see if that worked:

PS> node .\node_modules\.bin\run .\nwdev
internal/fs/utils.js:269
    throw err;
    ^

Error: EISDIR: illegal operation on a directory, lstat '\\wsl$\Ubuntu-20.04\home\<username>\dev\projects\js-ps-app\node_modules\.bin\run'
    at Object.realpathSync (fs.js:1643:7)
    at toRealPath (internal/modules/cjs/loader.js:356:13)
    at Function.Module._findPath (internal/modules/cjs/loader.js:512:22)
    at resolveMainPath (internal/modules/run_main.js:12:25)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:54:24)
    at internal/main/run_main_module.js:17:47 {
  errno: -4068,
  syscall: 'lstat',
  code: 'EISDIR',
  path: '\\\\wsl$\\Ubuntu-20.04\\home\\<username>\\dev\\projects\\js-ps-app\\node_modules\\.bin\\run'
}

It still doesn’t like Linux symlinks. How about if I skipped the symlink and tried running the script directly?

PS> node .\node_modules\nwjs-builder-phoenix\dist\bin\run.js .\nwdev
Error: Cannot find module '7zip-bin-win'
Require stack:
- \\wsl$\Ubuntu-20.04\home\<username>\dev\projects\js-ps-app\node_modules\7zip-bin\index.js
- \\wsl$\Ubuntu-20.04\home\<username>\dev\projects\js-ps-app\node_modules\nwjs-builder-phoenix\dist\lib\util\archive.js
- \\wsl$\Ubuntu-20.04\home\<username>\dev\projects\js-ps-app\node_modules\nwjs-builder-phoenix\dist\lib\util\index.js
- \\wsl$\Ubuntu-20.04\home\<username>\dev\projects\js-ps-app\node_modules\nwjs-builder-phoenix\dist\lib\common\DownloaderBase.js
- \\wsl$\Ubuntu-20.04\home\<username>\dev\projects\js-ps-app\node_modules\nwjs-builder-phoenix\dist\lib\Downloader.js
- \\wsl$\Ubuntu-20.04\home\<username>\dev\projects\js-ps-app\node_modules\nwjs-builder-phoenix\dist\lib\Runner.js
- \\wsl$\Ubuntu-20.04\home\<username>\dev\projects\js-ps-app\node_modules\nwjs-builder-phoenix\dist\lib\index.js
- \\wsl$\Ubuntu-20.04\home\<username>\dev\projects\js-ps-app\node_modules\nwjs-builder-phoenix\dist\bin\run.js
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:831:15)
    at Function.Module._load (internal/modules/cjs/loader.js:687:27)
    at Module.require (internal/modules/cjs/loader.js:903:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at Object.<anonymous> (\\wsl$\Ubuntu-20.04\home\sturm\dev\projects\js-ps-app\node_modules\7zip-bin\index.js:15:67)
    at Module._compile (internal/modules/cjs/loader.js:1015:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1035:10)
    at Module.load (internal/modules/cjs/loader.js:879:32)
    at Function.Module._load (internal/modules/cjs/loader.js:724:14)
    at Module.require (internal/modules/cjs/loader.js:903:19)

Ah, now we’re getting somewhere. Although I did have Node installed on Windows, I was missing a Windows-specific dependency.

PS> npm install --save-dev 7zip-bin-win

After installing the dependency, I gave it another go, and it worked.

So, I finally had a solution. It was a bit quirky and required that I run NW.js from Windows, not WSL. I could still do all of my other development work from WSL, though. In addition, the command I had to run was also rather annoying. Granted, this would be taken care of in the next step of Davide’s video, but for now, I though there must be a better way.


Solution #2 – Ditch WSL, use Windows

I wondered why I should even use WSL for most of the development. What was I gaining from it on this project? I couldn’t come up with a good answer, so I just cloned my repository into a Windows-native directory (i.e., not inside \\wsl$\) and tried it from there:

PS> .\node_modules\.bin\run .\nwdev

Success!

One last bit of info is that the forward slashes have to be turned into backslashes in package.json since we’re on a Windows context now. And as we’re calling concurrently in quotes, we have to escape each of those backslashes with a second backslash. Thus, Davide’s "nwdev" entry becomes:

"scripts": {
...
    "nwdev": "concurrently --kill-others --raw \"npm run serve\" \".\\node_modules\\.bin\\run .\\nwdev\""
},

Conclusion

As much as I don’t want to recommend it, I’m afraid that we have to run NW.js from within the native operating system, so that means us Windows developers must set aside WSL for projects that use NW.js.

Related Posts:

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *