Every app needs random data at some point, but what if that random data also needs to be real? That’s the challenge I ran into when generating test addresses for one of my clients. Since we wanted to plot these addresses on the map, they had to be real, physical places.
Oh, and I needed to geocode them, too, back to their lat-long coordinates.
Thanks in large part to Node and the huge collection of packages on npm, it only took me about 15 minutes to come up with a solution that worked great. In this series of posts, we’ll cover that app from start to finish.
Let’s start this series by looking at the absolute basics of creating a command-line app with Node.
Why Node?
One of the things I love most about Node is that it is ridiculously easy to create small apps that solve specific problems. It’s much lighter-weight than a .NET console app, and (in my opinion) cleaner and easier to use than a PowerShell script. There’s also a slew of packages you can use to solve common problems, too, and we’ll be using several of those in future posts.
The Challenge
Let’s kick things off by talking about what we are going to build, and why.
So here we are, trying to test out a new app before we have any customers or any real data. The app shows things overlayed on a Google Map, and we wanted to generate some pseudo-random data. Normally, generating random test data is pretty easy, and there are plenty of libraries and tools for that sort of thing.
But this was different. We couldn’t just ask Google Maps to plot made-up random addresses. They needed to be real places, just chosen at random. And our app needed those places to have corresponding lat-long coordinates, too.
Node to the Rescue
Creating simple command-line apps with Node is a breeze. Let’s go ahead and stub out our new project.
First, we’ll need a folder…
mkdir address-generator
cd address-generator
Now let’s initialize it with npm…
> npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help json` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
name: (address-generator)
version: (1.0.0)
description: Generates random (real) US street addresses.
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to E:\Projects\address-generator\package.json:
{
"name": "address-generator",
"version": "1.0.0",
"description": "Generates random (real) US street addresses.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Making A Command-Line App
Now here’s the cool part. We can easily make our app into a command-line tool by making one small tweak to our package.json file. We just add a “bin” section with the name we want to give our tool!
{
"name": "address-generator-2",
"version": "1.0.0",
"description": "Generates random (real) US street addresses.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
//Here's the bit we added!
"bin": {
"generate-address": "./index.js"
}
}
See what we added? The “bin” section defines “generate-address”, and says that should execute a script, index.js.
So now when our app is installed (more on that in a sec), we’ll be able to run generate-addresss
from the command line!
Of course, if we were to try to run this now, it’s not going to work, because we haven’t created the file index.js yet. Let’s do that now.
Stubbing Out Our App
Create index.js in the root of your project. Here’s what my workspace looks like in VS Code (Pumpkin Edition):
Now we just need to throw in some code…
#!/usr/bin/env node
console.log('Hello, world!');
That first line may look a little strange, but we’ll come back to that in a second.
All we need to do now is actually install our app. That’s actually easy, we can do it by running the following npm command in the root of our workspace.
npm i -g
The
i
is short forinstall
, and the-g
tells npm to install the package globally.
Now we can execute our new app from the command-line. On Windows, that looks like this:
> generate-address.cmd
Hello, world!
Success!
But how?
Well…
Behind the Scenes
When we ran npm i -g
, npm created a wrapper cmd
file for us. If you’re on Windows 10, that will be located at %AppData%\npm\
. The contents of that wrapper generate-address.cmd
file will look something like this:
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\node_modules\address-generator\index.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\node_modules\address-generator\index.js" %*
)
That’s a lot of noise, but basically, it calls node.exe
and tells it to execute our script. ?
But About That Shebang Line…
Remember that funky-looking line we put at the top of our JavaScript file? That’s called a Shebang. You’ve seen that before if you’ve ever worked on a *nix-based system. On those systems, it tells the program loader which program to use to execute the script. Windows doesn’t do this.
But npm does.
When we ran npm i -g
, npm looked at our package.json file, saw the bin
entry we made, then checked the target script. It saw the shebang statement, and figured out that we wanted our script to be executed with node.
What would have happened if we omitted that line? Let’s find out!
Take Away the Shebang…
Let’s just remove that shebang line complete…
//No shebang here!
console.log('Hello, world!');
And re-install our script…
npm -i g
Now if we take a look at the cmd wrapper that was generated, we’ll see that it just tries to run the script without node!
@"%~dp0\node_modules\address-generator\index.js" %*
Windows actually has a script host built-in that’s capable of running JScript (which is different from JavaScript!), and that’s (probably) what will run. Which, ya know, totally won’t work the way we want it to:
So, remember: that shebang line is really important when building command-line apps with node!
Up Next
That’s all we’re going to cover for this post. We’ve got our project, and we’ve seen how things get wrapped to create an app. In the next post, we’ll start actually implementing our address generator!