Sviluppo web
GitHub Actions per un sito: la pipeline minima
Un workflow che costruisce, conserva l'artefatto e pubblica solo da main: versione dei pacchetti, cache, permessi e i punti in cui si rompe.
In sintesi
- `permissions: contents: read` toglie al token tutto ciò che il job non usa.
- La cache di npm si invalida con l'hash del lockfile, non con la data.
- `needs` più `if` sul ref impediscono a un pull request di pubblicare.
GitHub Actions per un sito è un file YAML in .github/workflows: un job che costruisce, uno che pubblica e un permesso in sola lettura. Le versioni misurate sono checkout 7.0.1 e setup-node 7.1.0.
Il file minimo
name: ci
on:
push:
branches: [main]
pull_request:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v7
with:
name: dist
path: dist
retention-days: 7
concurrency annulla il run precedente sullo stesso ref; permissions: contents: read riduce il token al solo checkout. Senza quel blocco il token porta con sé i permessi di default del repository.
La cache che si invalida da sola
- uses: actions/cache@v6
with:
path: ~/.npm
key: npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: npm-
La chiave contiene l'hash del lockfile: cambi una dipendenza, cambia la chiave, la cache si ricrea. Una chiave fissa lascerebbe pacchetti vecchi per mesi, e il sintomo sarebbe una build che passa solo in CI.
Pubblicare solo da main
deploy:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/download-artifact@v7
with:
name: dist
path: dist
- name: Publish
env:
SSH_KEY: ${{ secrets.DEPLOY_KEY }}
run: |
install -m 600 /dev/null key
printf "%s" "$SSH_KEY" > key
rsync -az --delete -e 'ssh -i key' dist/ [email protected]:/var/www/site/
needs impone che il build sia verde, if limita il job al ramo principale. Su un pull request da fork i secret non arrivano, quindi il job salta e la CI resta verde senza esporre la chiave.
Artefatti e diagnosi
gh run list --limit 5
gh run watch
gh run download -n dist
upload-artifact conserva dist per sette giorni; gh run download -n dist riporta quei file in locale senza rifare la build. gh run watch segue il run fino alla fine, con i log del passo che fallisce.
Matrice e tempi
strategy:
fail-fast: false
matrix:
node: [22, 24]
La matrice duplica il job per ogni versione di Node. fail-fast: false lascia finire le altre combinazioni, così vedi se il problema è solo sulla versione vecchia.
Limite dichiarato
I minuti si pagano sui repository privati, e ogni matrice li moltiplica. cancel-in-progress uccide anche un deploy a metà se arriva un push durante il rilascio: separa build e deploy in due workflow se il rilascio dura più di qualche minuto.
Dove continuare
Tre componenti che finiscono nel build: input, spinner e la griglia delle icone; il resto è in components/lib e nelle 1.556 anteprime. Gli errori di build sono in errori di build comuni, l'ordine delle cartelle in App Router nel 2026. Il confronto fra Vite e Next per un sito marketing è in Next.js vs Vite.
Domande frequenti
Quanto costa GitHub Actions per un sito piccolo?
Sui repository pubblici i minuti sono gratuiti; su quelli privati il piano Free include 2.000 minuti al mese. Una build di due minuti per push sta largamente dentro quel tetto.
Dove metto la chiave SSH per il deploy?
In un secret del repository o dell'environment, mai nel file YAML. Il secret si passa al passo come variabile d'ambiente, e la chiave si scrive su disco con permessi 600.
Perché il job di deploy viene saltato sui pull request?
Perché la condizione if limita il job al ramo main, e perché i secret non sono disponibili per i fork. È il comportamento voluto: il pull request verifica il build, non pubblica.
Meglio cache di setup-node o actions/cache?
setup-node con cache: npm copre il caso normale e richiede due righe. actions/cache serve quando devi conservare una cartella che setup-node non conosce, per esempio un browser o un binario scaricato a mano.
Posso lanciare il workflow a mano?
Sì, aggiungendo workflow_dispatch fra i trigger. Da terminale il comando è gh workflow run ci.yml, e gh run watch segue l'esecuzione.