Joshua's Cheatsheets - Node And Npm
Light
help

Node and NPM - Cheatsheet

Init

npm init, or without the step-by-step questions, npm init -y

Some useful install flags - see full list here

Flag Full Flag Description
-g --global Save globally instead of into local project
NA --link Link globally installed packages into local project
-P --save-prod Save into dependencies section. Default
-D --save-dev Package will show in devDependencies
-O --save-optional Package will show in optionalDependencies
NA --no-save Does not save to package.json at all!

Updating release versions

You can use npm version {semVerString} to set a new version. This will update package.json, package-lock.json, and npm-shrinkwrap.json.

A helpful thing to remember is that, without any other arguments, this does a lot of automatic stuff you might not want:

  • Adds a new git commit with automated message

    • Use custom with -m arg
  • Add a new git tag, and points it at the auto commit

    • Use --no-git-tag-version to disable
  • Updates the npm files (as mentioned above)
  • Runs preversion, version and postversion under scripts.

Update version without tagging OR adding commit

Use the --no-git-tag-version arg, or git-tag-version=false

Auto version bump

If you don't want to manually type out a version string, you can just auto bump the version, so long as you are using a valid semVer in your npm files. Use npm version {incrementTarget} where {incrementTarget} is one of:

  • major
  • minor
  • patch
  • premajor
  • preminor
  • prepatch
  • prerelease

List installed packages

Courtesy of jkomyno

npm list -g --depth 0

List versions

node -v

and

npm -version

Note: Node also has "ABI" version number. regular version number is like 10.##.# (LTS or non-lts). ABI version is regular integer

node -p "process.versions.modules"

Or to get all version info:

node -p "process.versions"

Upgrading Node version

  • On Unix

    • Recommended way is to use "N"

      # Just needed once
      npm install -g n
      # Now upgrade
      sudo n stable
  • On windows

    • You can download new installer (MSI) and just install over current
    • You can now use "NVM" (node version manager) for both Unix and Windows

Get the version of a package

NPM

npm list {packageName}

Yarn

yarn list --pattern {packageNameOrPattern} Or... yarn list | grep {packageNameOrPattern} Or... yarn global list --pattern {packageNameOrPattern}

Install a very specific version of a package (from CLI)

You can actually use similar syntax as a package.json file - e.g. tslint@^5.0.0.

NPM

npm install {packageName}@{semVerPattern}

Yarn

yarn add {packageName}@{semVerPattern}

When in doubt and fubar'd beyond repair...

npm cache clean -force

When REALLY f'ed up

rm -rf node_modules
npm cache clean -force
npm install

Installing peer-dependencies

Many packages, especially lint configs, will require other dependencies (peer dependcies) but will not install them automatically. You could manually figure out what's needed (for example, by running npm ls) and manually install one by one, or use a tool like install-peerdeps.

npm install -g install-peerdeps
install-peerdeps --dev {package}

You can list peer dependencies needed by a package by using

npm info "{package}" peerDependencies

NPM Install Errors

gyp related errors:

  • "No prebuilt binaries found"

    • There is probably a dependency that was built using C++ or other codebase and is missing a prebuilt binary for your versions of node/ABI#. Check your ABI and compare against what is hosted as a prebuilt binary.

      • If you can't find a prebuilt to use, just build yourself (check depency's package.json and .gyp for details). You will probably also need build tools installed, depending on OS:

        npm install --global --production windows-build-tools
  • General build errors ("MSBuild", etc)

    • Make sure that you have build tools installed (see above)

      • Make sure built-tools install WORKED

        • Make sure to run as Admin
        • Check log, and if necessary, manually run the installer it downloads
    • You can switch what version of MSVC you are targeting:

      • For example: npm config set msvs_version 2015 -g
    • Try to get Node to use a prebuilt-binary instead of building from scratch

      • Check the log to see why node is trying to rebuild/build

        • For example, is a firewall blocking the binary download?
        • Some install scripts will let you specify a binary source URL
      • A quick hack if you can find a pre-built binary to download, is to save it to the corresponding npm-cache folder, and then run npm rebuild {packageName} before trying to re-install.

        • You should see Cached binary found at ... if this trick worked
        • Found via this comment

Paths, paths, paths

Current directory

Often in Node scripts, you will need to reference something either by absolute or relative path, which might require knowing the full path of where the script is running.

  • __dirname is a magic global that holds the string path of where the script resides - regardless from where it got called

    • Does not have trailing slash
  • process.cwd() returns the absolute path from where you invoked the script process - e.g. where you ran your command from

Normalizing paths (POSIX vs non-POSIX, aka Windows)

There is a really great native library for Node called path which has all kinds of methods for cleaning up and parsing paths. For example, if I want to create a path based on current directory, and then normalize it because I'm not sure which OS it is going to be running on, I might use something like this:

const path = require('path');
const myFilePath = path.normalize(__dirname + '../subdir/myFile.js');

However, that only normalizes it for the OS you are on. If you want to force a standard, across any env, that takes more work. Quick hackish example:

currFilePath = currFilePath.replace(/[\/\\]{1,2}/gm,'/');

Read more about path, here

Get list of node flags

node --help

Or here.

Using the Node CLI / REPL

You can use the -e argument to evaluate (eval) raw code string, or -p to both evaluate and "print" the output.

node -p "Math.min(24,2);"

Results in "2" being printed to console.

Running a CLI command / system / bash / shell commands from within a node script

Recommended way is with child_process.exec.

const childProc = require('child_process');
var lsResults = childProc.execSync('ls');
// Note - exec returns buffer, so need to convert
var lsResultsString = lsResults.toString();

Changing directory

If you want to use cd, you need to use it with the command you want to run at the same time - e.g. a single line input to child_process.exec. Otherwise, the change of directory will not persist between commands. For example:

const childProc = require('child_process');

// Right:
childProc.execSync('cd foo && ls');

// Wrong:
chldProc.execSync('cd foo');
childProc.execSync('ls');

A recommended alternative is to pass the directory you want to execute the command in through the cwd (working directory) option:

const childProc = require('child_process');
childProc.execSync('ls', {
	cwd: 'foo'
});

Receiving CLI arguments

Access through process.argv. It should follow the following syntax:

if (Array.isArray(process.argv)){
	// 0 = path to nodejs - {string}
	let nodePath = process.argv[0];
	// 1 = path to current executing file - {string}
	let currFile = process.argv[1];
	// 2, 3, etc. = arguments
	let argsArr = process.argv.slice(2);
}

Read in package.json within script file

const packageInfo = require('./package.json');
console.log('Version = ' + packageInfo.version);

List tasks

npm run

Setting globals

There are not many good reasons to do this, but if for some reason you need to set a true global (not as in file global or top of closure global, but as in pollutes every file once imported), here is how:

global.findMyAnywhere = 'Hello';
// Or...
globalThis.findMyAnywhere = 'Hello';

Details

Console EOF / process.stdin.on('end')

On Unix, pressing CTRL+D usually results in the system returning an EOF (end-of-file) to whatever is listening to the terminal. In node, you often see this listened to as:

process.stdin.on('end', ()=>{
	// Do something
}

However, this flat out does not work on Windows. Futhermore, pressing CTRL+C, since it sends the exit command, does not give that listener a chance to execute. The workaround is to use the process signal event SIGINT listener:

// Redirect windows CTRL+C to stdin-end
process.on('SIGINT',function(){
	// Do whatever you want here - finish up stuff, etc.
	// ...
	// Emit EOF / end event
	// https://nodejs.org/api/stream.html#stream_event_end
	process.stdin.emit('end');
});

Buliding a NPM Package - Tips

Resources

  • Scotch.io guide
  • NPM guide

    Misc tips

  • Know about "scoped packages"

    • You can publish names with slashes in them, like @joshua/right-pad
    • These by default are scoped to private
    • use npm publish --access=public to publish public
    • Thanks to this post for the tip
  • Don't forget about npm link for local testing

    • In package folder npm link
    • In other project you want to test the package with npm link {packageName}
  • If you are making both a CLI and a regular module, don't forget to have both fields:

    • main (points to index.js, or whatever your main module file is)
    • bin (points to the cli.js, or whatever your CLI file(s) are)

      Exposing a CLI

      You can specify that a specific file will receive CLI commands (instead of index.js), by using the bin field in your package.json.

If you want the command trigger (e.g. what someone types in their CLI to hit your package) to just be your package name, then bin can just be the path to the file:

{
	"bin": "cli.js"
}

But if you want to expose multiple commands, make bin an object with the commands as fields:

{
	"bin": {
		"myapp-foo": "cli-foo.js",
		"myapp-bar": "cli-bar.js"
	}
}

Make sure that all files exposed through bin start with #!/usr/bin/env node, otherwise they are not executed with the node executable!

Warning: If you are using npm link for local development, you might need to re-run npm link every time after modifying bin in order for the changes to be picked up globally. At least, I had to in my case.

See docs for details.

Publishing

You can use npm publish --dry-run to get a preview of what files would be published.

If you want to exclude files from being distributed as part of your package, you have a few options:

  • Use .gitignore file

    • Downside: this also prevents files from showing up on Github / tracked in Git
    • Not a good solution for preventing large files that you still want tracked in Git
  • Use .npmignore file

    • NOT RECOMMENDED, for several reasons:

      • Conflicts with .gitignore file - NPM will not even look at that file if .npmignore exists.
      • This is dangerous because if you exclude a password file in your .gitignore but forget to duplicate the rule to your .npmignore file, it will be included in your package!
  • Use package.json -> "files": []

    • This is the best option
    • You can move all the files you want to include into a separate folder, and then only include that folder. For example:

      {
      	"files": [
      		"src/"
      	]
      }

Express

Great cheatsheets

Quick Ref Table

Side Thing Description Relev type sig
Request req.params Captures named params, made explicit in route signature. {[index: string]: string | undefined}
Request req.query Captures QueryString key-pair vals. {[index: string]: string | undefined}
Request req.body Captures body payload key-pairs

Requires body parsing middleware
{[index: string]: any}

How do I...

  • Capture variable through route?

    • Use :var syntax in route, then access through injected req.params

      app.get('/users/:userId', (req, res) => {
      	const userId = req.params.userId;
      });
    • Or through actual request payload, with req.body (if using body-parser)
    • Or through query params with req.query.{queryParam}
  • Inject a variable into the route?

    • You probably want to use middleware
    • Actually very easy to write your own with just a few lines of code...
  • Capture a parameter and check if it was used in the request?

    • GET (QueryString)

      • Use req.query, which returns object of key/pair values corresponding to querystring.
      • Check for valid value through standard JS logic; e.g., if you are expecting a string for /?name={name}, maybe do !!req.query.name
    • POST (Body)

      • Basically same as GET, but use req.body, to access POST body params (assuming you switch to body with POST)
      • Requires body-parsing middleware
    • Named param in route

      • If you are capturing parameters explicitly as part of the route, you can use req.params to get the captured value
      • Example, if route is /book/:id, you can get ID through req.params.id
    • ALL

      • If you want to accept the same parameter, and allow it to be passed via any of the three methods (QueryString, Body, or Named Params), that is a little trickier
      • There used to be an API method for this, req.param({name}, {defaultValue}), but it was deprecated.
      • If you really need this, you could easily write your own wrapper method to check all three inputs and validate, and/or take a look at the original code, here.
      • Relevant S/O thread

Things to note

Param types

The built-in query string parser in Express does not infer types. For example, you might be tempted to think that if your request looks like /?name=joe&age=13, then req.query.name would be typeof string, and req.query.age would be typeof number. This is wrong. They are all inferred as strings.

In addition, since req.query is an object, if you try to query a param that was not provided, you will get back undefined, not an empty string.

All of the above is also true for req.params, but not for req.body, since if JSON is passed via request, then the types are preserved without any special parsing needed


Debugging, profiling, etc.

Debugging

Call node --inspect-brk {nodeScriptFilePath} {args}

Make sure you either have auto-attach on in your VSCode settings, or start a debug session before running.

Profiling

For a plug-n-play solution, check out 0x.

Markdown Source Last Updated:
Sun Nov 03 2019 08:08:49 GMT+0000 (Coordinated Universal Time)
Markdown Source Created:
Mon Aug 19 2019 17:06:24 GMT+0000 (Coordinated Universal Time)