Access variables in npm scripts

Increase the flexibility of your npm scripts

A while ago, almost all build tasks were managed by tools like grunt or gulp.

Depending on the project, people needed to understand the configurations and structures of the build tool which introduced some unnecessary complexity.

Since almost everybody is using npm as their package manager, it makes sense to profit from its ability to run scripts. npm scripts are managed inside our package.json and can be executed with the npm run command.

Compared to grunt or gulp files, they are easier to understand and maintain.

Flexible npm scripts

What do we mean when we talk about flexible npm scripts? We talk about scripts that can access variables and pass them to another script. Let’s have a look at the following graphic, which illustrates this concept further.

We have an environment with a variable. In this example, a variable called A which has the value 5. We want to pass in this variable to our npm script, access it, and pass it to the third-party library which we call in our script.

To illustrate how this concept can be implemented, we are going to use a simple use case that you are probably all familiar with. Serving a simple webpage over an HTTP server.

Serving HTML pages on different ports 🍸

Let’s imagine we have the following static HTML page which we want to serve.

<html>
<body>
<h1>Testpage</h1>
...
</body>
</html>

The first thing we need is a web server. So, let’s go ahead and grep one. I favor the http-server package.

npm i -D http-server

To start our page, we also add a simplestart task to the scripts section in our package.json.

"start": "http-server"

If we now open a terminal of our choice and type npm run start an HTTP server starts up and serves our index.html on port 8080 which is the default port the http-server package uses.

So what if for some reason we need to start up our application on another port than 8080?

Let’s first check the docs of our http-server module. We can see that we can specify the port via -p flag. Ok, easy, we can go on and add another build script like the following one.

"start-port-3000": "http-server -p 3000"

But this is not very flexible, right! Imagine we would need to do that for other ports as well. Our package.json would become cluttered.

So there must be a more elegant way!

Follow me on Twitter or medium to get notified about my newest blog posts!🐥

Accessing external arguments in NPM scripts

It would be nice to let the consumer of our npm script decide on which port the http-server should be started. So instead of adding another script, we can adjust our start script to access a port variable which will be passed to our script.

"start": "http-server -p $PORT"

The PORT variable is now controlled by the caller of the script. So he can set the desired PORT and pass it to our script.

PORT=3000 npm run start

Awesome! The PORT variable is set to 3000. It is then accessed by our start script and passed to the http-server. So we already implemented the desired behavior. Done!

✋Wait, not so fast.

This approach is helpful and flexible. But it has one major downside. Our script will not work if somebody forgets to set the PORT variable. Gasp 😧

Use a default value

Default values are a great way to handle undefined values. We use a predefined value instead. Inside our NPM script we can achieve that by using the following syntax;

"server:start": "http-server -p ${PORT:-8080}"

With this approach, our script is flexible and robust. The user decides if he wants or doesn’t want to pass in a port from outside.

Accessing variables in multiple scripts 🗂️

While this approach works great for single scripts, it’s crucial that it also works with multiple scripts than run sequential or even in parallel.

So imagine we would like to add another script which logs a sweet message once the server starts.

"log": "echo \"Success: Server successfully started on port \" + $PORT"

To run the task above together with our startup task, we need to install a package called npm-run-all as a dev dependency.

npm i -D npm-run-all

Let’s group those tasks by using the same prefix so that they can be run in parallel by using the command npm run server.

"server": "npm-run-all -p server:*",
"server:start": "http-server -p ${PORT:-8080}",
"server:log": "echo \"Success: Server successfully started on port \" + ${PORT:-8080}",

We can then set the port and run them all together.

PORT=3000 npm run server

Which results in the following output:

> echo "Success: Server successfully started on port " + $PORT
Success: Server successfully started on port  + 3000
Starting up http-server, serving ./
Available on:
http://127.0.0.1:3000
http://192.168.1.126:3000
Hit CTRL-C to stop the server

Variables are set on the current process as environment variables. Therefore they can either be accessed by a single script or even by multiple scripts.

Further use cases 🔭

The example above is a straightforward example to illustrate how to access variables inside your npm scripts. We went through this example because it's quite simple and explains the cause.

However, you may not really need it in practice because you normally do not change the port to often. But there are more complicated practical use cases where you are forced to use the approach described above.

Imagine you have a library which gets published to npm. The whole setup uses conventional commit messages to automatically bump the version of the package inside a build step of your pipeline.

In such a scenario, the new build version is only available in your build environment. If you, for example, want to do something with the new version like updating the version of your package.json or simply display it on a component by overriding some string inside an NPM script — you are forced to access the variable from the outside.

Conclusion

Accessing variables inside your NPM scripts makes your NPM scripts more flexible.

It is especially useful when you use it inside a pipeline or some other environment where you need to access variables in your NPM script.

🙏 If you find this post helpful then give some claps by clicking on the clap 👏🏻 button below.

Claps help other people finding it and encourage me to write more posts

Feel free to check out some of my other articles about Front End development.