Mac Visual Studio Code

Installing and Configuring Visual Studio Code on a Mac

Mac Visual Studio Code

by John Vincent


Posted on November 19, 2021


Including configuration of ESLint, AirBnb, React, Express, Webpack and Prettier

There are also notes regarding debugging Express, Mocha and Webpack and Fixing ESLint errors.

Visual Studio Code

The underlying software is constantly changing and so this document is being continuously updated.

Visual Studio Code

Visual Studio Code Shortcuts

Downloaded for Mac and installed.

Command Line

"/Applications/Visual Studio Code.app/Contents/MacOS/Electron" <your-workspace>

Preferences

For Mac, preferences file is

/Users/jv/Library/Application Support/Code/User/settings.json

which is currently

{
  "editor.renderIndentGuides": false,
  "window.zoomLevel": 0,
  "editor.tabSize": 2,
  "editor.insertSpaces": false,
  "editor.detectIndentation": false,
  "prettier.useTabs": true,
  "prettier.trailingComma": "es5",
  "prettier.tabWidth": 2,
  "prettier.printWidth": 120,
  "prettier.singleQuote": true
}

The workspace settings file is located in your project at

.vscode/settings.json

Basic Commands

  • show all command: shift+command+p

  • go to file: command p

  • find in files: shift command f

  • start debugging: f5

  • toggle terminal: ^`

  • reformat code: Shift Option F

  • Help

    • command p
      • ?
  • List commands

    • command p
      • ?
      • >
  • Find a symbol

    • command p
      • ?
      • #

Extensions

To install an extension

  • View
  • Extensions
  • Search for the plugin
    • Install

Installed the following:

  • Bookmarks
  • ESLint Plugin
  • Import Cost
  • json
  • Live Server
  • npm intellisense
  • Open in Browser
  • Path intellisense - autocomplete filenames in your code.
  • Prettier - Code formatter
  • PrintCode
  • Search node_modules - Quickly search for node modules in your project.
  • To Do Tasks

May wish to install:

  • JavaScript ES6 Snippets
  • jQuery code snippets
  • Mocha Latte
  • REST Client

To Print Code

  • View
  • Command Palette
  • PrintCode

File is converted to Html and is shown in a browser from which it can be printed.

Create snippets

  • Code, Preferences, User Snippets

Use

  • New snippets file for
  • Provide a name, for example my

which will create file my.code-snippets in ~/.vscode

or

  • New Global snippets file

which will create file ~/Library/Application Support/Code/User/snippets/my.code-snippets

ESLint

To find ESLint package, see npm search

I have chosen to use Airbnb ESLint. Ref for details

Initial

This can be a useful starting point. I suggest you perform these steps in a junk directory.

cd 
cd tmp
mkdir junk
cd junk

Initialize a new project

npm init

Install eslint

npm i eslint --save-dev

Run eslint

/node_modules/eslint/bin/eslint.js --init

I chose:

  • To check syntax, find problems, and enforce code style
  • Airbnb rules

and then whatever best describes the use.

For example .eslintrc.json

{
    "env": {
        "browser": true,
        "commonjs": true,
        "es2021": true
    },
    "extends": [
        "airbnb-base"
    ],
    "parserOptions": {
        "ecmaVersion": 12
    },
    "rules": {
    }
}

package.json

{
  "name": "....",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "eslint": "^7.15.0",
    "eslint-config-airbnb-base": "^14.2.1",
    "eslint-plugin-import": "^2.22.1"
  }
}

Configure a project

I have chosen to configure ESLint on a per project basis.

Add to package.json, notice the versions:

"devDependencies": {
"eslint": "^4.9.0",
"eslint-config-airbnb": "^16.1.0",
"eslint-loader": "^1.9.0",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-jsx-a11y": "^6.0.2",
"eslint-plugin-react": "^7.4.0"
}

If using Prettier, also add:

"eslint-config-prettier": "^2.9.0",

get packages

npm install

Re-open the workspace.

Base ESLint Rules

There are a great multitude of available rules. See ESLint Rules

The following I have found to be useful for all projects.

Edit .eslintrc.json

  "rules": {
		"object-curly-spacing": ["error", "always", { "objectsInObjects": false }],
		"comma-spacing": ["error", { "before": false, "after": true }],
		"space-in-parens": ["error", "never"],
		"array-bracket-spacing": ["error", "never"],
		"semi": ["error", "always"],
		"key-spacing": ["error"],
		"comma-dangle": ["error", "never"],
		"no-trailing-spaces": "error",
		"no-console": 0,
		"indent": [2, "tab", { "SwitchCase": 1 }],
    "no-tabs": 0,
				"max-len": [
			"error",
			{
				"code": 120,
				"tabWidth": 2,
				"comments": 120
			}
		],
		...

Base Node ESLint Configuration

Create .eslintrc.json

{
  "extends": ["airbnb", "prettier"],
  "env": {
    "node": true,
    "browser": false,
    "es6": true
  },
  "globals": {},
  "rules": {
    "no-console": 0,
    "max-len": [
      "error",
      {
        "code": 120,
        "tabWidth": 2,
        "comments": 120
      }
    ],
    "indent": [2, "tab", { "SwitchCase": 1 }],
    "no-tabs": 0
  },
  "plugins": []
}

Base React ESLint Configuration

Create .eslintrc.json in client

{
  "extends": ["airbnb", "prettier", "prettier/react"],
  "env": {
    "browser": true
  },
  "parser": "babel-eslint",
  "globals": {},
  "rules": {
    "no-console": 0,
    "max-len": [
      "error",
      {
        "code": 120,
        "tabWidth": 2,
        "comments": 120,
        "ignoreTrailingComments": true,
        "ignoreUrls": true,
        "ignorePattern": "^import\\s.+\\sfrom\\s.+;$"
      }
    ],
    "indent": [2, "tab", { "SwitchCase": 1 }],
    "no-tabs": 0,
    "react/jsx-indent": ["off", 2],
    "react/jsx-indent-props": ["off", 2],
		"quotes": ["error", "single"],
		"jsx-quotes": [2, "prefer-single"],
    "jsx-a11y/anchor-is-valid": [
      "error",
      {
        "components": ["Link"],
        "specialLink": ["to"]
      }
    ],
		"react/destructuring-assignment": ["off", "always"],
		"react-hooks/rules-of-hooks": "error",
		"react-hooks/exhaustive-deps": "warn"
  },
  "plugins": ["react", "jsx-a11y", "import", "react-hooks"]
}

Base Express ESLint Configuration

Create .eslintrc.json in server

{
	"extends": "airbnb",
	"env": {
		"node": true,
		"browser": false,
		"es6": true
	},
	"globals": {},
	"rules": {
		"indent": [2, "tab"],
		"no-tabs": 0,
		"react/jsx-indent": ["off", 2],
		"react/jsx-indent-props": ["off", 2]
	},
	"plugins": []
}

Notice the extends clause.

Base Browser ESLint Configuration

Create .eslintrc.json

{
	"extends": [
		"airbnb",
		"prettier"
	],
	"env": {
		"node": false,
		"browser": true,
		"es6": false,
		"jquery": true
	},
	"globals": {},
	"rules": {
		"no-console": 0,
		"max-len": [
			"error",
			{
				"code": 120,
				"tabWidth": 2,
				"comments": 120
			}
		],
		"indent": [
			2,
			"tab",
			{
				"SwitchCase": 1
			}
		],
		"no-tabs": 0
	},
	"plugins": []
}

Notice the jquery clause

Configuring ESLint

ESLint User Guide is an excellent source. There are a vast number of options, too many to discuss here.

Useful ESLint commands

Add to package.json scripts

ESLint Versions

"eslint-versions": "npm info eslint-config-airbnb@latest peerDependencies",

will list the latest peer dependencies. Useful for checking which package versions to include.

ESLint / Prettier Configuration Check

"eslint-check": "eslint-config-prettier index.js",

checks your ESLint configuration looking for inconsistencies between your ESLint and prettier configurations. Useful if you are having difficulties with Prettier.

ESLint Your Code

"lint": "eslint 'src/**/*.{js,jsx}' --quiet",

performs ESLint on all code in src and its subfolders. All messages are written to stdout. Useful for viewing all ESLint problems in one place.

Note that folders may be ignored using .eslintignore

For example

node_modules

Removing ESLint errors

Switching directly to Airbnb ESLint, for one project, created far too many errors.

Thus, for this project, I chose to configure two linters

  • UI code
  • Node code

.eslintrc.json in project root

{
  "env": {
    "node": true,
    "browser": false,
    "es6": true
  },
  "globals": {
  },
  "rules": {
    "eqeqeq": 1,
    "strict":"off",
    "no-console": "off",
    "camelcase": "off",
    "no-unused-expressions": "off",
    "indent": "off",
    "comma-dangle": "off",
    "object-curly-spacing": "off",
    "import/newline-after-import": "off",
    "prefer-const":"off",
    "no-var":"off",
    "space-before-function-paren": "off",
    "quotes":"off",
    "prefer-template":"off",
    "space-infix-ops":"off",
    "quote-props":"off",
    "arrow-parens": "off",
    "consistent-return":"off",
    "guard-for-in":"off",
    "arrow-spacing":"off",
    "object-property-newline":"off",
    "no-underscore-dangle":"off",
    "prefer-arrow-callback":"off",
    "brace-style":"off",
    "func-names":"off",
    "class-methods-use-this":"off",
    "no-path-concat":"off",
    "no-param-reassign":"off",
    "space-unary-ops":"off",
    "max-len":"off",
    "padded-blocks":"off",
    "no-multiple-empty-lines":"off",
    "vars-on-top":"off",
    "no-unused-vars":"off"
  },
  "plugins": [
  ],
  "extends": "airbnb"
}

root/public/js/.eslintrc.json

{
  "env": {
    "node": false,
    "browser": true,
    "jquery": true
  },
  "globals": {
  },
  "rules": {
    "eqeqeq": 1,
    "no-console": "off",
    "camelcase": "off",
    "no-unused-expressions": "off",
    "indent": "off",
    "comma-dangle": ["off"],
    "prefer-arrow-callback": "off",
    "strict": "off",
    "no-var": "off",
    "vars-on-top": "off",
    "prefer-template": "off",
    "quotes": "off",
    "quote-props": "off",
    "space-infix-ops": "off",
    "space-before-function-paren": "off",
    "object-curly-spacing": "off",
    "no-shadow": "off",
    "brace-style": "off",
    "no-multiple-empty-lines": "off",
    "max-len": "off",
    "func-names": "off",
    "spaced-comment": "off",
    "wrap-life": "off",
    "no-multi-str": "off",
    "padded-blocks": "off",
    "wrap-iife": "off",
    "object-shorthand": "off"
  },
  "plugins": [
    //you can put plugins here
  ],
  "extends": "airbnb"
}

This removes all errors from the workspace.

Fixing ESLint errors

Now I have time to remove the rules one-by-one, cleaning the code in an orderly manner.

In Code Rules

/* eslint-env node, mocha */

/* global describe, it, before, beforeEach, after, afterEach */

/* global document */

/* global $ */

Inline Code Rules

// eslint-disable-next-line no-multi-str
// eslint-disable-next-line no-plusplus

// eslint-disable-next-line import/no-named-as-default
// eslint-disable-next-line react/prefer-stateless-function
// eslint-disable-next-line no-useless-constructor

// eslint-disable-next-line no-mixed-operators

// eslint-disable-next-line react/no-typos
// eslint-disable-next-line function-paren-newline

// eslint-disable-line no-param-reassign
// eslint-disable-line react/forbid-prop-types
// eslint-disable-line react/no-typos

Disable all occurrences within file

/* eslint-disable global-require */
/* eslint no-restricted-globals: ["off"] */
/* eslint-disable import/no-named-as-default */
/* eslint-disable no-underscore-dangle */
/* eslint-disable no-param-reassign */
/* eslint-disable class-methods-use-this */
/* eslint-disable import/prefer-default-export */
/* eslint-disable max-len */
/* eslint-disable no-console */
/* eslint-disable react/no-multi-comp */
/* eslint-disable no-case-declarations */
/* eslint-disable no-unused-vars */
/* eslint-disable import/no-extraneous-dependencies */

Maximum length, set to 150 characters

/* eslint max-len: [2, 150, 4] */ // maximum length of 150 characters
function doSomething(event) {
  // eslint-disable-next-line no-console
  console.log(event.currentTarget.getAttribute('data-something'));
}

Configuring Prettier Plugin

Thus can be a real pest seemingly frequently changing.

To change a Visual Studio Code preferences for all workspaces, edit preferences file.

For Mac, preferences file is

/Users/jv/Library/Application Support/Code/User/settings.json

If only wish to make the change for a workspace, change the workspace settings file which is located in your project at

.vscode/settings.json

The current setup

.vscode/settings.json

Add Format on Save

{
	"editor.defaultFormatter": "esbenp.prettier-vscode",
	"editor.codeActionsOnSave": {
		"source.fixAll.eslint": true
	},
	"editor.tabCompletion": "on",
	"editor.snippetSuggestions": "top"
}

Older versions

{
	"editor.formatOnSave": true,
	"editor.codeActionsOnSave": {
		"source.fixAll.eslint": true
	},
	"editor.tabCompletion": "on",
	"editor.snippetSuggestions": "top"
}

and

{
	"eslint.autoFixOnSave": true
}
  1. Disable the Prettier plugin

  2. .prettierrc

{
	"singleQuote": true,
	"semi": true,
	"tabWidth": 2,
	"trailingComma": "none",
	"useTabs": true,
	"printWidth": 120
}

Edit .eslintrc.json

"extends": ["airbnb", "prettier"],

Beware of max-len. The following will break Prettier

"max-len": [2, 100, 4],

Use the following code instead:

"max-len": ["error", {
	"code": 100,
	"tabWidth": 2
}]

or, better yet

"max-len": ["error", {
	"code": 100,
	"tabWidth": 2,
	"comments": 100,
	"ignoreTrailingComments": true,
	"ignoreUrls": true,
	"ignorePattern": "^import\\s.+\\sfrom\\s.+;$"
}]

Restart Visual Studio Code to enable the changes.

Prettier Plugin to Ignore Code

To ignore a piece of code, precede the code with

JavaScript
// prettier-ignore

JSX
{/* prettier-ignore */}

SCSS, CSS
/* prettier-ignore */

Markdown
<!-- prettier-ignore -->

To exclude files from formatting, add entries to the .prettierignore file in the project root.

Prettier, Quotes or Double Quotes

By default, Prettier uses double quotes.

To override and use single quotes, create file .prettierrc in root folder and enter:

"prettier.singleQuote": true,

or false for double quotes.

Debugger

Set conditional breakpoint

  • Right click the breakpoint
  • Enter the condition

Debugging Node Application

For simple usage:

  • Select .js file
  • F5 to start the debugger.

To add a configuration:

  • Debug icon (left nav)
  • Gear icon (top of debug view)

Which creates a default launch.json

Use Add Configuration if necessary to get to the following

{
	"type": "node",
	"request": "launch",
	"name": "Run my Application",
	"program": "${workspaceRoot}/directory/file.js",
	"args": ["arg1", "arg2"],
	"env": {
		"ENV_1": "value1",
		"ENV_2": "value2"
	}
}

Debugging Express Application

  • Debug icon (left nav)
  • Gear icon (top of debug view)

Which creates a default launch.json

Use Add Configuration if necessary to get to the following

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "attach",
            "name": "Attach to Process",
            "processId": "${command:PickProcess}",
            "port": 5858
        },
        {
            "type": "node",
            "request": "launch",
            "name": "Launch Program",
            "program": "${workspaceRoot}/server.js"
        },
				{
					"type": "node",
					"request": "launch",
					"name": "Launch Create-Music-Data",
					"program": "${workspaceRoot}/create-music-data/create-all.js",
					"runtimeArgs": ["--max-old-space-size=8192"]
				}
    ]
}
  • Open file to debugged and set a breakpoint.
  • F5 to start debugging app

Mocha

Install extensions

To run tests:

  • Command Palette (Shift+CMD+P)
  • Mocha: Run all tests

Debugging Mocha

  • Debug icon (left nav)
  • Gear icon (top of debug view)
  • Which edits launch.json

Add the following configuration

{
// Name of configuration; appears in the launch configuration drop down menu.
	"name": "Run mocha",
// Type of configuration. Possible values: "node", "mono".
	"type": "node",
// Workspace relative or absolute path to the program.
	"program": "${workspaceRoot}/node_modules/mocha/bin/_mocha",
// Automatically stop program after launch.
	"stopOnEntry": false,
// Command line arguments passed to the program.
	"args": ["test/**/*.js", "--no-timeouts"],
// Workspace relative or absolute path to the working directory of the program being debugged. Default is the current workspace.
	"cwd": "${workspaceRoot}",
// Workspace relative or absolute path to the runtime executable to be used. Default is the runtime executable on the PATH.
	"runtimeExecutable": null,
// Environment variables passed to the program.
	"env": { "NODE_ENV": "testing"}
},
  • Debug view (top nav)
  • Set a breakpoint.
  • Select 'Run Mocha'
  • Click on the green arrow icon to start debugging.

Debugging Webpack

  • Debug icon (left nav)
  • Gear icon (top of debug view)

Which creates a default launch.json

For this example:

  • ${workspaceRoot} is VSCode root directory
  • webpack/play-4 is the root directory of the project code.

Use Add Configuration if necessary to get to the following

{
    "version": "0.2.0",
    "configurations": [
      {
        "type": "node",
        "request": "launch",
        "name": "Run webpack",
        "program": "${workspaceRoot}/webpack/play-4/node_modules/.bin/webpack",
        "cwd": "${workspaceRoot}/webpack/play-4/",
        "args": [ 
          "--config",
					"${workspaceRoot}/webpack/play-4/webpack.config.js",
					"--context",
					"${workspaceRoot}/webpack/play-4",
					"--output-path",
					"${workspaceRoot}/webpack/play-4/dist"
        ]
      },
      {
        "type": "node",
        "request": "launch",
        "name": "Launch Program",
        "program": "${file}"
      }
    ]
}
  • Open webpack.config.js and set a breakpoint.
  • F5 to start debugging app

Debugging Mocha / Webpack

  • Debug icon (left nav)
  • Gear icon (top of debug view)

Which creates a default launch.json

Use Add Configuration if necessary to get to the following

{
	"type": "node",
	"request": "launch",
	"name": "Run mocha",
	"program": "${workspaceRoot}/node_modules/mocha/bin/_mocha",
	"stopOnEntry": true,
	"args": ["test/**/*.js", "--recursive", "--compilers", "js:babel-register", "--no-timeouts", "--devtool", "source-map"],
	"cwd": "${workspaceRoot}",
	"runtimeExecutable": null,
	"env": { "NODE_ENV": "testing"}
},
  • Use debugger statements
  • F5 to start debugging app

Debugging React

This is easiest to perform with Chrome Developer Tools.

  • Sources
  • Webpack
  • .
  • find the source file
  • Open the file
  • Set breakpoints etc

Debugging React with Enzyme and Jest

  • Debug icon (left nav)
  • Gear icon (top of debug view)

Which creates a default launch.json

Use Add Configuration if necessary to get to the following

{
	"type": "node",
	"request": "launch",
	"name": "Debug Enzyme Jest",
	"program": "${workspaceRoot}/node_modules/jest/bin/jest.js",
	"args": ["-i"],
	"cwd": "${workspaceRoot}",
	"outFiles": ["${workspaceRoot}/dist/**/*"],
	"env": {
		"NODE_ENV": "development"
	},
	"envFile": "${workspaceRoot}/.env"
}
  • Use debugger statements
  • F5 to start debugging app

Note

  • args -i causes jest to run tests asynchronously

To obtain useful debug messages, use debug() or html()

const ahref = countries.find('.country').at(1).find('a');
console.log('ahref ', ahref.debug());

Debugging Next.js

Add to .vscode/launch.json

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "attach",
      "name": "ORIG",
      "skipFiles": ["<node_internals>/**"],
      "port": 9229
		}
	]
}

To run the debugger

  • Set a break point
  • Select Debug mode
  • Select node.js (preview)
  • Select Run Script: dev nextjs-website
  • Start the debugger
  • Run the app http://localhost:3200/

Debugger will stop at the break point.

Using Chrome Inspector

Add to package.json

"scripts": {
	"inspect": "node --inspect src/main.js",
},

Set a breakpoint and run

npm run inspect

From Chrome browser

chrome://inspect

See

  • Remote Target
  • Click on your node app

JavaScript CPU Profiler

  • Profiler
  • Start & Stop

Displays Functions by Total Time.

Memory

  • Heap Snapshot
  • Take snapshot

Take multiple snapshots to determine where additional resources are being accumulated.

  • Allocation instrumentation on timeline
  • Stop

Useful

  • Summary, also with a timeline
  • Class filter, find my code
  • Statistics