← Back to home

How to require and execute the same nodejs script

I needed for a particular node script to be executable and available to reference with require from another script. And there’s a neat trick how to do it.

Imagine you have a script like this:

#!/usr/bin/env node

const config = {
  endpoint: 'https://example.com'
}

process.stdout.write(JSON.stringify(config, null, 2))

Executing it would produce the following output:

$ ./config.js
{
  "endpoint": "https://example.com"
}

Then imagine you have another script that references the one above:

#!/usr/bin/env node

const config = require('./config.js')

config.testing = true

process.stdout.write(JSON.stringify(config, null, 2))

This obviously won’t work, because we don’t set module.exports in the first script. Then let’s set it. We add module.exports = config to the first script, and here’s the output when we execute the second one:

$ config-test.js
{
  "endpoint": "https://example.com"
}
{
  "endpoint": "https://example.com",
  "testing": true
}

Hmm, the script outputs two JSON objects, but I expected only one (the last one, to be specific). After looking at the code again I figure out that by simply requiring config.js in the second script, interpreter automatically executes process.stdout.write command in the first script, and outputs the first JSON object.

What I would like to have is that the first script stays executable and its output is a JSON object, but when I require it in another script, then it would stay silent. Well, after a bit of struggling and nudging my mate Paulus (thanks, Paulus!) I’ve discovered this trick.

In the first script I add a conditional in the end:

require.main === module ?
  process.stdout.write(JSON.stringify(config, null, 2)) :
  module.exports = config

And then:

$ ./config.js
{
  "endpoint": "https://example.com"
}
$ ./config-test.js
{
  "endpoint": "https://example.com",
  "testing": true
}

Works like a charm!

Last edited on Jan 11, 2019