nodejs local vs target development workflow advice

Hi. I have followed the nodejs/rpi3 getting started guide Get started on developing with Raspberry Pi 3 and Node.js - Balena Documentation and got the hello world app running on a compute module.
GitHub - balena-io-examples/balena-nodejs-hello-world: Example of how to deploy Node code on a balena supported device.

I’ve gone so far as to extend the GitHub - balena-io-examples/balena-ts-node-hello-world: A simple TypeScript Node.js Express server example to implement the onoff module (dependent on epoll) and am able to turn led’s on and off from gui controls on a hosted page.

But now that I am using the onoff (epoll) modules for hardware interaction, ‘npm install’ won’t work on my local machine. I want to add chart.js (and likely many more modules) to my project.

So specific question is: how do I ‘npm install chart.js’ in my project?

When I run it on my development machine I get node gyp errors because epoll needs to be compiled on the rpi target.

(base) % npm install chart.js
npm WARN read-shrinkwrap This version of npm is compatible with lockfileVersion@1, but package-lock.json was generated for lockfileVersion@2. I’ll try to do my best with it!

epoll@4.0.1 install …/node_modules/epoll
node-gyp rebuild

A more abstract question is, how should I manage the development of a client (browser) and server (rpi target specific)? Suggestions welcome…


Welcome to the forums

This seems like a tricky situation.

I checked and it seems npm still does not have a way to only add a dependency without installing

Can you please try using the add-dependencies package?
You can run npx add-dependencies chart.js from the root of your project where your package.json is.

A more abstract question is, how should I manage the development of a client (browser) and server (rpi target specific)? Suggestions welcome…

We are aware of the friction in developing with such a use case. We have several ideas we are exploring one of which is to provide a IDE on the device itself(RPi in this case) where you would be able to edit the source code directly on the target and not run into such issues. However, this is still in the early phase of ideation.

For now, maybe you can try local mode which allows to develop directly on the device with instant reloading functionality Develop locally - Balena Documentation

Let us know if this is helpful


If you have any ideas on what would work for you you can come and post them here, it would be great to get your input: Development workflows - mount a folder from your device to your local system for development and testing - #5 by Maggie

@ikellymo Are you using this npm module for onoff? onoff - npm
I was using that for dev with a motion sensor that would trigger the LEDs
I just created a motionSensorFake function in order to develop other parts of the app locally.
You could do some kind of featureFlag or something like:

if (host !== 'localhost') {
  const { motionSensor } = require('./motion-sensor');
} else {
  const { motionSensorFake } = require('./motion-sensor');

You can also use local mode and install packages directly on the device if you need to just test to see if it works before rebuilding your docker  ```balena ssh deviceid.local service```

Also you could potentially use nvm to manage node versions and have that in your docker file for example:

nvm install 18

Here's a Dockerfile.template for a project with working node-gyp and onoff

FROM balenalib/%%BALENA_MACHINE_NAME%%-debian-node:${NODEJS_VERSION}-bookworm

RUN apt-get update
&& apt-get install --no-install-recommends -y python3 build-essential
&& apt-get clean

WORKDIR /usr/src/app

COPY package*.json ./

COPY . ./

RUN yarn global add node-gyp --network-timeout 600000
RUN yarn install --network-timeout 600000
RUN yarn cache clean


CMD [“npm”, “start”]