Skip to content

Instantly share code, notes, and snippets.

@gusalbukrk
Last active March 19, 2023 18:45
Show Gist options
  • Save gusalbukrk/78f781811df2548b73dc859335a3aaea to your computer and use it in GitHub Desktop.
Save gusalbukrk/78f781811df2548b73dc859335a3aaea to your computer and use it in GitHub Desktop.
#npm #yarn #pnpm

NPM

Install, update

  • update node:
    • curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
    • sudo apt-get install -y nodejs
  • update npm: sudo npm install -g npm@latest
  • get node-module location: npm root [-g]

Configuration

  • echo >> ~/.bashrc && npm completion >> ~/.bashrc && source ~/.bashrc = enable npm completion

Defaults

  • set defaults: npm config set init-author-name "<name>"
  • get defaults: npm config get init-author-name
  • delete defauts: npm config delete init-author-name

Basics

  • create package.json: npm init

    • without prompt: npm init -y
  • remount project with packages.json: npm install

  • get package info = npm view <package>

    • specific info = npm view <package> dependencies
  • install dependency: npm install [-g] <dependencies name> [--save-dev | -D], aliases: i

    • install specific version: npm install [-g] <name>@<version>
    • install from git remotes (repository must be a npm package, have a package.json): npm i <github:>username/repository
  • uninstall dependency: npm uninstall [-g] <name>, aliases: remove, rm, un

  • list installed dependencies: npm list, aliases: ls

    • using depth flag: npm -g ls --depth 0
  • check updates: npm [-g] outdated

  • update all packages, respecting semver: npm update [-g] [name]

    • update package(s) to the version defined at column 'wanted' of npm outdated
    • if you want to update to version in column 'latest' of npm outdated, edit manually the package.json or npm i <package>@latest

package.json, package-lock.json, npm-shrinkwrap.json

package.json

  • package.json lists, among other things, your package dependencies - but not their dependencies (nested dependencies)
  • and the dependencies' versions are locked with a carret (e.g. ^2.20.0)
  • meaning any future minor and patch updates will be installed instead of the exact version

files field

  • describes the entries to be included when your package is installed as a dependency
  • it's supposed to follow a syntax similar to .gitignore, here
  • however, it supports braces expansion (e.g. !src/**/*.{test,spec}.{js,jsx,ts,tsx}), as you can see in npm pack output
  • differently, eslint-plugin-node (which looks at package.json's files field to perform rules no-unpublished-*) doesn't understand braces expansion
  • mysticatea/eslint-plugin-node#199
  • mysticatea/eslint-plugin-node#290

why to keep a lock file

  • npm can be locked with a package-lock or npm-shrinkwrap, see below
  • a good reason to always keep a lock file is to be able to know exactly when (i.e. in which version of each dependency) everything was working
  • after update dependencies, you should always check to make sure everything is working
  • if there is no lockfile, you will have to check the dependencies every time you install or re-install them and make sure that everything still works

package-lock.json

  • package-lock.json is automatically generated for any operations where npm modifies either the node_modules tree or package.json
  • it describes the exact dependency tree (direct and nested dependencies...) that was generated
  • the goal of this file is to keep track of the exact version of every package that is installed so that the project is 100% reproducible even if packages are updated by their maintainers
  • its intended to be committed to the repository but cannot be published to npm registry (if you want to publish a lock file, use shrinkwrap)

npm-shrinkwrap.json

  • npm shrinkwrap = creates a npm-shrinkwrap.json
  • a file identical to package-lock.json, but that can be publish
  • you should keep lock or shrinkwrap, one or another, they're not programmed to coexist
  • for instance, if you run npm shrinkwrap in a project that already contains a lock file, this lock file will be renamed to shrinkwrap and future installations will modified the shrinkwrap

NPX

  • npx package-name
    • run a locally installed package (alternative to npm scripts)
    • if package isn't installed, download and execute it but won't save it: npx <non-installed package>
      • you can run different versions of the same command, using the syntax '@version'
  • npx node@6 = run code using a different Node version
  • npx https://gist.github.com/zkat/4bc19503fe9e9309e2bfaa2c58074d32 = run code (must be a npm package) from url

fix errors

  • the two more useful commands to run after encounter any warning or error: audit and cache clean

audit

  • npm audit = scan project for vulnerabilities and just show the details
  • npm audit fix = automatically install any compatible updates to vulnerable dependencies

cache

  • npm cache verify = display cache info
  • npm cache clean --force = clean the cache

View docs

  • open site, docs: npm home <package>, npm docs <package>
  • open github repo: npm repo <package>

NPM scripts

  • npm <script-name> = run pre-defined script names (install, test, publish...); full list here
  • npm run <script-name> = run arbitrary scripts
    • to run a script before or after a script use 'pre' and 'post' hooks (even user defined scripts), example: preinstall, postmycustom
    • --silent prevent the default NPM logs

Link

  • useful for when you need to work on application code and a dependency at the same time
  • link in two steps:
    • in the dependency directory sudo npm link = in the global node_modules (get it with npm root -g) create a symbolic link pointing to this project
    • in the main project npm link linkname --save = in this project's node_modules, create a symbolic link pointing to the specified link (located at the global node_modules)
  • sudo npm unlink -g linkname = to delete from the global node_modules directory

link vs install

  • instead of link, you could instead npm install the directory of the local dependency
  • differences is that npm install:
    • won't use the global node-modules
    • will alter project's package.json

ignore

  • both options accept .gitignore pattern and glob

files field at package.json (whitelist)

{
  "files": [
    "dist",
    "src",
    "!src/**/__tests__",
    "!src/**/*.{test,spec}.{js,jsx,ts,tsx}"
  ],
}

.npmignore file

# config files
/*.{js,cjs,json}
.browserslistrc
.editorconfig
.husky

# test files
src/**/__tests__
src/**/*.{test,spec}.{js,jsx,ts,tsx}

Publish

  • NOTE: with a free account, you only get to create public packages
  • create a NPM account
  • log in the cli with npm login
  • make sure the package is not already taken
  • in the package directory, npm publish

unpublish

  • npm unpublish <package-name>@<version> = delete a single version
    • npm unpublish [<@scope>/]<pkg>[@<version>] = scoped packages
    • NOTE: you cannot republish the same version ever again
  • npm unpublish --force package = delete the entire package from npm registry
    • NOTE: you'll need to wait 24 to republish package, NOTE: you cannot publish the same versions you published previously
  • unpublishing rules

Workspaces

How it works

  • dependencies get installed in the root node_modules
  • even if a dependency is shared by multiple packages, it gets saved only once in the root
  • however, if multiple workspaces depend on different versions of a package
    • npm will create a node_modules folder inside of one of the packages
    • containing the package at different version of the one inside the root node_modules/

Setup

npm init -w

  • inside a directory package.json
    • npm init -w packages/a -w packages/b -y

Manual

  • structure:
├── node_modules/
├── package.json
└── packages
    ├── package-a
    │   └── package.json
    └── package-b
        └── package.json
  • root package.json must contain:
{
  "private": true,
  "workspaces": [
    "packages/*", // every directory in packages/ will be a package
  ],
}
  • npm i = all workspaces will be symlinked at /node_modules, making possible for them to reference one another
    • you must add local dependencies in the local dependent package.json
    • otherwise, dependencies wouldn't be downloaded when downloading dependent package

Commands

  • workspace command:
    • --workspace, -w followed by a workspace name = operates in a single workspace
    • --workspaces, -ws = operates in all workspaces
  • install, uninstall:
    • npm i pkgname -ws = install in all workspaces
    • npm [install|remove] pkgname -w workspacename
  • run scripts:
    • npm run test -ws
    • npm run test -w a
  • publish:
    • npm publish -ws = publish all workspaces (if package is scoped, read below)
      • for scoped monorepo (@scope/pkgname):
        • must create an organization (scope) in NPM site
        • --access public is needed in the initial publication

Yarn

npm vs yarn

  • upon release, yarn had many advantages compared to npm
  • however, the rise of yarn pushed npm to make improvements and the competion has became increasingly tighten
  • though, yarn is still (even after npm 6.0) somewhat faster
  • the popularity gap is slowly closing but npm still is the most popular

Install

  • `sudo npm install -g yarn
  • curl --compressed -o- -L https://yarnpkg.com/install.sh | bash = update yarn

Basics

init

  • yarn init [-y]
  • yarn or yarn install = install all dependencies listed at 'package.json' and, if 'yarn.lock' exists and is enough to satisfy every dependency, the exact versions recorded in 'yarn.lock' are installed

info, list

  • yarn info package = info about a package = now you can use yarn as package manager anywhere, just like npm
    • yarn info package field = select a specific field, e.g. description, versions, license
  • yarn list = lists all dependencies for the current directory
    • yarn list --depth 0 --pattern "pattern"

install, upgrade, remove

  • yarn add [package]@[version] = install
    • yarn add [package] --dev|--peer|--optional = different categories of dependencies
  • yarn global add package = install globally
  • yarn outdated = checks for outdated package dependencies
  • yarn upgrade [package]@[version] = update dependency
  • yarn remove [package] = remove dependency

scripts

  • yarn run scriptname

cache

  • yarn stores every package in a global cache in your user directory on the file system
  • yarn cache list = view every cached package
    • yarn cache list --pattern "pattern"

yarn.lock

  • when you run either yarn or yarn add package, Yarn will generate a yarn.lock
  • this file will ensure that they get precisely the same dependencies as you have, is equivalent to npm's 'package-lock.json' and 'pm-shrinkwrap.json'

link

  • for development, a package can be linked into another project
  • two steps:
    • yarn link = in package you want to link
    • yarn link packagelinked = link the linked package into current directory

publish

  • yarn login
  • yarn publish, yarn publish --new-version <version>, yarn publish --access <public|restricted> = publish current package
  • as of now, no command to unpublish

workspaces

  • add to package.json: "workspaces": ["packages/*"]
  • tutorial

cli

  • yarn workspaces
    • info = info about each workspace
    • run <command> = run command in each workspace
      • currently in version 1, error if a package hasn't script
      • version 2 fixed this, here
  • yarn workspace
    • <workspace-name> <command> = run script in the choosen workspace

how to migrate from npm

  • delete node_modules, package-lock.json
  • run yarn (equivalent to npm i)

force yarn use (instead of npm)

method 1

  • NOTE: blocks both npm i, npm i <package-name>, npm remove <package-name>, npm update
// package.json
  "engines": {
    "npm": "use `yarn` instead",
    "pnpm": "use `yarn` instead"
  },
// .npmrc
engine-strict = true

method 2

  • NOTE: apparently only-allow doesn't work with npm anymore, so the other method is recommended; here
  • NOTE: blocks only npm i (not npm i <package-name>)
  • NOTE: no need to install (it's run via npx)
// package.json
  "scripts": {
    "preinstall": "npx only-allow yarn"
  }

PNPM

commands

install

  • npm install => pnpm install
  • npm i <package-name> => pnpm add <package-name>

run, exec

  • pnpm run <cmd> (run is optional) = run script
  • pnpm exec <cmd> (exec is optional) = run command

npx

  • pnpm exec <cmd> (exec is optional) = run command
  • pnpm dlx <pkg> = run package without installing

peer-dependencies

  • when pnpm i you may get error: Issues with peer dependencies found pnpm
  • the way to fix is to install (add to package.json & repeat command) missing peer dependencies as devDependencies

monorepo

pnpm-workspace.yaml

  • yarn monorepos must contain this file at root
  • defines the root of the workspace and enables you to include / exclude directories from the workspace
packages:
  # all packages in subdirs of packages/ and components/
  - 'packages/**'
  - 'components/**'
  # exclude packages that are inside test directories
  - '!**/test/**'

workspace: protocol

  • this is how local packages reference one another
  • variations:
    • workspace:* => exact current version
    • workspace:~ => tilde range (patch versions only)
    • workspace:^ => caret range (patch & minor versions only)

migration

  • replace any mention of npm or yarn to pnpm
  • pnpm import = generates a pnpm-lock.yaml from another package manager's lockfile (package-lock.json or yarn.lock)
  • force pnpm (instead of npm or yarn):
// package.json
  "engines": {
    "npm": "use `pnpm` instead",
    "yarn": "use `pnpm` instead"
  },
// .npmrc
engine-strict = true

how to integrate with changesets

Additional resources

semver

pre-release

  • alpha versions:
    • 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0

npm-check-updates - easier updates

  • ncu (no arguments)= display available updates
  • ncu -u = upgrade all
  • ncu --target minor = update only patch & minor versions
  • upgrade only some packages:
    • ncu chalk react
    • ncu --filter chalk react = include only package names matching the given string, wildcard, glob, comma-or-space-delimited list, or /regex/
    • ncu --reject react chalk = exclude packages matching the given string, wildcard, glob, comma-or-space-delimited list, or /regex/
  • ncu --deep = run recursively in current working directory (alias of --packageFile '**/package.json')
    • if you run ncu -i --deep -u refuse when asked if you want ncu to run npm install
      • otherwise, ncu will run npm install recursively in every directory containing a package.json and as a consequence create a package-lock.json in every single one of those directories
  • using in npm workspaces:
    • ncu --root -ws|--workspaces = run on all workspaces
      • NOTE: package.json must contain workspaces property
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment