Explore best practices for building and deploying Node.js projects on Raspberry Pi. Overcome common challenges and keep your project running smoothly with our expert tips and tricks.
Last Christmas I received a gift so fascinating that it occupied many of my weekends and even kept me up at night. It's the new Raspberry Pi Zero.
It opened up endless possibilities and couldn't help but occupy my mind, so the only obvious course of action I took was to throw it in a drawer and slowly move away from it. A few months later, I read an excellent article by fellow double agent Adam Lukens. That article gave me the boost I needed to roll up my sleeves, dust off my Raspberry Pi, and get to work. For an extra challenge, I decided to add Node.js to my project. I call it Tot Tunes.
Tot Tunes:https://github.com/pingortle/tot-tunes
It only took me an hour or two to build a working prototype and briefly feel like a superhero. Then I found a bug. I fixed that bug, but a bunch of other little issues popped up. What if the power goes out or is unplugged? So I went through a series of learnings and built a library of tools for my small projects. I want to share more than just the experience of building Tot Tunes itself. This is thanks to Adam's detailed article. I want to lower the barrier to entry so more people can build great products and run them with confidence without having to go through the pain I experienced with my projects.
If you want to build something while reading this article, you'll need a Raspberry Pi with Raspbian installed, a reasonable grasp of JavaScript basics, and Node.js installed. We'll also do a little shell scripting.
I built a Node.js project
You probably have a little project you've been dying to build, and if not, I've got a simple Node.js service for you. Please go here to clone the project and follow the instructions in the readme file to set it up.
project:https://github.com/pingortle/til-node-raspberry-pi-delivery
How to deploy?
The most obvious way to deploy a Node.js project is to install Node.js on your Raspberry Pi and start writing code. Some workflows might be well-suited to this approach, but I know I'll quickly miss the power and convenience of a laptop. Another common method is to write the code on your laptop, then copy the code to the Raspberry Pi and run npm install && npm start. Every time you update your code, just copy the code and restart the service. While this isn't the worst situation in the world, I think there must be another, better way. One of the issues is that I am limited by the Node.js version available in the Raspbian package repository, as I would like to use a newer version of Node.js for improved performance and functionality.A common way to solve this problem is to use a tool like nodenv to manage Node.js versions. But I realized there were different options. Do I continue to manage all this infrastructure on the Raspberry Pi, or try to find an easier way? I recently heard about a project that bundles packages with the Node.js runtime so that you can distribute your application as a standalone executable. This ended up solving a lot of my problems. You can find the tool at zeit/pkg on GitHub. Since I'm dealing with binary executables now, I know I need to get a Linux binary for the Raspberry Pi CPU architecture. Preliminary testing showed that, in theory, pkg supports these constraints, but an error message appeared.
nodenv:https://github.com/nodenv/nodenv
zeit/pkg:https://github.com/vercel/pkg
mistake! Can't build for 'armv7' here, only for 'x64'
After some digging I found the comments for this issue on github. It shows that as long as my dependencies are pure JavaScript, I can tell pkg not to compile the results to bytecode via a flag, i.e. pkg ... --no-bytecode. The build was successful so I copied the binaries to the Raspberry Pi. It works! I no longer have to worry about synchronizing deployment and development versions of Node.js. I can check these configurations directly into git.
Question comments:https://github.com/vercel/pkg/issues/145#issuecomment-311150484
it works! But it just collapsed...
I live near Tornado Alley. Luckily, there's never really been a tornado in my neighborhood. But unfortunately, every year a storm comes and then the power goes out. Sometimes it's just a brief outage caused by a voltage fluctuation, but regardless, my Raspberry Pi without a battery will restart without warning. The point is, my Raspberry Pi service needs to be ready for whatever mother nature throws at it. Since I'm using Raspbian, systemd seems like the right tool for the job. I have no idea how to write systemd services, but this seemed like the perfect excuse to learn. It's actually very easy to make! The command line interface is very intuitive and all you need to do is create a file that describes how to run the service.
[Unit]
Description=Tot Tunes
[Service]
User=pi
ExecStart=/usr/local/bin/tot-tunes
Type=simple
Restart=always
[Install]
WantedBy=multi-user.target
Place this file in the /etc/systemd/system/ directory. Then run the following command.
systemctl daemon-reload
systemctl enable tot-tunes.service
service tot-tunes start
With this simple configuration, you can have a service that automatically restarts on reboots and crashes. Additionally, it provides easy access to the application's logs via the journalctl interface.
Mission accomplished?
Developing on a Raspberry Pi (Raspberry Pi) project is fun and a little addictive. But if you're like me, we're also eager to have a life outside of our little IoT overlords, so don't always have the time to spend hours learning a new operating system or programming language.
We need to implement an idea quickly so we can get on with our lives with just a little more JS automation, because you can never have too much JS.
While I chose Node.js in part as a fun challenge, I think it has other advantages for those new to IoT. On the one hand, almost everyone knows a little bit of JS, so this is an avenue for people who want to become more productive quickly. If you're not a fan of JS, there are tons of tools to help you write TypeScript, CoffeeScript, and many other languages that compile to JS. npm has thousands of packages, so you can build on the work of others, and pkg allows us to package all of this into an executable binary without installing any necessary dependencies.
Even though there are good reasons to use Node.js and pkg on your next Raspberry Pi project, you still want to weigh the costs and benefits before committing to the platform. Node.js is a fairly large dependency and including the runtime environment in the binary creates over 30MB of files. This slows down deployment because you have to transfer the entire binary, not just some text files. Additionally, like any interpreted language, you may encounter situations where application performance is unacceptable.
This setup is great for starting a simple service, but I think we can continue to improve the Raspberry Pi and Node.js experience. One of the biggest paradoxes when building software for the Raspberry Pi is that you can get fast and higher-fidelity feedback by developing on the device itself, but you may not have all the great tools you're used to using. If you choose to build software from the comfort of your laptop, you'll likely experience the pain of waiting for deployment every time you want to test your code on your Raspberry Pi.
Another frustration is the tediousness of setting up service configurations. The process of manually editing files on a Raspberry Pi can easily eat up hours of time that you could be spending building something you love. A related issue is distribution. What if your non-technical friends came over and noticed your cool new gadget? What if you built a project for someone else and need to update it?
This field is full of opportunities, and I'm excited to continue learning, building, and sharing with you. If you are doing exciting things with the Raspberry Pi and these resonate with you, please contact me! Follow Raspberry Pi developers to learn more about Raspberry Pi!