npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

run-simple

v0.2.3

Published

A simple, enhanced replacement for `npm run-script <command> [-- <args>...]`

Downloads

28

Readme

run – Simple development task automation

Briefly

run is a simple, enhanced replacement for npm run-script <command> [-- <args>...] with zero third-party dependencies. If you already use npm run, you can use run immediately. But run can do a bit more as well.

Installation

npm install -g run-simple

Usage

Command Line

run [--version] [-h | --help] [-q | --quiet | -s | --silent] <command> [-- <args>...]

Module

const Runner = require('run-simple')
const runner = new Runner()

runner.on('error', (error) => {
  console.error(error)
  process.exit(1)
})

runner.on('exit', (code) => {
  process.exit(code)
})

runner.on('list', (scripts) => {
  console.log(`${runner.appName}: ${runner.moduleRoot} scripts:`)
  Object.keys(scripts).forEach((name) => console.log(`  ${name}:\n    ${scripts[name]}`))
  process.exit()
})

runner.on('run', (spec) => {
  console.log()
  console.log(`> ${spec.name}${spec.version ? `@${spec.version}` : ''} ${spec.wd}`)
  console.log(`> ${spec.script}`)
  console.log()
})

runner.run()

Why not npm run-script?

Obviously, npm is a fine piece of software. And npm run-script (AKA npm run) is one of the simplest development automation tools available. I love it, and as a result, I have never wanted to waste time learning more featureful alternatives like gulp or grunt.

But… it could be better. One thing that npm run doesn’t support well is signal handling. When npm run executes scripts, handling signals like 'SIGINT' within the scripts themselves is unreliable at best, which means a script that should clean up before exiting simply can’t. The implications go beyond signal handling – scripts behave differently when npm runs them than they do when they run by themselves. npm run just isn’t satisfied to run something and then get out out of the way.

Which may explain why npm run is verbose to a fault. npm has a lot more on its mind than just running your scripts so by default you’re going to see more output than you really need. Sure, you can pass it --silent or redirect output to /dev/null, but other people (your teammates and mine, for example) will need to do the same or they’ll get a bunch of npm disclaimer boilerplate when what they really want to see is what the script itself did.

Finally, package.json is great for project configuration, but it’s a pretty poor place to write scripts. There’s no way to comment or document your scripts. And being forced to write everything on a single line either hinders readability or forces artificial factoring of script logic.

Why run?

Although run is quieter and will cede more control to scripts, it is designed to work as much like npm run as possible. In fact, you can easily use it as if it was nothing more than an alias for npm run; it’ll happily find and execute all the scripts you have already defined in package.json.

But if you create a scripts.js file, run will look there for tasks as well. Here’s what the run project’s own scripts.js looks like:

const path = require('path')
const rollup = require('rollup')

const reimportFrom = require('./scripts/reimport-from')
const varsPathname = path.resolve('./scripts/vars.js')
const {
  binPathname,
  distPathname,
  mainPathname
} = require(varsPathname)

module.exports = {
  // ---------------------------------------------------------------------------
  // Dist

  predist: `mkdir -p ${distPathname}`,
  dist: 'rollup -c',
  postdist: `chmod 755 ${binPathname}`,

  // ---------------------------------------------------------------------------
  // Publish

  prepublish: 'run test',
  publish: 'npm publish',

  // ---------------------------------------------------------------------------
  // Test

  pretest: 'NODE_ENV=test run -q dist',
  test: "mocha -s 400 test/init.js './test/*.test.js' './test/**/*.test.js'",
  watchtest() {
    process.env.NODE_ENV = 'test'

    return Promise.all([
      reimportFrom(varsPathname),
      reimportFrom('./rollup.config.js')
    ]).then(([, config]) => {
      const {spawn, spawnSync} = require('child_process')
      const {watch} = require('chokidar')

      const {distPathname, mainPathname} = require(varsPathname)
      const testPathname = path.resolve('test')

      const wdRegExp = new RegExp(`^${process.cwd()}/`)
      const rollupWatcher = rollup.watch(config)

      const runTest = () => {
        spawnSync('sh', ['-c', this.test], {stdio: 'inherit'})
      }

      const debounceTimeoutMilliseconds = 250

      let debounceTimeoutId
      let ready = false
      const watchRollupOnce = (event) => {
        if (!ready && event.code === 'END') {
          ready = true
          rollupWatcher.removeListener('event', watchRollupOnce)
          runTest()

          const testWatcher = watch(testPathname)
          const watchTestOnce = () => {
            testWatcher.on('all', (type, pathname) => {
              clearTimeout(debounceTimeoutId)
              debounceTimeoutId = setTimeout(runTest, debounceTimeoutMilliseconds)
            })
          }

          testWatcher.once('ready', watchTestOnce)
        }
      }

      rollupWatcher.on('event', watchRollupOnce)

      rollupWatcher.on('event', (event) => {
        switch (event.code) {
          case 'BUNDLE_END':
            const input = event.input
            const output = event.output
              .map((x) => x.replace(wdRegExp, ''))
              .join(`\n${new Array(input.length).join(' ')}`)

            console.log(input, '→', output)
            break
          case 'ERROR':
            console.error(event.error)
            break
          case 'FATAL':
            throw event.error
        }
      })
    })
  }

  // ---------------------------------------------------------------------------
}

The first thing you’ll see is that run supports imports. Now you can share modules between the code you build and the code that builds it.

Then there are comments and whitespace, which make automation tasks easier to write, read, and maintain.

Finally, the watchtest script is actually a plain-old JavaScript function. Just like other scripts, functions will be passed whatever arguments you define after the -- in run <command> [-- <args>...].

Imagine that.

Compatibility

Environment Variables

npm_package_*

Because npm_package_* variables are useful to shell scripts that depend on values stored in package.json, run will define most of them exactly as npm does. However, there are a couple of exceptions.

Unlike, npm run, run will not attempt to normalize package.json keys or values. For example, run won’t produce the following environment variables unless they are explicitly included in package.json:

  • npm_package_bugs_url
  • npm_package_homepage
  • npm_package_readmeFilename

Similarly, run does not transform values like npm_package_repository_url.

For a complete description of how npm run transforms package.json, see: npm/normalize-package-data.

npm_config_*

In the interest of simplicity in both implementation and behavior, run does not read npm’s configuration nor does it define npm_config_* variables.

Other npm_*

run defines a few miscellaneous npm environment variables as well:

  • npm_execpath (as run_execpath – npm isn’t running)
  • npm_lifecycle_event
  • npm_lifecycle_script
  • npm_node_execpath

Credits

run was inspired in part by “An alternative to npm scripts” by James Forbes.