nps (npm-package-scripts)

repository·master·Indexed 23 days ago

https://github.com/sezna/nps

A tool to replace the scripts section of package.json with more powerful and maintainable JavaScript or YAML configuration files. nps allows for comments, logic, and advanced execution (such as concurrent scripts via nps-utils) while avoiding bloated JSON files. It includes a CLI for running scripts, an init command for migration, and support for platform-specific logic in package-scripts.js.

Tokens
4.1K
Snippets
10
Records
25
Agent score
80%

What's inside nps

  1. What is nps?

    master

    nps (npm-package-scripts) is a tool that allows you to move your npm scripts from a bloated package.json file into a dedicated package-scripts.js or package-scripts.yml file. This provides several advantages over JSON:

    • Comments: You can add documentation directly within your script definitions.
    • Logic: Since package-scripts.js is a JavaScript file, you can use variables, functions, and logic to define scripts.
    • Maintainability: Avoids the unmaintainable mess of large JSON files.
    • Advanced Execution: Supports running scripts concurrently or in sequence using utilities like nps-utils.
  2. Use the nps CLI to run scripts

    master

    To run a script defined in your package-scripts.js, provide the script name as an argument to the nps command.

    Running single scripts:

    nps cover

    Running multiple scripts in series: Add space-separated arguments to run scripts one after another.

    nps cover check-coverage

    Passing arguments to scripts: Wrap the script and its arguments in quotes to ensure they are passed correctly.

    nps "test --cover" check-coverage
    nps cover
  3. Use nps via package.json (Non-global installation)

    master

    If you prefer not to install nps globally or modify your $PATH, you can add a script to your package.json to trigger nps. It is recommended to use the start script for convenience.

    {
      "scripts": {
        "start": "nps"
      }
    }
  4. Install nps

    master

    You can install nps as a development dependency in your project or install it globally. Global installation is recommended for easier CLI access.

    As a devDependency:

    npm install --save-dev nps

    Globally:

    npm install --global nps
  5. Run scripts in parallel with nps-utils

    master

    To run multiple non-interdependent scripts concurrently, use the nps-utils package. It provides utility functions like concurrent to wrap script definitions.

    • npsUtils.concurrent({...}): Allows you to define a group of scripts as a single task, where each sub-task can have its own configuration (like colors).
    • npsUtils.concurrent.nps('script1', 'script2', ...): Allows you to run existing nps scripts in parallel.
    const npsUtils = require('nps-utils')
    
    module.exports = {
      scripts: {
        sayThings: npsUtils.concurrent({
          hi: {script: 'echo hi'},
          hey: {script: 'echo hey', color: 'blue.bgGreen.dim'},
          hello: 'echo hello there',
        }),
        validate: npsUtils.concurrent.nps(
          'build',
          'lint',
          'test',
          'order.sandwich',
        ),
        build: 'webpack',
        lint: 'eslint .',
        test: 'jest',
        order: {sandwich: 'makemeasandwich'}
        // etc...
      }
    }
  6. Configure scripts using package-scripts.yml

    master

    Alternatively, you can use YAML for your script definitions by creating a package-scripts.yml file.

    scripts:
      default: node index.js
      lint: eslint .
      test:
        # learn more about Jest here: https://kcd.im/egghead-jest
        default: jest
        watch:
          script: jest --watch
          description: run in the amazingly intelligent Jest watch mode
      build:
        default: webpack
        prod: webpack -p
      validate: concurrent "nps lint" "nps test" "nps build"
  7. Configure scripts using package-scripts.js

    master

    To use JavaScript for your scripts, create a package-scripts.js file in your project root. The file must export an object with a scripts key. You can define simple strings, nested objects for sub-scripts, or use nps-utils for complex tasks like concurrent execution.

    Sub-scripts are defined by nesting objects. A sub-script can have a default key (the command) and an optional description key.

    const npsUtils = require("nps-utils"); // not required, but handy!
    
    module.exports = {
      scripts: {
        default: "node index.js",
        lint: "eslint .",
        test: {
          // learn more about Jest here: https://facebook.github.io/jest
          default: "jest",
          watch: {
            script: "jest --watch",
            description: "run in the amazingly intelligent Jest watch mode"
          }
        },
        build: {
          // learn more about Webpack here: https://webpack.js.org/
          default: "webpack",
          prod: "webpack -p"
        },
        // learn more about npsUtils here: https://npm.im/nps-utils
        validate: npsUtils.concurrent.nps("lint", "test", "build")
      }
    };
  8. Migrate from npm scripts to nps

    master
    If you already have scripts defined in your package.json, you can automatically migrate them to nps using the init command. This will generate a package-scripts.js (or .yml) and update your package.json to use the nps binary.
  9. Write cross-platform scripts using package-scripts.js

    master

    Since package.json cannot detect the operating system, you can use a package-scripts.js file to handle platform-specific logic. This allows you to maintain a single script name that executes different commands depending on whether the user is on Windows or a Unix-based system (macOS/Linux).

    To implement this, use a package like is-os to detect the platform and conditionally define your command strings.

    var isWindows = require('is-os').isWindows
    var removeDist = isWindows ? 'rmdir ./dist' : 'rm ./dist'
    module.exports = {
      scripts: {
        build: {
          description: 'Build the project (built based on the platform)',
          script: removeDist + ' && babel --copy-files --out-dir dist src'
        }
      }
    }
  10. Configure nps via .npsrc or .npsrc.json

    master

    You can use a .npsrc or .npsrc.json file to persist CLI options. nps searches upwards from the current directory to find these files.

    Supported options for the configuration file:

    • require: A module to be loaded before the config file (e.g., for preloading babel-register or ts-node).
    • config: A path to a different configuration file.

    Example .npsrc.json:

    {
      "require": "ts-node/register/transpile-only",
      "config": "package-scripts.ts"
    }
  11. Fix 'Failed with exit code' or 'Emitted an error'

    master

    These errors indicate that a script executed by nps failed (returned a non-zero exit code) or the child process emitted an error.

    To fix:

    1. Inspect the specific error message emitted by the script to identify the cause.
    2. Try running the script directly without nps to verify if the issue lies within the script itself or within nps. If the script works fine without nps, please file an issue.