Mastering npm Scripts

Tomas Litera

by

@

πŸ§ πŸ’­βš–οΈ Cognitive Load

The amount of mental resources needed to understand and interact with an interface.

Best practice in sustainable naming and organization of npm scripts

  • πŸ€”βš–οΈπŸ”€ Dilemma
  • πŸ“πŸ·οΈπŸ“› Naming Conventions
  • πŸ› οΈπŸ§°βš™οΈ Tooling

πŸ€”βš–οΈπŸ”€ Dilemma

⚠️🧩🚧 Common Challenges

Standardization

Lack of a common approach creates inconsistencies between projects.

Relearning Curve

Developers must adapt to new script names in each project.

Efficiency

A standardized set of scripts would promote efficiency.

πŸ“¦πŸ§­βš οΈ Navigating npm Scripts

JSON Limitations

JSON format limits script organization and commenting.

Lack of Native Help

npm -h doesn't display available scripts

Script Descriptions

Wish for better ways to describe what scripts do.

npm/yarn/pnpn run

"scripts": {
  "\n========== Building ==========": "",
  "build": "npm run clean && tsc",
  "watch": "tsc --watch",
  "clean": "shx rm -rf ./dist/*",
  "\n========== Testing ==========": "",
  "test": "mocha --enable-source-maps --ui qunit",
  "testall": "mocha --enable-source-maps --ui qunit \"./dist/**/*_test.js\"",
  "\n========== Publishing ==========": "",
  "publishd": "npm publish --dry-run",
  "prepublishOnly": "npm run build"
},

Self-documented Makefile

πŸ“πŸ·οΈπŸ“› Naming Conventions

From my experience, the npm test (or yarn test) is what everyone expects to be present in every (or almost every) package. As a developer, I switch from one package to another on a daily basis and this is precisely what I appreciate to be the same everywhere. It's far more convenient to know I can rely on the npm test (or yarn test) in all projects then having to remember different testing tasks names across different projects. It's a part of the standard set of tasks: the built-in install (or ci), then build, test, and start.

Universal Script

Core Scripts

  • start - starts the project, default node server.js
  • stop - stops the project
  • test - tests the whole project

Namespaces

"test":               // starts testing the whole project (test:unit, lint, types, format)
"test:unit":          // runs unit tests
"test:e2e":           // runs end-to-end test
"lint":               // runs lint
"lint:scripts":       // starts JavaScript linting
"lint:scripts:fix":   // runs the JavaScript fixer
"format":             // runs format check (Prettier)
"types":              // runs type check

Aliases

"scripts": {
    "dev": "start the development",
    "start": "start the production",
    "build": "build the project",
    "clean": "clean build files and other things",
    "test": "main script for testing entire project",
    "test:unit": "run unit tests",
    "test:unit:ci": "run unit tests for CI",
    "test:unit:local": "run unit tests on local",
    "test:unit:watch": "run unit tests in watch mode",
    "test:unit:coverage": "run unit tests with code coverage",
    "lint": "main linting script",
    "lint:scripts": "run ecma script linting",
    "lint:scripts:fix": "run ecma script fixing",
    "lint:commit": "lint commit",
    "lint:markdown": "lint markdown",
    "lint:text": "lint text",
    "lint:text:fix": "fix text",
    "format": "run format checker",
    "format:fix": "run format fixer",
    "types": "run type checking"
},
  • test - tests the entire project
  • test:unit - runs unit tests
  • lint - executes lints
  • format - runs format check
  • types - runs type check
  • build - builds the project
  • dev - starts local development
  • start - starts production configuration
  • release - prepares a new release
  • deploy - uploads the project to the runtime environment

List of mandatory scripts

πŸ› οΈπŸ§°βš™οΈ Tooling

Grouping

"lint": "lint:scripts & lint:css & lint:html"
"lint": "lint:scripts; lint:css; lint:html"
"lint": "lint:scripts && lint:css && lint:html"

Parallel (subprocess problem)

Series (return value problem)

Series

npm-run-all

"lint": "npm-run-all --parallel lint:scripts lint:css lint:html"
"lint": "npm-run-all --serial lint:scripts lint:css lint:html"
"lint": "npm-run-all --serial --continue-on-error lint:*"

Parallel

Series

Wildcard

πŸͺ Life-cycle Hooks

"build": "npm-run-all --serial build:prepare build:compile build:finalize",
"build:prepare": "shx rm -rf dist",
"build:compile": "rollup",
"build:finalize": "mv package.json dist/"
  • build:prepare
  • build
  • build:finalize

πŸ”€ Script Ordering

"scripts": {
    "prepare": "is-ci || husky install",
    "start": "yarn packages:start --ignore '@almacareer/spirit-example*'",
    "storybook": "lerna run start --scope=@lmc-eu/spirit-storybook",
    "test": "yarn packages:test",
    "test:unit": "yarn packages:test:unit",
    "test:e2e": "yarn playwright test",
    "test:e2e:update": "yarn playwright test --update-snapshots",
    "test:e2e:report": "yarn playwright show-report",
    "test:e2e:ui": "yarn playwright test --ui",
    "lint": "npm-run-all --parallel es:lint lint:markdown packages:lint",
    "lint:fix": "npm-run-all --parallel es:lint:fix packages:lint:fix",
    "lint:markdown": "remark ./ --quiet",
    "lint:commit": "yarn commitlint --verbose --color --from $(git merge-base origin/main HEAD)",
    "es:lint": "eslint ./",
    "es:lint:fix": "yarn es:lint --fix",
    "format": "yarn format:check",
    "format:check": "prettier --check ./",
    "format:fix": "prettier --write ./",
    "format:fix:changelog": "prettier --write ./**/CHANGELOG.md",
    "types": "yarn packages:types",
    "build": "npm-run-all --serial packages:build:libs packages:build:web",
    "version": "yarn format:fix:changelog",
    "release": "npm-run-all --serial packages:build && packages:publish",
    "packages:start": "lerna run start --parallel",
    "packages:test": "lerna run test",
    "packages:test:unit": "lerna run test:unit",
    "packages:lint": "lerna run lint --parallel --no-sort",
    "packages:lint:fix": "lerna run lint:fix --parallel",
    "packages:types": "lerna run types --no-sort",
    "packages:build:libs": "lerna run build --ignore '@lmc-eu/spirit-web*' --ignore=@lmc-eu/spirit-demo-app --ignore=@lmc-eu/spirit-storybook --ignore '@almacareer/spirit-example*'",
    "packages:build:web": "lerna run build --scope '@lmc-eu/spirit-web*' --ignore=@lmc-eu/spirit-demo-app",
    "packages:publish": "lerna publish",
    "packages:diff": "lerna diff",
    "packages:changed": "lerna changed",
    "packages:list": "lerna ls"
},
  1. Standardize Script Names.

  2. Be Consistent and Explicit.

  3. Leverage Tools.

πŸ₯‘ Takeaways

πŸ‘‹

No robots (AI) were harmed while fabricating these slides and posts.

 

https://slides.com

https://gamma.app

https://chatgpt.com

https://grammarly.com