92

My package.json looks like the following:

{
  "name": "project",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "lint": "./node_modules/eslint/bin/eslint.js --format \"./node_modules/eslint-friendly-formatter/index.js\" .",
    "build:server": "./node_modules/babel-cli/bin/babel.js . -d dist/server --ignore node_modules,dist,client,public,webpack*"
  }
}

As you can see, the lint and build:server command are hard to read, so I want to break them into multiple lines.

I've tried to use \, but it throws errors like:

npm ERR! Failed to parse json
npm ERR! Unexpected token ' ' at 11:80
npm ERR! :server": "./node_modules/babel-cli/bin/babel.js . -d dist/server \
npm ERR!                                                                   ^

How can I do this?

Only to write another bash file like build.sh and use it in npm scripts like ./build.sh server ?

Minifyre
  • 510
  • 2
  • 5
  • 17
user2331095
  • 6,577
  • 8
  • 36
  • 56

3 Answers3

122

You can chain independent tasks.

Here is an example:

"scripts": {
    "lint-jshint": "jshint --verbose --show-non-errors ./src/main/js",
    "lint-eslint": "eslint ./src/main/js ./src/test/js",
    "lint-csslint": "csslint ./src/main/js",

    "lint": "npm run -s lint-jshint & npm run -s lint-eslint & npm run -s lint-csslint",

    "pretest": "rimraf ./build/reports/tests && mkdirp ./build/reports/tests && npm run -s lint",
    "test": "karma start ./src/test/resources/conf/karma.conf.js",
    ...

Here is a nice blog which I used at that time: https://www.keithcirkel.co.uk/how-to-use-npm-as-a-build-tool/

El Ronnoco
  • 11,753
  • 5
  • 38
  • 65
asa
  • 1,776
  • 2
  • 11
  • 10
  • 44
    Note that this code uses `&` instead of `&&`. The former means to run the script in the background, meaning that they execute in parallel and their output is shuffled together. The latter would mean to execute the *next* command only if the *current* command exits without an error code. – Bruno Bronosky Apr 09 '19 at 18:46
  • Thanks for your comments, there are indeed more configurations and information available in the linked article, which deserve all the credits, hence why I linked it. – asa Apr 10 '19 at 18:15
  • 1
    since I'm developing mainly on Windows for as long as I can remember, I'm assuming that any issue you are encountering is related to something else. In the example above the command `npm run lint` works fine (just tested again). – asa Jun 03 '19 at 19:27
  • This would blow up the list with scripts that are only used in one script. I would rather outsource in a file with (somehow) linebreaks. – fabpico Jun 25 '21 at 14:18
  • 1
    This doesn't even attempt to answer the question? – Jim Aho May 27 '22 at 06:46
34

You can't do that.

The following code is in read-json.js which is in package node_modules/npm/node_modules/read-package-json which is used in run-script.js to execute $ npm run-script ~~ or $ npm run ~~ which is its alias.

function scriptpath (file, data, cb) {
  if (!data.scripts) return cb(null, data)
  var k = Object.keys(data.scripts)
  k.forEach(scriptpath_, data.scripts)
  cb(null, data)
}

function scriptpath_ (key) {
  var s = this[key]
  // This is never allowed, and only causes problems
  if (typeof s !== 'string') return delete this[key]

  var spre = /^(\.[\/\\])?node_modules[\/\\].bin[\\\/]/
  if (s.match(spre)) {
    this[key] = this[key].replace(spre, '')
  }
}

The key in scriptpath_ is like "build:server" in your code.

The this[key] is like "./node_modules/babel-cli/bin/babel.js . -d dist/server --ignore node_modules,dist,client,public,webpack*" in your code.

So, if you write the code which is not string type, in other words, if you don't write the string text in package.json, it will be an error unless you contribute to the package npm/read-package-json.

harukaeru
  • 683
  • 6
  • 15
  • 1
    seems like the code could be made to support an array of strings...I hope somebody does that someday. – David Burson Aug 16 '17 at 15:39
  • 5
    This sort of answers the question without solving the problem. Personally, I'm leaning toward running external scripts (`"build:server": "node build_server.js"`) given how limited npm "scripts" are. – snarf Jul 06 '19 at 03:47
  • @snarf do you have a simple example of what build_server.js would look like? – J'e Dec 30 '19 at 17:25
  • 1
    It would be the moral equivalent of your npm script. You can use `exec` or `spawn` to call out to the same external programs you'd normally invoke on the command line, spreading the logic over as many lines as necessary to keep things readable and maintainable. – snarf Dec 31 '19 at 20:58
18

Another common alternative is to write an npm command that references a local bash script (where you have more power to do what you want).

i.e.

# package.json
{
  "name": "project",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "lint": "./node_modules/eslint/bin/eslint.js --format \"./node_modules/eslint-friendly-formatter/index.js\" .",
    "build:server": "./build-server.sh"
  }
}
# build-server.sh
#!/bin/bash

./node_modules/babel-cli/bin/babel.js . \
  -d dist/server \
  --ignore \
    node_modules,\
    dist,\
    client,\
    public,\
    webpack*

NOTE: make sure you give yourself permission to run the file; otherwise you'll run into permission issues

sudo chmod 755 'build-server.sh'

See: Run script on mac prompt "Permission denied"

TheScrappyDev
  • 4,375
  • 2
  • 21
  • 25