DEV Community

seanbh
seanbh

Posted on • Originally published at Medium on

Enhancing npm Script Tasks with Node.js and JavaScript


Photo by Kelly Sikkema on Unsplash

Npm script tasks are an integral part of any modern JavaScript project. They allow us to automate mundane tasks and prevent us from having to remember a bunch of different commands.

You can accomplish many things without ever leaving package.json. But sometimes you need to do more than can be done in the single line definition of a script task or with multiple tasks.

If you find yourself in that situation you can offload the work to a JavaScript file and define the script task so that it runs that file with Node.js.

Running a JavaScript file with Node

Running a JavaScript file with an npm script task is as simple as:

"my-script-task": "node ./my-script.mjs"
Enter fullscreen mode Exit fullscreen mode

When you execute npm run my-script-task in the terminal, npm will execute this task, which runs the my-script.mjs file using Node.

Why does the file have an .mjs extension? The .mjs extension stands for “Module JavaScript”. It is used to explicitly tell Node that the file should be run as an ES module, which allows us to use ESM syntax. See this post to learn more about JavaScript Modules.

Helpful Modules

I have found that I can accomplish a lot by only importing 3 modules:

import { execSync } from 'child_process';
import readline from 'readline';
import chalk from 'chalk';
Enter fullscreen mode Exit fullscreen mode

If you are using ESLint, it may complain about the import statement unless you add this to your .eslintrc.json file:

{
  "files": ["*.mjs"],
  "parserOptions": {
    "sourceType": "module",
    "ecmaVersion": "latest"
  }
}
Enter fullscreen mode Exit fullscreen mode

execSync

execSync is built into Node and is the workhorse. It is used to execute shell commands which actually accomplish the work we need to perform. Note that it is surrounded by {} in the import statement because it is a named export rather than the default export.

To use it, you just pass in the command that you would normally run in the terminal. For example, if I want to bump the prerelease version of my package, I can do:

execSync(`npm version prerelease --preid=test`);
Enter fullscreen mode Exit fullscreen mode

readLine

readLine also comes with Node and allows for user interaction. For example, we can make the user confirm what they are about to do:

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

// make the user confirm what they are about to do
rl.question('Are you sure? (y/n) ', (answer) => {
  if (answer.toLowerCase() === 'y') {
    // do your work
  } else {
    // abort
    rl.close();
  }
});
Enter fullscreen mode Exit fullscreen mode

chalk

chalk is a third-party package we can use to style the terminal, so that we can make questions and messages stand out. To use it, you just wrap the text in a function call:

chalk.yellowBright(
   ‘This text will be bright yellow’
);
Enter fullscreen mode Exit fullscreen mode

You can use this when passing text to both rl.question and console.log:

console.log(
   chalk.redBright(
     ‘This text will be bright red’
   )
);
Enter fullscreen mode Exit fullscreen mode

With this combination of tools, I’ve been able to greatly enhance our development workflows.

That’s it! I hope you found this useful.

Bibliography

Top comments (0)