I understand the appeal of a browser textbox when someone hands you a wall of markup. Paste, click, breathe again. But formatting alone cannot prove that HTML is valid, CSS behaves correctly, or JSON has the shape your application expects—and sending private source to an unknown service can create a security incident. A small local toolchain is safer and repeatable.

Four jobs that are often confused

  • A formatter rewrites whitespace and layout to a consistent style.

  • A linter reports suspicious, invalid, inaccessible, or policy-breaking patterns.

  • A validator/parser checks whether input follows a syntax; schema validation also checks structure and constraints.

  • A minifier removes delivery bytes and may transform syntax while aiming to preserve behavior.

  • A formatter is not automatically a validator, and a successful minifier is not proof that the result works in every target browser.

A practical local stack

  • Prettier for deterministic HTML, CSS, and JSON formatting.

  • HTML-validate for configurable HTML linting and structural rules.

  • Stylelint for CSS correctness and project conventions.

  • jq or Python’s standard-library JSON tool for strict JSON parsing and readable output.

  • Ajv or another standards-aware validator when JSON must satisfy a JSON Schema.

  • A reviewed bundler/minifier such as cssnano in the production build—not an ad hoc copy/paste step.

1. Create a project-owned tool environment

Web project rootbash
npm init -y
npm install --save-dev --save-exact prettier html-validate stylelint stylelint-config-standard
added development dependencies and updated package-lock.json

Risk level: caution. Review the command before running it.

Review the dependency change before committing

  • --save-dev records build-quality tools as development dependencies.

  • --save-exact avoids a range in package.json; the lockfile captures the resolved dependency graph.

  • npm init -y creates a manifest and should not overwrite an established project setup.

  • Inspect package provenance, licenses, install scripts, vulnerability reports, and the lockfile diff under your organization’s supply-chain policy.

  • CI should use the project lockfile, commonly through npm ci, rather than resolving fresh versions.

2. Format HTML, CSS, and JSON with Prettier

.prettierrc.jsonjson
{
  "printWidth": 100,
  "singleQuote": true,
  "tabWidth": 2,
  "useTabs": false
}

Keep formatting policy intentionally small

  • The config is valid JSON, so property names and strings use double quotes.

  • printWidth is a wrapping preference, not a hard maximum for every construct.

  • Prettier may normalize embedded CSS/JavaScript when it can parse the surrounding file.

  • Avoid turning every preference into debate; formatter value comes from deterministic automation.

  • Ignore generated, vendor, minified, and other non-source files with a reviewed .prettierignore.

Web project rootbash
npx prettier --check "src/**/*.{html,css,json}"
npx prettier --write "src/**/*.{html,css,json}"
Checking formatting...
All matched files use Prettier code style!

Risk level: caution. Review the command before running it.

Check in CI; write in development

  • --check exits nonzero when matched files need formatting and does not rewrite them.

  • --write mutates every matched source file, so run it with a clean/known worktree and review the diff.

  • The quoted glob is passed to Prettier rather than expanded inconsistently by the shell.

  • Formatting cannot identify every missing semantic element, accessibility error, or invalid data relationship.

  • Do not run a formatter blindly over generated snapshots, vendor files, or templates whose syntax needs a plugin not yet reviewed.

3. Lint HTML structure and accessibility hooks

.htmlvalidate.jsonjson
{
  "extends": ["html-validate:recommended"],
  "rules": {
    "attr-quotes": ["error", { "style": "double" }],
    "no-dup-id": "error"
  }
}

Lint rules turn silent browser recovery into feedback

  • Browsers recover from many malformed constructs, so “it rendered” is weak evidence.

  • The recommended preset supplies a maintained baseline; project overrides should be documented.

  • Duplicate IDs can break fragments, form labels, ARIA references, tests, and JavaScript selection.

  • Static linting cannot prove dynamic templates render unique IDs across repeated component instances.

  • Framework templates may require a transformer/plugin or linting the rendered HTML rather than raw template syntax.

Web project rootbash
npx html-validate "src/**/*.html"
0 errors found

Treat each diagnostic as a source location

  • The command reads matched HTML files and exits nonzero on configured errors.

  • Fix the markup rather than disabling a rule globally after one inconvenient result.

  • If a rule is inapplicable, scope the exception narrowly and record why.

  • Pair linting with browser accessibility testing, keyboard interaction, and assistive-technology review.

  • Validate fully rendered pages for server/client systems that assemble markup dynamically.

4. Lint CSS before minifying it

.stylelintrc.jsonjson
{
  "extends": ["stylelint-config-standard"],
  "rules": {
    "declaration-block-no-duplicate-properties": true,
    "selector-id-pattern": null
  }
}

Start from a standard, then encode project decisions

  • Stylelint catches invalid and contradictory declarations that formatting may leave untouched.

  • A shared config reduces bespoke rule maintenance.

  • Setting a rule to null disables it deliberately; remove unnecessary overrides rather than accumulating them.

  • CSS preprocessors, CSS Modules, and framework syntax may need appropriate syntax packages/configuration.

  • Lint success does not prove visual layout across viewport, browser, theme, and content variations.

Web project rootbash
npx stylelint "src/**/*.css"
npx stylelint "src/**/*.css" --fix
No Stylelint errors

Risk level: caution. Review the command before running it.

Auto-fix is still a code change

  • The first command reports without intentional rewriting.

  • --fix changes files for fixable rules; use it only after the reporting pass and review the diff.

  • Some fixes can expose cascade assumptions even when syntactically safe.

  • Run visual/component tests after broad CSS changes.

  • Keep linting on authored source; minified output is a build artifact.

5. Parse JSON locally

Directory containing the JSON filebash
jq empty config.json
jq --sort-keys . config.json > /tmp/config.formatted.json
python -m json.tool config.json > /dev/null
No output and exit status 0 means the parser accepted the JSON.

Syntax validation is not schema validation

  • jq empty parses the complete document without printing its data.

  • jq --sort-keys . writes a formatted copy to an explicit temporary file rather than overwriting source.

  • Python’s json.tool offers a standard-library parser when jq is unavailable.

  • Strict JSON does not allow comments, trailing commas, single-quoted strings, NaN, or Infinity.

  • A syntactically valid payload can still omit required fields, use the wrong types, or violate business rules.

6. Validate JSON against a schema

config.schema.jsonjson
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["environment", "features"],
  "properties": {
    "environment": { "enum": ["development", "staging", "production"] },
    "features": {
      "type": "array",
      "items": { "type": "string", "minLength": 1 },
      "uniqueItems": true
    }
  },
  "additionalProperties": false
}

The schema describes structure, not every domain invariant

  • Draft 2020-12 is declared explicitly so validator behavior is not guessed.

  • required controls property presence; listing a property under properties alone does not require it.

  • enum limits the environment to known string values.

  • uniqueItems prevents duplicate feature values under JSON equality semantics.

  • additionalProperties:false rejects misspelled or unexpected keys but can make schema evolution stricter; choose intentionally.

Web project rootbash
npx ajv-cli validate \
  --spec=draft2020 \
  --schema config.schema.json \
  --data config.json
config.json valid

Pin the validator before relying on it

  • Add a reviewed Ajv CLI version to project development dependencies before using the command in CI.

  • --spec=draft2020 aligns the validator with the schema declaration.

  • A schema-valid configuration may still reference nonexistent resources or violate cross-system policy.

  • Test valid and intentionally invalid fixtures to prove the schema rejects what matters.

  • Avoid placing secrets in test fixtures, command history, or CI logs.

7. Minify CSS in a production build

postcss.config.cjsjavascript
module.exports = ({ env }) => ({
  plugins: [
    require("autoprefixer"),
    ...(env === "production" ? [require("cssnano")({ preset: "default" })] : []),
  ],
});

Minification belongs after authored-source checks

  • The example enables cssnano only for the production environment.

  • Autoprefixer derives prefixes from the project’s browsers target configuration.

  • Add and pin these packages before using this configuration.

  • Preserve source maps according to debugging and source-disclosure policy.

  • Review transformations when CSS relies on custom properties, advanced functions, hacks, or third-party code.

Web project rootbash
NODE_ENV=production npx postcss src/styles.css \
  --output dist/styles.min.css
wc -c src/styles.css dist/styles.min.css
8421 src/styles.css
5310 dist/styles.min.css

Risk level: caution. Review the command before running it.

A smaller file is only the first assertion

  • The command writes a build artifact under dist; confirm that directory is intended and generated.

  • Byte counts show raw size, not transfer size after Brotli/gzip.

  • Run visual regression, supported-browser, and critical-interaction tests against the minified bundle.

  • Verify URLs and source-map references resolve from the deployed asset location.

  • Use content hashes and long-lived caching through the established asset pipeline rather than manual filename editing.

Formatters cannot repair ambiguous HTML

broken.htmlhtml
<ul>
  <li>First item
  <li>Second item
</ul>
 
<div><p>Browser recovery can make this look acceptable.</div>

Parsing rules and author intent are different

  • Some end tags are optional in HTML, so a formatter may produce valid output that still surprises a reader.

  • Browsers use specified error-recovery algorithms for malformed nesting.

  • A formatter cannot know whether a missing wrapper or closing tag reflects intended structure.

  • Inspect the DOM in browser developer tools and validate/lint the rendered markup.

  • Add semantic, accessibility, and behavior tests rather than using indentation as proof.

Editor and pre-commit workflow

  • Enable format-on-save only with the repository’s selected formatter and configuration.

  • Run linting on changed files for fast feedback, then the full check in CI.

  • Do not let editor extensions silently use globally installed tool versions.

  • Keep generated/minified files excluded unless the repository intentionally commits them.

  • Make CI commands identical to local package scripts so failures reproduce.

  • Use pre-commit hooks as convenience; protected CI remains the enforcement boundary.

Online tool decision checklist

  • Does the input contain credentials, personal data, customer content, internal URLs, or proprietary source? Keep it local.

  • Is the service vendor approved, and are transport, retention, training, subprocessors, and deletion terms understood?

  • Can the same result be reproduced later with a named tool/version/configuration?

  • Will the tool upload data as you type or only after submission?

  • Does the output need validation/tests beyond visual formatting?

  • Can a small synthetic example reproduce the issue without exposing the real file? Use that instead.

Troubleshooting map

  • Prettier says “no parser”: verify the file extension, explicit parser, or required reviewed plugin.

  • HTML linter rejects template syntax: configure the appropriate transformer or lint rendered HTML.

  • Stylelint cannot parse a preprocessor: select the matching custom syntax and compatible rules.

  • JSON formatter accepts data but the app rejects it: validate schema, encoding, number ranges, and application semantics.

  • jq reports an error near a quote: inspect escaping and remember JSON requires double-quoted keys/strings.

  • Ajv rejects a valid-looking file: align schema draft, formats, references, and strictness options.

  • Minified CSS changes the page: compare the transformation, browser targets, cascade, asset URLs, and source maps; do not ship solely because the build exited zero.

  • CI and editor disagree: compare resolved package versions, configuration discovery, ignore files, line endings, and working directory.

A reliable completion gate

  • Dependencies and lockfile are reviewed and committed.

  • Formatting check produces no diff.

  • HTML and CSS linters pass on authored or correctly transformed source.

  • JSON files parse strictly and schema-bound files satisfy the intended draft.

  • Secret scanning and data-handling policy permit every processed fixture.

  • Minification is confined to production artifacts and preserves source files.

  • Rendered HTML, accessibility, visual behavior, and supported browsers are tested.

  • CI runs the same pinned commands from a clean checkout.

  • Production asset URLs, content types, compression, caching, CSP, and source maps are verified.

Primary documentation

  • Prettier CLI documents check/write behavior and file matching.

  • HTML-validate documents configuration, rules, integrations, and framework handling.

  • Stylelint user guide covers configuration, CLI, custom syntaxes, and fixes.

  • jq manual documents strict JSON parsing and transformations.

  • Python json.tool documents standard-library validation/pretty-printing.

  • JSON Schema 2020-12 defines the schema dialect used in the example.

  • Ajv guide explains compilation and JSON Schema validation.

  • cssnano documents PostCSS-based CSS optimization and presets.