I use Linux Mint as my daily OS at home. I use Windows as my daily OS at work. And I use both for web development. I don’t own a Mac, so I can’t say for sure that this guide will work for those, but it shouldn’t be too far off - if at all.
Whatever operating system you use, I trust that you know your way around it well enough that I don’t have to tell you how to install and configure software. With that in mind, I’ll give you a high-level rundown of how I have my development environment setup.
For all practical purposes, it’s probably easier if you install Node, Git, and VS Code first, and then use your Bash (Git Bash) terminal to find your config files, and VS Code to edit them.
You can easily find the config files listed below by opening a bash terminal and typing:
cd
ls -al
and look for the files (.bashrc, .gitconfig, .npmrc).
If VS Code is installed, you should be able to open each file with the code command.
code ~/.bashrc
code ~/.gitconfig
code ~/.npmrc
Nodejs
There are many download options for NodeJS.
If you’re using Linux you will need to choose the link to Install via Package Manager.
If you’re running a Debian or Ubuntu based distro, then you can find the install instructions here: https://github.com/nodesource/distributions
.npmrc
If you have authTokens for npm or github or anywhere else, you can add them here too. Any proxy configs you might have to use would also go in here.
.npmrc
”~/.npmrc”
Link to original prefix=/home/username/npm init-author-name=Your Name init-version=0.0.1 init-license=MIT save-exact=true package-lock=false ignore-scripts=false save-prefix= fund=false
Git
Downloading and installing git is pretty straight forward. Grab the installer you need from the downloads page and follow the prompts when you run it.
Make sure to install Bash if given the option.
.gitconfig
You will want to add your email and name so that you don’t get prompted every time you commit.
Add the core.editor = code setting to use VS Code as your editor whenever git prompts you for input on anything.
I added some aliases as an example. You would type git adog to show the oneline graph log.
And you can change the name of your default branch if you don’t want it to be “master.”
.gitconfig
~/.gitconfig
Link to original [user] email = your@email.com name = Your Name [push] default = simple followTags = true [core] editor = code [pull] rebase = false [alias] adog = log --all --decorate --oneline --graph logn = log --abbrev-commit --all --decorate --graph --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' [init] defaultBranch = master
Bash
If you’re running Linux or Mac, then you probably already have bash (or something like it - zsh) installed. If you’re on Windows, then you will have installed Bash when you installed Git For Windows.
If you have zsh or csh or something else, then you will need to edit your .zshrc, or whatever respective rc file your terminal uses.
Here I’m showing you how to export tab-completeable shortcuts that you can use instead of having to type out the full path every time you cd to a folder, or run a command.
I make full use of the aliases so that I don’t have to type out repetitive commands, and some of them I don’t use often enough to memorize them so I just type something and hit tab a couple times to see what my options are, which is a quick way to get a reminder of things I’ve aliased.
.bashrc
.bashrc
”~/.bashrc”
Link to original export PATH="$HOME/npm/bin:$HOME/bin:$HOME/.local/bin:$PATH" export PROJECTS="$HOME/dev/projects" export UTILS="$PROJECTS/utils" export NGCOMMON="$PROJECTS/ng-common" export NGSCHEMATICS="$PROJECTS/ng-schematics" alias ls="ls -a --color" alias editbashrc="code ~/.bashrc" alias editnpmrc="code ~/.npmrc" alias editgitconfig="code ~/.gitconfig" alias refreshbashrc=". ~/.bashrc" alias updatenpm="npm i -g npm" alias updatenpmcheckupdates="npm i -g npm-check-updates" alias updateangularcli="npm i -g @angular/cli@latest" alias nbuild="npm run build" alias nstart="npm start" alias ntest="npm test" alias ntestcov="npm run test:cov" alias ntestfile="npm run test:file" alias nlint="npm run lint" alias ncypress="npm run cypress" alias npushpatch="npm run push:patch" alias npushminor="npm run push:minor" alias npushmajor="npm run push:major" alias npmi="npm install --ignore-scripts" alias niutils="npm i -S @bjanderson/utils@latest" alias niclitool="npm i -g @bjanderson/cli-tool@latest" alias nimoneytoolshared="npm i -S @bjanderson/moneytool-shared@latest" alias ningcommon="npm i -S @bjanderson/ng-common@latest" alias ningschematics="npm i -D @bjanderson/ng-schematics@latest" alias ngcomponent="ng g @bjanderson/ng-schematics:component -n" alias ngdialog="ng g @bjanderson/ng-schematics:dialog -n" alias ngmodel="ng g @bjanderson/ng-schematics:model -n" alias ngservice="ng g @bjanderson/ng-schematics:service -n" alias ngstore="ng g @bjanderson/ng-schematics:store -n" alias ngtable="ng g @bjanderson/ng-schematics:table -n" alias ngtablewithdatasource="ng g @bjanderson/ng-schematics:table-with-data-source -n" alias ngtablewithserversidedatasource="ng g @bjanderson/ng-schematics:table-with-server-side-data-source -n" alias ngjest="ng g @bjanderson/ng-schematics:setup-jest" alias gs="git status" alias ga="git add -A" alias gc="git commit -m" alias gcamend="git commit --amend --no-edit" alias gcmaster="git checkout master" alias gcdev="git checkout dev" alias gcedits="git checkout edits" alias gmedits="git merge edits" alias gbdedits="git branch -d edits" alias gcbedits="git checkout -b edits" alias gnewedits="git branch -d edits && git checkout -b edits" function parse_git_branch () { git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/' } BLUE="\[\033[01;34m\]" GREEN="\[\033[0;32m\]" RED="\[\033[0;31m\]" WHITE="\[\033[0m\]" YELLOW="\[\033[0;33m\]" PS1="$BLUE\W$YELLOW\$(parse_git_branch)$BLUE\$$WHITE "
Visual Studio Code
The installer for VS Code is pretty straight forward too. Just grab the installer from the home page and follow the prompts when you run it. Make sure to select the option to include code in your PATH and to allow it to open files and folders from the right-click menu.
Extensions
VS Code Extensions
Link to original
- Angular Language Service: angular.ng-template
- EditorConfig for VS Code: editorconfig.editorconfig
- JavaScript (ES6) code snippets: xabikos.JavaScriptSnippets
- Prettier - Code formatter: esbenp.prettier-vscode
- Prettier ESLint: rvest.vs-code-prettier-eslint
- ESLint: dbaeumer.vscode-eslint
- REST Client: humao.rest-client
- SQLite: alexcvzz.vscode-sqlite
- IntelliCode: visualstudioexptteam.vscodeintellicode
- IntelliCode API Usage Examples: visualstudioexptteam.intellicode-api-usage-examples
Settings
VS Code Settings
Link to original { "angular.enable-strict-mode-prompt": false, "breadcrumbs.enabled": true, "css.lint.unknownProperties": "ignore", "css.lint.unknownVendorSpecificProperties": "ignore", "diffEditor.ignoreTrimWhitespace": true, "editor.autoClosingQuotes": "beforeWhitespace", "editor.autoIndent": "brackets", "editor.codeActionsOnSave": { "source.fixAll.eslint": true, "source.fixAll": true }, "editor.cursorSurroundingLines": 5, "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnPaste": true, "editor.formatOnSave": true, "editor.insertSpaces": true, "editor.minimap.enabled": true, "editor.minimap.showSlider": "always", "editor.multiCursorModifier": "ctrlCmd", "editor.scrollBeyondLastLine": false, "editor.snippetSuggestions": "top", "editor.suggestSelection": "first", "editor.suggest.preview": true, "editor.suggest.showDeprecated": false, "editor.tabCompletion": "on", "editor.tabSize": 2, "editor.trimAutoWhitespace": true, "eslint.alwaysShowStatus": true, "eslint.codeActionsOnSave.mode": "problems", "eslint.format.enable": true, "eslint.options": { "extensions": [".html", ".ts", ".tsx", ".js", ".jsx"] }, "eslint.validate": ["javascript", "typescript"], "explorer.confirmDelete": true, "explorer.confirmDragAndDrop": true, "extensions.ignoreRecommendations": true, "files.insertFinalNewline": true, "files.trimFinalNewlines": true, "files.trimTrailingWhitespace": true, "html.format.enable": true, "html.format.endWithNewline": true, "html.format.wrapAttributes": "force-expand-multiline", "html.format.wrapLineLength": 50, "javascript.format.enable": false, "javascript.format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": true, "javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": true, "javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": true, "javascript.format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": true, "javascript.preferences.quoteStyle": "single", "javascript.suggest.completeFunctionCalls": true, "javascript.updateImportsOnFileMove.enabled": "never", "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true }, "js/ts.implicitProjectConfig.experimentalDecorators": true, "less.lint.unknownProperties": "ignore", "less.lint.unknownVendorSpecificProperties": "ignore", "rest-client.enableTelemetry": false, "scss.lint.unknownProperties": "ignore", "scss.lint.unknownVendorSpecificProperties": "ignore", "security.workspace.trust.untrustedFiles": "open", "typescript.format.enable": false, "typescript.format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": true, "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": true, "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": true, "typescript.format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": true, "typescript.preferences.quoteStyle": "single", "typescript.suggest.completeFunctionCalls": true, "typescript.updateImportsOnFileMove.enabled": "never", "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true }, "telemetry.telemetryLevel": "off", "vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue", "window.zoomLevel": 0, "workbench.editor.enablePreview": false, "workbench.startupEditor": "none" }
Keybindings
VS Code Keybindings
Link to original [ { "key": "ctrl+shift+s", "command": "workbench.action.files.saveAll" }, { "key": "ctrl+up", "command": "editor.action.insertCursorAbove", "when": "editorTextFocus" }, { "key": "ctrl+shift+up", "command": "-editor.action.insertCursorAbove", "when": "editorTextFocus" }, { "key": "ctrl+down", "command": "editor.action.insertCursorBelow", "when": "editorTextFocus" }, { "key": "ctrl+shift+down", "command": "-editor.action.insertCursorBelow", "when": "editorTextFocus" }, { "key": "ctrl+shift+/", "command": "editor.action.blockComment", "when": "editorTextFocus && !editorReadonly" }, { "key": "ctrl+shift+a", "command": "-editor.action.blockComment", "when": "editorTextFocus && !editorReadonly" }, { "key": "alt+q", "command": "sqlite.runSelectedQuery" } ]
Snippets
html
VS Code HTML Snippets
Link to original "ahref": { "prefix": "ahref", "description": "a:href target blank", "body": [ "<a href=\"$1\" target=\"_blank\" rel=\"noopener noreferrer\">$2</a>" ] }, { "href target blank": { "prefix": "target=", "body": [ "target=\"_blank\" rel=\"noopener noreferrer\"" ], "description": "href target blank" }, "mat-icon": { "prefix": "mat-icon", "body": [ "<mat-icon class=\"icon\" aria-hidden=\"true\" fontSet=\"fas\" fontIcon=\"fa-$0\"></mat-icon>" ], "description": "mat-icon" }, "language-bash": { "prefix": "language-bash", "body": [ "<code class=\"language-bash\">$0</code>" ], "description": "language-bash" }, "language-javascript": { "prefix": "language-javascript", "body": [ "<code class=\"language-javascript\">$0</code>" ], "description": "language-javascript" }, "language-text": { "prefix": "language-text", "body": [ "<code class=\"language-text\">$0</code>" ], "description": "language-text" } }
javascript
VS Code JavaScript Snippets
Link to original { "Print to console": { "prefix": "llog", "body": ["console.log('$0');"], "description": "Log output to console" }, "Print vlaue to console": { "prefix": "ccl", "body": ["console.log('$0: ', $0);"], "description": "Log value to console" }, "noop": { "prefix": "noop", "body": ["() => undefined"], "description": "noop" }, "import": { "prefix": "import", "body": ["import { $2 } from '$1';"], "description": "import" }, "describe test": { "prefix": "desc", "body": ["describe('$0', () => {", "", "});"], "description": "describe test" }, "create test": { "prefix": "itt", "body": [ "it('$0', () => {", " const expected = '';", " const result = '';", " expect(result).toEqual(expected);", "});" ], "description": "create test" }, "create test with spy": { "prefix": "ittspy", "body": [ "it('calls $0', () => {", " spyOn(component, '$0').and.returnValue(null);", " component.();", " expect(component.$0).toHaveBeenCalled();", "});" ], "description": "create test with spy" }, "filter": { "prefix": "filter", "body": ["filter((v,i,a) => a.indexOf(v) === i)"], "description": "filter unique values in an array" } }
typescript
VS Code TypeScript Snippets
Link to original { "filterunique": { "prefix": "filterunique", "body": ["${TM_SELECTED_TEXT}.filter((v,i,a) => a.indexOf(v) === i)"] }, "filteruniqueobject": { "prefix": "filteruniqueobject", "body": ["${TM_SELECTED_TEXT}.filter((v,i,a) => a.findIndex((x) => x.id === v.id) === i)"] }, "sort": { "prefix": "sort", "body": ["${TM_SELECTED_TEXT}.sort((a,b) => a.localeCompare(b))"] }, "noop": { "prefix": "noop", "body": ["() => undefined"] }, "import": { "prefix": "import", "body": ["import { $2 } from '$1';$0"] }, "export": { "prefix": "export", "body": ["export * from '$1';$0"] }, "mockservice": { "prefix": "mockservice", "body": ["const $0: any = {", " $0: () => undefined,", "};"] }, "import-angular-core-mock": { "prefix": "import-angular-core-mock", "body": ["import '../../../mocks/@angular/core/core.mock';"] }, "describe test": { "prefix": "describetest", "body": [ "describe('$1', () => {", " beforeEach(() => {", " init();", " });", "", " it('has a function named $1', () => {", " expect(typeof ${2|component,service|}.$1).toEqual('function');", " });", "", " it('returns expected', () => {", " const expected = '';", " const result = ${2|component,service|}.$1();", " expect(result).toEqual(expected);", " });", "});" ] }, "it test": { "prefix": "ittest", "body": [ "it('returns expected', () => {", " const expected = '';", " const result = ${2|component,service|}.$1();", " expect(result).toEqual(expected);", "});" ] }, "it test spy": { "prefix": "itspy", "body": [ "it('calls $1', () => {", " const spy = spyOn(${2|component,service|}, '$1').and.callThrough();", " const arg = 'test arg';", " const request = new Request({ arg });", " ${2|component,service|}.$3(request);", " expect(spy).toHaveBeenCalledWith(arg);", "});" ] }, "mock function spy from clipboard": { "prefix": "mockfunctionspy", "body": [ "export const calls${CLIPBOARD/^(\\S+)\\s+(.*)$/${1:/capitalize}/g}${CLIPBOARD/^(.*?)\\s+(.*)/${2:/capitalize}/g} = (testSubject: () => unknown, calledWith?: unknown[]) => {", " it('calls ${CLIPBOARD/^(\\S+)\\s+(.*)$/$1/g}.${CLIPBOARD/^(.*?)\\s+//g}', () => {", " const spy = spyOn(${CLIPBOARD/^(\\S+)\\s+(.*)$/$1/g}, '${CLIPBOARD/^(.*?)\\s+//g}').and.callThrough();", " testSubject();", " callsSpy(spy, calledWith);", " });", "};" ], "description": "copy a service name and a function name (multi-cursor) to the clipboard and run this snippet to create a mock test from them" }, "mock selected function spy": { "prefix": "mockselectedfunctionspy", "body": [ "export const callsSvc${TM_SELECTED_TEXT/(.*)/${1:/capitalize}/g} = (testSubject: () => unknown, calledWith?: unknown[]) => {", " it('calls svc.${TM_SELECTED_TEXT/(.*)/$1/g}', () => {", " const spy = spyOn(svc, '${TM_SELECTED_TEXT/(.*)/$1/g}').and.callThrough();", " testSubject();", " callsSpy(spy, calledWith);", " });", "};" ], "description": "highlight a function name and type mockselectedfunctionspy to run this snippet and create a mock test from the highlighted text" }, "Create Server Model": { "prefix": "smodel", "body": [ "import { getObject, getString } from '@bjanderson/utils';", "import { IHasPK } from './ihaspk';", "", "export class $0 implements IHasPK {", " pk: string;", "", " constructor(o?: Partial<$0>) {", " const obj: Partial<$0> = getObject(o);", " this.pk = getString(obj.pk);", " }", "}" ], "description": "Create Server Model" }, "Print to console": { "prefix": "clog", "body": ["console.log('$0');"], "description": "Log output to console" }, "Print vlaue to console": { "prefix": "clvalue", "body": ["console.log('$0: ', $0);"], "description": "Log value to console" }, "Print error to console": { "prefix": "clerror", "body": ["console.error(`ERROR : $1 : ${$0}`);"], "description": "Log error to console" }, "ngOnDestroy unsubscribe": { "prefix": "ngOnDestroy", "body": [ "unsubscribe = new Subject();", "ngOnDestroy(): void {", " this.unsubscribe.next();", " this.unsubscribe.complete();", "}" ], "description": "ngOnDestroy unsubscribe" }, "new class": { "prefix": "newclass", "body": [ "import { getObject, getString } from '@bjanderson/utils';", "", "export class $0 {", "", " value: string;", "", " constructor(obj?: Partial<$0>) {", " obj = getObject(obj);", " this.value = getString(obj.value);", " }", "}" ], "description": "new class" } }
css
VS Code CSS Snippets
Link to original { "css-starter": { "prefix": "css-starter", "body": [ "html {", " box-sizing: border-box;", "}", "", "*,", "*:before,", "*:after {", " box-sizing: inherit;", "}", "", "html, body {", " font-family: system-ui;", " font-size: 16px;", " height: 100%;", " width: 100%;", " margin: 0;", " padding: 0;", "}" ], "description": "css-starter" } }
scss
VS Code SCSS Snippets
Link to original { "css-starter": { "prefix": "css-starter", "body": [ "html {", " box-sizing: border-box;", "}", "", "*,", "*:before,", "*:after {", " box-sizing: inherit;", "}", "", "html, body {", " font-family: system-ui;", " font-size: 16px;", " height: 100%;", " width: 100%;", " margin: 0;", " padding: 0;", "}" ], "description": "css-starter" } }