Punto 12. Le cinque librerie erano già state portate in casa (28ee44b): nessun
template carica più niente dalla rete, il worker di PDF.js è locale in tutti e
quattro i file che lo impostano, i font sono woff2 nel pacchetto. Verificato riga
per riga, e le impronte SHA-256 in VERSIONS.md corrispondono ancora.
Mancava però la seconda metà dell'intervento, e mancava dove conta. La
Content-Security-Policy a sola origine locale esisteva sul backend, cioè sulle
risposte API; le pagine HTML le serve il client Flask, che non mandava alcuna
policy. La regola stava scritta dove non poteva essere infranta e assente dove
poteva. Ora il client la manda su ogni risposta.
Serve meno a difendere e più a non far tornare indietro il punto: un tag verso un
CDN aggiunto fra sei mesi viene rifiutato dal browser alla scrivania, dove c'è la
rete e l'errore si legge in console, invece che in reparto dove la rete non c'è.
Tailwind era ancora agganciato a `tailwindcss@3` nel Dockerfile: stesso difetto
che il documento cita per le librerie del browser, un gradino più in basso. Fissato
a 3.4.19, che è la versione con cui l'immagine in esercizio è stata costruita.
I test non renderizzano niente: leggono i sorgenti, perché il difetto che devono
impedire si scrive in un template e non si vede finché non si stacca la rete.
Controllano anche le impronte — una libreria sostituita sul posto tiene lo stesso
nome e la stessa riga in tabella, e l'hash è l'unica parte che se ne accorge.
Annotato in VERSIONS.md che `html5-qrcode` è l'unica libreria dichiarata e mai
caricata: lo scanner da fotocamera non è incluso da nessuna pagina, il lettore che
l'operatore usa è un campo di testo. Va portata in casa prima di accenderlo.
README aggiornato a V3.0.0: novità della versione punto per punto, ruolo
Supervisor, librerie locali al posto dei CDN, stato dei test.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
6.0 KiB
Librerie di terze parti — copie locali
Queste copie servono al punto 12 del documento delle modifiche: l'installazione a Tràfilo è on-premise, su rete di produzione isolata. Finché queste librerie venivano scaricate da CDN a ogni apertura di pagina, senza internet l'interfaccia non partiva affatto (Alpine.js governa tutta la UI).
Secondo effetto, non meno importante: le versioni sono congelate. Prima Alpine.js
era agganciato a alpinejs@3.x.x, cioè l'applicazione cambiava da sola a ogni rilascio
degli autori, senza validazione. Per un sistema che produce evidenze per audit
ISO 9001 / IATF 16949 questo è di per sé un difetto.
Scaricate il 28 luglio 2026.
JavaScript
| File | Versione | Origine |
|---|---|---|
alpinejs-3.15.12.min.js |
3.15.12 | https://cdn.jsdelivr.net/npm/alpinejs@3.15.12/dist/cdn.min.js |
plotly-2.32.0.min.js |
2.32.0 | https://cdn.plot.ly/plotly-2.32.0.min.js |
pdf-3.11.174.min.js |
3.11.174 | https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js |
pdf.worker-3.11.174.min.js |
3.11.174 | https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js |
fabric-5.3.1.min.js |
5.3.1 | https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.1/fabric.min.js |
La versione di Alpine è quella a cui 3.x.x risolveva il giorno del congelamento:
il pin non cambia il comportamento rispetto a quanto già in esercizio.
pdf.worker è un file a sé che PDF.js carica a runtime via
pdfjsLib.GlobalWorkerOptions.workerSrc. Va ripuntato in tutti i template che usano
PDF.js, non basta lo script principale: altrimenti la libreria si carica in locale e il
worker continua a cercare internet — sembra funzionare finché non si apre un disegno.
Font
fonts.css sostituisce il <link> a fonts.googleapis.com in base.html.
| File | Famiglia | Subset |
|---|---|---|
fonts/inter-latin.woff2 |
Inter | latin |
fonts/inter-latin-ext.woff2 |
Inter | latin-ext |
fonts/jetbrains-mono-latin.woff2 |
JetBrains Mono | latin |
fonts/jetbrains-mono-latin-ext.woff2 |
JetBrains Mono | latin-ext |
Entrambe le famiglie sono font variabili (asse wght: Inter 100–900, JetBrains Mono
400–800): un solo file per subset copre tutti i pesi usati dall'interfaccia. Google
serviva lo stesso woff2 sotto otto URL diversi, uno per peso dichiarato.
Tenuti i soli subset latin e latin-ext, che coprono per intero italiano e inglese. Per gli altri alfabeti il browser ricade sul font di sistema — scelta consapevole: cirillico, greco e vietnamita valevano 600 KB di peso morto.
Impronte SHA-256
57b37d7cae9a27d965fdae4adcc844245dfdc407e655aee85dcfff3a08036a3f alpinejs-3.15.12.min.js
bb0442d69a4d4673320f689bc6e16c05a0e3f16ccfbf551f394d90a7e7cfc772 fabric-5.3.1.min.js
5b5799e6f8c680663207ac5b42ee14eed2a406fa7af48f50c154f0c0b1566946 pdf-3.11.174.min.js
feabdf309770ed24bba31a5467836cdc8cf639c705af27d52b585b041bb8527b pdf.worker-3.11.174.min.js
0a17719a72751704861215da0e5c5cdb3f9a8d50eff5cb84cb6f8b80786682b0 plotly-2.32.0.min.js
34b9c504cab7a73e37b746343a449132e56cf7b5481af2cb81dc74dcff25c956 fonts/inter-latin-ext.woff2
3100e775e8616cd2611beecfa23a4263d7037586789b43f035236a2e6fbd4c62 fonts/inter-latin.woff2
db5ff4db83e580426280e9337a58dc57d3a83784a1b03ad80914651594441d52 fonts/jetbrains-mono-latin-ext.woff2
83c005d49d8a6a50474c73a5a36ac0468076e9c4a29da7bdb14995d80560a5be fonts/jetbrains-mono-latin.woff2
Verifica: sha256sum -c da questa cartella, oppure
sha256sum *.js fonts/*.woff2. Il confronto è anche un test
(tests/test_offline.py::test_the_shipped_libraries_are_the_ones_that_were_checked):
una libreria sostituita sul posto tiene lo stesso nome e la stessa riga in tabella,
e l'impronta è l'unica parte che se ne accorge.
La regola che tiene il punto chiuso
Le copie locali risolvono il problema una volta; quello che lo tiene risolto è la
Content-Security-Policy servita dal client Flask (app.py, CSP), che ammette
solo l'origine locale. Prima esisteva solo sul backend — cioè sulle risposte API,
non sulle pagine che il browser disegna: la regola stava scritta dove non poteva
essere infranta e mancava dove poteva.
Con la policy in vigore, un <script src="https://cdn…"> aggiunto fra sei mesi viene
rifiutato dal browser alla scrivania, dove c'è la rete e l'errore si legge in
console, invece che in reparto dove la rete non c'è.
Tailwind
Tailwind non sta in questa cartella: è compilato in fase di build dell'immagine
(Dockerfile.frontend) e il CSS finito viene servito da static/css/tailwind.css.
Vale però lo stesso vincolo — la versione è fissata a tailwindcss@3.4.19. Con
tailwindcss@3 ogni ricostruzione poteva prendere una minor diversa e produrre un
foglio di stile diverso senza che nessuno l'avesse validato.
Nota per l'installazione on-premise: la costruzione dell'immagine richiede rete (npm, apt, uv). È l'esecuzione a non richiederla. In reparto va portata l'immagine già costruita, non il repository da compilare sul posto.
Una sesta libreria, oggi non caricata
static/js/barcode.js e templates/components/barcode_scanner.html implementano lo
scanner QR con la fotocamera e si appoggiano a html5-qrcode, che non è mai
caricata da nessuna pagina: il componente non è incluso da nessuna parte e la
libreria non è in questa cartella. A runtime non rompe niente — è codice morto.
La lettura del barcode che l'operatore usa davvero è un campo di testo in
measure/select_recipe.html: il lettore hardware la digita, e non serve nessuna
libreria.
Se un giorno si accende lo scanner da fotocamera, html5-qrcode va portata qui
prima, altrimenti in reparto quel pulsante mostra «scanner_lib_not_loaded» e
basta.
Aggiornare una libreria
- Scaricare la nuova versione con il nome comprensivo di versione.
- Ripuntare i
<script>/<link>nei template (grep -rn vendor/ ../../templates/). - Aggiornare questa tabella e le impronte.
- Rimuovere il file vecchio.
Il nome del file porta la versione apposta: un aggiornamento non passa inosservato in revisione, e la modifica resta tracciata in git.