npm package.json OS specific script

node.jsNpmpackage.jsonNpm Scripts

node.js Problem Overview


I would like to create a package.json build script that executes slightly different set of commands when run from Windows, Linux, Mac.

The problem is that I cannot find a way to put it in package.json file that will run without problems at every system.

Here is an example that I would like to have:

"scripts" : {
    "build.windows" : "echo do windows specific stuff",
    "build.linux" : "echo do linux specific stuff",
    "build.mac" : "echo do mac specific stuff",
    "build" : "??????????????" <- what to put here to execute script designed for OS
                                  on which npm is running
}

node.js Solutions


Solution 1 - node.js

There's an NPM package called run-script-os ( NPM | GitHub ) that doesn't require you to write any additional files, and this can be convenient if what you're trying to do is very simple. For example, in your package.json, you might have something like:

"scripts": {
    "test": "run-script-os",
    "test:darwin:linux": "export NODE_ENV=test && mocha",
    "test:win32": "SET NODE_ENV=test&& mocha"
}

Then you could run npm test on Windows, Mac, or Linux and get similar (or different!) results on each.

Solution 2 - node.js

You can use scripts with node run-script command. npm run is a shortcut of it.

Package json:

"scripts" : {
    "build-windows" : "node build-windows.js",
    "build-linux" : "node build-linux.js",
    "build-mac" : "node build-mac.js",
    "build" : "node build.js"
}

Command line:

npm run build-windows

If you don't like it, you can use commands inside node.js.

Package json:

"scripts" : {
    "build" : "node build.js"
}

Build.js

var sys = require('sys');
var exec = require('child_process').exec;
var os = require('os');

function puts(error, stdout, stderr) { sys.puts(stdout) }

// Run command depending on the OS
if (os.type() === 'Linux') 
   exec("node build-linux.js", puts); 
else if (os.type() === 'Darwin') 
   exec("node build-mac.js", puts); 
else if (os.type() === 'Windows_NT') 
   exec("node build-windows.js", puts);
else
   throw new Error("Unsupported OS found: " + os.type());

Solution 3 - node.js

It depends on exactly what you're trying to do in the scripts, but it's likely that you can use npm cli packages to effectively add cross-platform commands to any shell.

For example, if you wanted to delete a directory, you could use separate syntaxes for windows and linux:

rm -rf _site     # bash
rd /s /q _site   # cmd

Or instead, you could use the npm package rimraf which works cross platform:

npx rimraf _site

To take Dave P's example above, you could set environment variables with cross-env like this:

"scripts": {
    "test": "npx cross-env NODE_ENV=test mocha",
}

And if you don't want to use npx to install scripts live, you can install them globally ahead of time like this:

npm i cross-env -g

Here's a post I wrote on making NPM scripts work cross platform which explores some of these options

Solution 4 - node.js

Definitely not the most reliable way to do this, but you can technically accomplish this all in one npm script:

{
    "scripts": {
        "build": "( Write-Output 'Powershell' && ./tools/build-ps.ps1 ) || 
                  ( CALL ./tools/build-cmd.bat ) || 
                  ( bash -c 'uname -a | grep -q -i Linux' && bash -c ./tools/build-linux.sh ) ||
                  ( bash -c 'uname -a | grep -q -i Darwin' && bash -c ./tools/build-mac.sh )"
        }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiongawiView Question on Stackoverflow
Solution 1 - node.jsDave PView Answer on Stackoverflow
Solution 2 - node.jshurricaneView Answer on Stackoverflow
Solution 3 - node.jsKyleMitView Answer on Stackoverflow
Solution 4 - node.jsLayne BernardoView Answer on Stackoverflow