A Working Setup: Formatting, Linting and Live Preview

Consistent formatting, markup linting, live reload and shared settings. A day of setup that pays back on every file afterwards.

Concept

The difference between a comfortable project and a frustrating one is largely tooling that runs without being asked. Four things are worth setting up once.

1. Automatic formatting

A formatter rewrites files to a consistent style on save. It ends indentation arguments permanently, because nobody is formatting by hand any more.

// .vscode/settings.json - committed, so the whole team shares it
{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.tabSize": 2,
  "files.trimTrailingWhitespace": true,
  "files.insertFinalNewline": true
}
// .prettierrc
{
  "printWidth": 100,
  "tabWidth": 2,
  "singleQuote": false,
  "htmlWhitespaceSensitivity": "css"
}

The htmlWhitespaceSensitivity setting matters for HTML specifically. Whitespace between inline elements is rendered as a space, so a formatter that reflows freely can change how a page looks. The css value tells it to respect the display value of each element.

EditorConfig

# .editorconfig - respected by nearly every editor
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false

Worth adding to every project. It is a single small file and it works across editors, which a formatter configuration alone does not.

2. Markup linting

A formatter makes files look consistent. A linter tells you the markup is wrong.

npm install --save-dev html-validate
// .htmlvalidate.json
{
  "extends": ["html-validate:recommended"],
  "rules": {
    "require-sri": "off",
    "no-inline-style": "warn"
  }
}
npx html-validate "src/**/*.html"

It catches duplicate ids, bad nesting, missing alt, obsolete attributes and unclosed tags - as you work, rather than at launch.

Accessibility linting

An accessibility linter catches a further class of problem: an anchor with no href, an aria-* attribute on an element that does not support it, a positive tabindex, an image with a redundant alt.

3. Live preview

A local server that reloads the browser on save.

# any of these serve the current folder with live reload
npx live-server
npx browser-sync start --server --files "**/*"
python -m http.server 8000          # no reload, but no install either

Editor extensions do the same with one click. Whatever you use, serve over HTTP rather than opening the file directly - root relative paths, modules, fetch and several browser APIs behave differently over file://, and every one of those differences is a bug you will otherwise find at deployment.

Testing from a phone

Browser Sync prints a network address alongside the local one. Opening that on a phone on the same network shows the real page on real hardware, with real touch behaviour - which no emulator reproduces.

4. Snippets

Emmet covers general structure. Snippets cover the specific blocks you write repeatedly in this project.

// .vscode/html.code-snippets
{
  "Labelled field": {
    "prefix": "field",
    "body": [
      "

", " ", " ", "

" ], "description": "A labelled form field" }, "Responsive image": { "prefix": "rimg", "body": [ "$2" ] } }

$1 and $2 are tab stops; repeating $1 fills both places at once. The pipe syntax offers a dropdown of choices.

Committing snippets to .vscode/ shares them with everyone on the project, which quietly enforces house patterns better than a style document does.

Extensions worth having

PurposeWhat it gives you
FormatterConsistent files with no effort
HTML validatorMarkup errors as you type
Accessibility linterMissing labels, bad ARIA, positive tabindex
Auto rename tagClosing tag follows the opening one
Path autocompleteSuggests real file paths in src and href
Colour highlightShows colour values inline
Live serverReload on save
Spell checkerTypos in visible text, which readers do notice

Resist installing thirty. Each one costs startup time and adds a way for the editor to behave unexpectedly.

Committing the configuration

project/
  .editorconfig            committed
  .prettierrc              committed
  .htmlvalidate.json       committed
  .vscode/
    settings.json          committed - shared project settings
    extensions.json        committed - recommended extensions
    html.code-snippets     committed - shared snippets
  .gitignore
// .vscode/extensions.json - prompts new contributors to install these
{
  "recommendations": [
    "esbenp.prettier-vscode",
    "formulahendry.auto-rename-tag",
    "ritwickdey.liveserver"
  ]
}

A new contributor clones the repository, opens it, accepts the prompt, and has the same setup as everyone else in two minutes.

Checks in the build

// package.json
{
  "scripts": {
    "lint:html": "html-validate "src/**/*.html"",
    "lint:a11y": "pa11y-ci",
    "format:check": "prettier --check "src/**/*.{html,css,js}"",
    "check": "npm run format:check && npm run lint:html && npm run lint:a11y"
  }
}

Run check in continuous integration and a broken page cannot reach the main branch. This is what stops quality decaying over months, which manual discipline reliably fails to do.

Important rules

  • Serve over HTTP, not file://.
  • HTML whitespace is significant between inline elements; configure the formatter accordingly.
  • Commit configuration so everyone shares it.
  • A formatter is not a linter. You want both.
  • Automated checks in CI are what make the standard stick.

Common mistakes

  • Opening files directly and hitting path problems only at deployment.
  • Formatting by hand.
  • Configuration kept locally, so every contributor formats differently.
  • A formatter that reflows inline elements and changes spacing on the page.
  • Thirty extensions and a slow editor.
  • No checks in the build, so standards slip silently.

Best practices

  • Add .editorconfig to every project.
  • Turn on format on save immediately.
  • Add a markup validator and an accessibility linter.
  • Use a live server, and test on a phone over the network address.
  • Write snippets for repeated project patterns and commit them.
  • Run format, validate and accessibility checks in CI.

Practice

  1. Set up a project with .editorconfig, a formatter and format on save.
  2. Add a markup validator and fix everything it reports on one page.
  3. Start a live server and open the page on a phone using the network address.
  4. Write a snippet for a pattern you type often and use it five times.

Useful resources

Hand picked references for this topic
Written by Lorens Mishra

Software Engineer Notes Management System Administrator

Continue reading

All HTML notes →
HTML

Final HTML Assessment

Forty questions covering the whole path, from document structure to SEO and accessibility. Sample questions only - no answers, no submission.

Read more
HTML

Project Exams

Five larger assessments where the deliverable is a working site. Requirements, constraints and a rubric for each.

Read more

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.