Lezione 29 di 35

Git 29

🔀 Git & GitHub · Modulo 5 · Lezione 29

Linting e quality check ✨

Controllare la qualità automaticamente · HTMLHint · Stylelint · ESLint · Linter nel workflow CI

⏱️ Durata stimata: 60–75 min 📊 Livello: Avanzato (Modulo 5) 🔧 Strumenti: Terminale · Node.js (npm) · GitHub 📋 Prerequisiti: Lezioni 25–28 (workflow CI/CD)

✨ I test verificano che il codice funziona. I linter verificano che il codice è scritto bene. Un linter è uno strumento che analizza il codice sorgente e segnala errori di stile, problemi potenziali, tag HTML non chiusi, proprietà CSS sconosciute, variabili inutilizzate. Non è un capriccio estetico — il codice pulito ha meno bug, è più facile da leggere e da mantenere. Integrato nel CI, il linter garantisce che tutto il team segua le stesse convenzioni.

🎯 Obiettivi della lezione

  • Capire cos’è un linter e perché è utile
  • Usare HTMLHint per verificare la qualità dell’HTML
  • Usare Stylelint per verificare la qualità del CSS
  • Usare ESLint per verificare la qualità del JavaScript
  • Integrare i linter nel workflow CI
  • Configurare le regole con file di configurazione

📖 1. Teoria

1.1 — Cos’è un linter

Un linter è un programma che analizza il codice sorgente senza eseguirlo e segnala problemi di stile, errori potenziali e violazioni delle convenzioni. Il nome viene da “lint” — i pelucchi che si tolgono dai vestiti.

Cosa trova un linter
Tag HTML non chiusi
Proprietà CSS sconosciute o duplicate
Variabili JS dichiarate ma mai usate
Uso di == invece di ===
Indentazione inconsistente
Errori di accessibilità (alt mancante)
Cosa NON trova un linter
Bug logici (la funzione fa la cosa sbagliata)
Problemi di design (il layout è brutto)
Errori di business logic
Performance lenta
Vulnerabilità di sicurezza complesse
→ Per questi servono i test (Lezione 27)
Un linter per ogni linguaggio
Linguaggio Linter Installa Esegui
HTML HTMLHint npm install htmlhint –save-dev npx htmlhint “**/*.html”
CSS Stylelint npm install stylelint stylelint-config-standard –save-dev npx stylelint “**/*.css”
JavaScript ESLint npm init @eslint/config@latest npx eslint .
Python Ruff (o flake8) pip install ruff ruff check .

1.2 — HTMLHint: linting dell’HTML

# Inizializza il progetto npm (se non l’hai già fatto)
$ npm init -y

# Installa HTMLHint
$ npm install htmlhint –save-dev

# Esegui su tutti i file HTML
$ npx htmlhint “**/*.html”
index.html
L1 |<!DOCTYPE html>
Scanned 1 files, no errors found (3ms).

HTMLHint ha regole predefinite ragionevoli. Puoi personalizzarle con un file .htmlhintrc:

// File: .htmlhintrc
{
“tagname-lowercase”: true, // tag in minuscolo
“attr-lowercase”: true, // attributi in minuscolo
“attr-value-double-quotes”: true, // virgolette doppie
“doctype-first”: true, // DOCTYPE obbligatorio
“tag-pair”: true, // tag aperti devono essere chiusi
“alt-require”: true, // img deve avere alt (accessibilità)
“id-unique”: true, // id devono essere unici
“src-not-empty”: true // src non vuoto
}

1.3 — Stylelint: linting del CSS

# Installa Stylelint con la configurazione standard
$ npm install stylelint stylelint-config-standard –save-dev

# Esegui
$ npx stylelint “**/*.css”
style.css
12:3 ⚠ Unexpected duplicate “color” declaration-no-duplicates
25:1 ⚠ Expected empty line before rule rule-empty-line-before
// File: .stylelintrc.json
{
“extends”: “stylelint-config-standard”,
“rules”: {
“declaration-no-duplicates”: true, // no proprietà duplicate
“color-no-invalid-hex”: true, // colori hex validi
“no-descending-specificity”: null, // disabilita questa regola
“rule-empty-line-before”: null // troppo pedante per la scuola
}
}

📌 Mettere null disabilita una regola. Alcune regole sono troppo rigide per un progetto scolastico (es. “riga vuota obbligatoria prima di ogni regola CSS”). Inizia con la configurazione standard, poi disabilita le regole che il team trova troppo invasive.

1.4 — ESLint: linting del JavaScript

# Setup guidato di ESLint (risponde a domande sulla configurazione)
$ npm init @eslint/config@latest

# Oppure installazione manuale
$ npm install eslint –save-dev

# Esegui
$ npx eslint .
script.js
3:7 error ‘risultato’ is assigned but never used no-unused-vars
8:5 warning Unexpected var, use let or const no-var
15:1 error ‘x’ is not defined no-undef
// File: eslint.config.mjs (ESLint flat config — il formato attuale)
import js from “@eslint/js”;

export default [
js.configs.recommended, // regole raccomandate
{
rules: {
“no-unused-vars”: “warn”, // variabili inutilizzate = warning
“no-var”: “error”, // vietato var, usa let/const
“eqeqeq”: “error”, // === obbligatorio (no ==)
“no-console”: “off” // console.log permesso (per la scuola)
}
}
];
I 3 livelli di severità
Livello Valore Effetto Il CI fallisce?
off 0 Regola disabilitata No
warn 1 Avviso giallo — segnala ma non blocca No
error 2 Errore rosso — blocca Sì — exit code 1

1.5 — Integrare i linter nel workflow CI

# File: .github/workflows/lint.yml

name: Lint

on: [push, pull_request]

jobs:
lint-html:
runs-on: ubuntu-latest
steps:
– uses: actions/checkout@v4
– uses: actions/setup-node@v4
with:
node-version: 20
– run: npm ci
– name: HTMLHint
run: npx htmlhint “**/*.html”

lint-css:
runs-on: ubuntu-latest
steps:
– uses: actions/checkout@v4
– uses: actions/setup-node@v4
with:
node-version: 20
– run: npm ci
– name: Stylelint
run: npx stylelint “**/*.css”

lint-js:
runs-on: ubuntu-latest
steps:
– uses: actions/checkout@v4
– uses: actions/setup-node@v4
with:
node-version: 20
– run: npm ci
– name: ESLint
run: npx eslint .
I 3 job girano in parallelo
lint-html
HTMLHint
lint-css
Stylelint
lint-js
ESLint
Tutti in parallelo — se uno fallisce, non blocca gli altri. Vedi tutti gli errori in una volta.

1.6 — Script npm: semplificare i comandi

Invece di ricordare i comandi lunghi, configura gli script in package.json:

// In package.json, aggiungi nella sezione “scripts”:
{
“scripts”: {
“lint:html”: “htmlhint ‘**/*.html'”,
“lint:css”: “stylelint ‘**/*.css'”,
“lint:js”: “eslint .”,
“lint”: “npm run lint:html && npm run lint:css && npm run lint:js”,
“test”: “node utils.test.js”
}
}
# Ora in locale:
$ npm run lint ← esegue tutti e 3 i linter
$ npm run lint:html ← solo HTML
$ npm test ← esegue i test

# E nel workflow CI puoi semplicemente:
– run: npm run lint
– run: npm test

💻 2. Esempi guidati

Esempio A — Setup completo di linting per un progetto HTML/CSS/JS

# 1. Inizializza npm
$ npm init -y

# 2. Installa i linter
$ npm install –save-dev htmlhint stylelint stylelint-config-standard

# 3. Crea le configurazioni
$ echo ‘{“doctype-first”:true,”tag-pair”:true,”alt-require”:true}’ > .htmlhintrc
$ echo ‘{“extends”:”stylelint-config-standard”,”rules”:{“rule-empty-line-before”:null}}’ > .stylelintrc.json

# 4. Aggiungi gli script a package.json
# (modifica manualmente la sezione “scripts”)

# 5. Aggiungi node_modules al .gitignore
$ echo “node_modules/” >> .gitignore

# 6. Testa in locale
$ npx htmlhint “**/*.html”
$ npx stylelint “**/*.css”

# 7. Committa tutto
$ git add . && git commit -m “Aggiunto linting: HTMLHint + Stylelint”
$ git push

Esempio B — Workflow semplificato con npm scripts

# Se hai configurato gli script in package.json, il workflow è semplicissimo:

name: CI
on: [push, pull_request]

jobs:
quality:
runs-on: ubuntu-latest
steps:
– uses: actions/checkout@v4
– uses: actions/setup-node@v4
with:
node-version: 20
– run: npm ci
– name: Lint
run: npm run lint
– name: Test
run: npm test

🏋️ 3. Esercizi

🟢 Esercizio 1 — HTMLHint in locale (Facile)

a) Nel tuo progetto: npm init -y → npm install htmlhint --save-dev.
b) Esegui: npx htmlhint "**/*.html". Ci sono errori?
c) Introduci un errore intenzionale (es. togli un tag di chiusura). Riesegui. HTMLHint lo trova?
d) Crea un file .htmlhintrc con la regola "alt-require": true.
e) Aggiungi un <img> senza alt. HTMLHint lo segnala?
f) Correggi tutti gli errori. Il linter passa con 0 errori.

🔵 Esercizio 2 — Aggiungi Stylelint (Medio)

a) Installa: npm install stylelint stylelint-config-standard --save-dev.
b) Crea .stylelintrc.json con la configurazione della sezione 1.3.
c) Esegui: npx stylelint "**/*.css". Quanti avvisi?
d) Correggi gli errori critici. Disabilita le regole troppo pedanti con null.
e) Aggiungi gli script lint:html, lint:css e lint a package.json.
f) Verifica: npm run lint esegue entrambi i linter senza errori.

🟠 Esercizio 3 — Lint nel CI (Medio)

a) Crea il workflow .github/workflows/lint.yml con i job della sezione 1.5.
b) Committa e pusha. I job di lint sono verdi?
c) Introduci un errore HTML (tag non chiuso). Pusha. Il job lint-html diventa rosso?
d) Se hai le branch protection: configura i job di lint come status check obbligatori.
e) Apri una PR con un errore CSS. Il merge è bloccato?
f) Correggi, pusha, verifica che tutto torni verde.

🟣 Esercizio 4 — Pipeline completa: lint + test + deploy (Difficile)

Unisci tutto in un unico workflow pipeline.yml:

a) Job 1 — lint: npm run lint (HTML + CSS + JS se presente).
b) Job 2 — test: esegue i test del codice (parallelo con lint).
c) Job 3 — deploy: needs: [lint, test]. Pubblica su GitHub Pages. Solo su push a main.
d) Configura branch protection: lint e test come status check obbligatori.
e) Testa il flusso completo: PR con errore lint → bloccata. PR corretta → merge → deploy.
f) Verifica: il sito online ha il codice corretto e lintato.

❓ 4. Quiz di verifica

1. Cos’è un linter e come si differenzia dai test?

Mostra risposta

Un linter analizza il codice sorgente senza eseguirlo e segnala problemi di stile, errori sintattici e violazioni delle convenzioni. I test eseguono il codice e verificano che produca i risultati corretti. Il linter trova tag non chiusi, variabili inutilizzate, proprietà CSS duplicate; i test trovano bug logici, funzioni che restituiscono valori sbagliati, casi limite non gestiti. Sono complementari: il linter garantisce che il codice è scritto bene, i test garantiscono che funziona bene. Un progetto professionale usa entrambi.


2. Qual è la differenza tra i livelli “warn” e “error” in un linter?

Mostra risposta

“warn” (livello 1) mostra un avviso giallo ma non fa fallire il CI — il processo esce con codice 0. “error” (livello 2) mostra un errore rosso e fa fallire il CI — il processo esce con codice 1 e il workflow diventa rosso. Usa “error” per regole non negoziabili (es. no-var, eqeqeq) e “warn” per regole educative che il team sta ancora imparando. "off" (livello 0) disabilita completamente la regola.


3. Perché è importante aggiungere node_modules/ al .gitignore?

Mostra risposta

Perché node_modules/ contiene migliaia di file (tutte le dipendenze scaricate da npm) che non devono essere nel repository. Sono pesanti (decine o centinaia di MB), si rigenerano con npm install (o npm ci), e cambiano tra sistemi operativi. Il file package-lock.json (che va committato) garantisce che tutti installino le stesse versioni. Nel CI, il workflow fa npm ci che ricrea node_modules dal lockfile — non serve che siano nel repo.


4. Cos’è npm ci e perché si usa nel CI invece di npm install?

Mostra risposta

npm ci (Clean Install) installa le dipendenze esattamente come specificate nel package-lock.json, senza modificarlo. A differenza di npm install (che può aggiornare il lockfile), npm ci è deterministico: produce sempre lo stesso risultato. Nel CI è fondamentale perché garantisce che il runner abbia le stesse identiche dipendenze che il team usa in locale. npm ci cancella anche node_modules/ prima di installare, partendo sempre da zero.


5. Come disabiliti una regola di Stylelint che trovi troppo rigida?

Mostra risposta

Nel file di configurazione .stylelintrc.json, dentro la sezione "rules", imposta la regola a null. Esempio: "rule-empty-line-before": null disabilita la regola che richiede una riga vuota prima di ogni regola CSS. Puoi anche cambiare il livello di severità o le opzioni delle regole. Il file .stylelintrc.json con "extends": "stylelint-config-standard" parte con le regole standard, e tu le personalizzi nel blocco "rules" sovrascrivendo solo quelle che vuoi cambiare.


6. Qual è il vantaggio di definire gli script npm come "lint": "npm run lint:html && npm run lint:css"?

Mostra risposta

Tre vantaggi. Semplicità: in locale basta digitare npm run lint invece di ricordare i comandi completi di ogni linter. Consistenza: tutti nel team eseguono gli stessi comandi con le stesse opzioni — non c’è rischio di variazioni. Portabilità: nel workflow CI scrivi run: npm run lint e funziona — se domani cambi linter, aggiorni solo il package.json e il workflow resta identico. L’operatore && garantisce che se il primo linter fallisce, il secondo non viene eseguito — ti mostra l’errore subito.


📚 Riepilogo della lezione

Cosa hai imparato oggi:
  • Linter = analizza il codice senza eseguirlo, trova errori di stile e problemi potenziali
  • HTMLHint: tag non chiusi, DOCTYPE, alt mancante → .htmlhintrc
  • Stylelint: proprietà duplicate, colori invalidi, stile inconsistente → .stylelintrc.json
  • ESLint: no-var, ===, variabili inutilizzate → eslint.config.mjs
  • 3 livelli: off (disabilitato) · warn (avviso) · error (blocca CI)
  • npm scripts: npm run lint per eseguire tutti i linter con un comando
  • npm ci nel CI per installazioni deterministiche dal lockfile
  • Workflow: 3 job lint paralleli, o 1 job con npm run lint

Prossima lezione →

Lezione 30 — Secrets e variabili d’ambiente
Gestire credenziali e dati sensibili nei workflow.
GitHub Secrets. Variabili di repository. Sicurezza nelle pipeline.

Corso Git & GitHub · Per studenti e insegnanti · Lezione 29 di 45