Why doesn't my nodejs snap create a binary?

I did the hello world and “chuck norris” tutorials on tutorials.ubuntu.com to familiarize myself with building and running snaps. I then wrote snapcraft.yaml files for two nodejs apps I have. One is much simpler than the other. It has only 1 dependency (like the chuck norris tutorial), and when I build it with snapcraft prime it does build a binary in prime/bin.
The other nodejs I want to make a snap of is more complicated and has 5 npm dependencies, including noble and bluetooth-hci-socket (which has shown issues installing in the past). When I snapcraft prime this application, it does not build a binary in prime/bin.

So I’m wondering, because I haven’t been able to find it in documentation: what is required for a nodejs snap to build a binary, and is it ok that I was not warned in the console output that a binary could not be created?

I would think the answer to the latter is “no”, because my more complicated nodejs snap does not run, where the simpler nodejs snap does. The error I receive with the more complicated one is “Module version mismatch. Expected 48, got 46.” Internet searches tell me this is likely related to an outdated dependency, but snap is supposed to manage the dependencies, so I’m at a loss.

Hi @spencer-rig. Can you provide a gist of your snapcraft.yaml?

@evan snapcraft.yaml: https://pastebin.com/p4qP4d7g
package.json: https://pastebin.com/FPeE2QeR

There’s a slight issue in the package.json I’ve corrected, which is to change the bin value to server.js (so that the npm run command will start the server).

I’m not sure what change did it, but now I am seeing a binary show up in prime/bin. I’m still concerned that snapcraft prime never alerted me to the fact the binary wasn’t created. Is there a difference between the app’s command being, e.g. bin/my-binary vs bin/npm run?

If you had used bin/my-binary and my-binary was not created you would of resulted in an error whereas if you used command: bin/npm run my-binary you would have not as bin/npm would have probably existed whilst my-binary (or target) would have not and we do not do semantic parsing of the value of command

I ran into this as well. So, when we use the nodejs plugin,

unless we specify a node version greater than 7.x , the bundled npm version is 3.x

some dependencies, need npm 5 and later.

Now, as soon as snapcraft finds a package,json , it starts installing all listed dependencies.

The only option as of now, is for the developer to have a prepare scriptlet to run before a build

where, he runs npm cache clean --force , npm install -g npm , npm update and npm rebuild.

followed by , rm -rf node_modules and npm install

Now the problem is, the entire dependency chain is being installed twice.

nodejs and npm dependencies, are famous for being extremely picky , moody and extremely slow to install.

In cases where the package.json is huge, the time taken for an avg npm install to complete is 60 to 90 minutes.

This is kind of avoidable isn’t it?

would be great, if snapcraft, can run npm install -g npm and npm update -g npm and npm rebuild

before it attempts to install in the first place.

In my case, It also required an electron rebuild everytime npm install happened, so I was looking at build times upwards of 100 to 120 minutes for 1 run. Actual times were 200 minutes on avg (network/host issues accounted too)

my issue with launchpad and nodejs plugins

Hmm, would it be worth it if the plugin always updates to the latest npm?

That is debatable considering node and npm are volatile in dependency management.

But in my case, I was / am still snapping atom as a learning experience for building snaps.

And atom says, install node v 6.x and upgrade npm before you build.

tough call to make for snapcraft though :slight_smile:

But I am hoping npm is backwards compatible.

The best possible solution may be, snapcraft introducing an optional scriptlet before it installs from package.json?

Yes, which is my worry.
We can flag the need for an update or the fact that we don’t want to update (whichever is more common should be the default). Or if the tooling allows, allow you to specify the version of npm you want to use.

1 Like