Wilson Mar bio photo

Wilson Mar


Calendar YouTube Github


How we configure each GitHub repo to maximize teamwork

US (English)   Norsk (Norwegian)   Español (Spanish)   Français (French)   Deutsch (German)   Italiano   Português   Estonian   اَلْعَرَبِيَّةُ (Egypt Arabic)   Napali   中文 (简体) Chinese (Simplified)   日本語 Japanese   한국어 Korean


This article describes how to configure GitHub to maximize teamwork.

NOTE: Content here are my personal opinions, and not intended to represent any employer (past or present). “PROTIP:” here highlight information I haven’t seen elsewhere on the internet because it is hard-won, little-know but significant facts based on my personal research and experience.

.gitignore in root folder

This defines all the folders and files which should NOT be pushed up to GitHub for the team to see. We look at this first because it summarizes many of the various utilities used:

See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# macOS:
# NodeJs dependencies:
# testing
# production
# misc
# ReactJs:

package.json in root

For NodeJs developers, there are two competing utilities to automate install of dependencies specified in import statements within NodeJs code:: npm vs. yarn:

  • yarn users create a yarn.json file.

  • npm users create a package.json file

Here is a sample package.json file:

  "name": "ps-serverless-app",
  "private": true,
  "workspaces": [
  "scripts": {
    "lint": "npx eslint . --fix --ext .js,.ts,.jsx",  
    "test": "",
    "load:sampleData": "aws dynamodb batch-write-item --request-items file://sampleData.json"
  "devDependencies": {
    "@types/jest": "^26.0.15",
    "@typescript-eslint/eslint-plugin": "^4.6.1",
    "@typescript-eslint/parser": "^4.6.1",
    "@babel/eslint-parser": "^7.13.14",
    "eslint-config-airbnb": "^18.2.1",
    "esbuild": "0",
    "eslint": "^7.12.1",
    "eslint-config-airbnb-base": "^14.2.1",
    "eslint-config-airbnb-typescript": "^12.0.0",
    "eslint-config-airbnb-typescript-prettier": "^3.1.0",
    "eslint-config-prettier": "^6.15.0",
    "eslint-import-resolver-node": "^0.3.4",
    "eslint-import-resolver-typescript": "^2.3.0",
    "eslint-plugin-eslint-comments": "^3.2.0",
    "eslint-plugin-import": "^2.22.1",
    "eslint-plugin-jest": "^24.1.0",
    "eslint-plugin-prettier": "^3.1.4",
    "eslint-plugin-promise": "^4.2.1",
    "eslint-plugin-simple-import-sort": "^5.0.3",
    "eslint-plugin-unicorn": "^23.0.0",
    "husky": "^4.3.0",
    "jest-html-reporter": "^3.3.0",
    "jest-junit": "^12.0.0",
    "lint-staged": "^10.5.1",
    "prettier": "^2.1.2",
    "prettier-eslint": "^11.0.0",
    "ts-jest": "^26.4.3",
    "typescript": "^4.0.5"
  "resolutions": {
    "@typescript-eslint/eslint-plugin": "^4.6.1",
    "@typescript-eslint/parser": "^4.6.1",
    "jest": "26.6.0"
  • “dependencies” are packages required by the app in production.

  • “devDependencies” are packages that are only needed for local development and testing.

  • “resolutions” specifies custom package versions or ranges instead of waiting for the author of transitive sub-dependencies to update their package dependencies (to resolve a GitHub Dependabot alert). Or your dependency defines a broad version range and your sub-dependency has a problematic update so you want to pin it to an earlier version.

      "resolutions": {
      "@typescript-eslint/eslint-plugin": "^4.6.1",
      "@typescript-eslint/parser": "^4.6.1",
      "jest": "26.6.0"

So “jest”: “26.6.0” serves to specify a version without the security vulnerability which should be used inside transitive dependencies.

If you use yarn, the above is instead of manual edits in the yarn.lock file before running yarn install.

Scripts in npm package.json


  • https://levelup.gitconnected.com/understanding-dependency-management-with-node-modules-1c47bcdee98b
  • https://medium.com/learnwithrahul/understanding-npm-dependency-resolution-84a24180901b
  • https://www.digitalocean.com/community/tutorials/how-to-use-node-js-modules-with-npm-and-package-json
  • https://juffalow.com/blog/javascript/how-yarn-resolutions-can-save-you/
  • https://www.linkedin.com/learning/github-dependabot-dependency-updates/get-started-with-dependabot

However, if you use npm rather than yarn, you can change the package-lock.json file and running npm, use overrides use github.com/rogeriochaves/npm-force-resolutions which forces the installation of specific version of a transitive dependency, as a last resort after contacting maintainers of top-level dependency libraries.

  1. The utility uses Clojure, which requires Java JDK 6+. Clojure has the Leiningen build tool. So install Clojure (one time on the macOS machine running npm)


    brew install clojure/tools/clojure

    NOTE: Clojure has rlwarp for tab completions and parenthesis matching.

  2. Verify install:

    which clojure


  3. Cleanup: remove the downloaded installers:

    rm -rf "${HOME}/.src"
  4. Clojure has an uncommon way to check whether it is installed:

    clj -e '(+ 1 1)'

    should return 2 and take you back to the Terminal prompt.

    NOTE: clj -e nil returns “WARNING: Implicit use of clojure.main with options is deprecated, use -M” and puts you in the Clojure REPL “user=>”.

  5. To invoke the script using npx, add to package-json

      "scripts": {
     "preinstall": "npx npm-force-resolutions"
  6. Run npm install as you would normally do at your project’s folder:

    npm install
  7. Use a text editor to open the package-lock.json file created:

    cat package-lock.json

    This file should be comitted and pushed to GitHub (it should not be specified within .gitignore).

  8. Verify that the package version has been updated to the new value.

ESLint install

  1. In package.json, npx eslint temporarily installs and runs eslint (on every run).
      "resolutions": {
     "@typescript-eslint/eslint-plugin": "^4.6.1",
     "@typescript-eslint/parser": "^4.6.1",
  2. In .vscode/settings.json

    This invokes ESLint on each save:

      "editor.codeActionsOnSave": {
     "source.fixAll.eslint": true

    ESLint catches “code smells” according to a set of rules hopefully agreed upon by the team, which is why it’s in the team’s GitHub instead of locally on your laptop.

  3. In file .eslintignore

  4. In file .eslintrc

      "root": true,
      "parser": "@babel/eslint-parser",
      "parserOptions": {
     "requireConfigFile": false

babel.config.js in root

  1. Within babel.config.js in root folder:

    module.exports = {
      presets: ['@babel/preset-env', '@babel/preset-react'],
      targets: {
     node: 'current',