Tutti gli sviluppatori che utilizzano Mac OS X, compreso me, hanno le loro buone ragioni.
È innegabile però che ci siano alcune differenze di cui va tenuto conto. Una di queste è il fatto che il filesystem è case insensitive.
Facciamo un esempio. Creiamo un file contenente la parola ciao e poi stampiamone il contenuto usando un nome di file con case diverso.
I seguenti comandi non daranno errore per file non trovato ma verrà stampato ciao
echo ciao > FooBar cat fOObAR
Questa caratteristica può rivelarsi spiacevole specialmente quando si interagisce con sistemi case sensitive, siano essi computer di altri sviluppatori del team o sistemi di build o deploy.
Case insensitive: un esempio concreto
Ho creato una applicazione Node.Js di esempio che sfrutta Webpack per gestire gli import. Nel paragrafo Riferimenti trovate il link al progetto con il codice eseguibile mentre di seguito riportiamo solo le parti principali.
I due file sorgenti dell’esempio sono i seguenti:
index.js
import {foobar} from './FooBar' console.log("foobar is ", foobar)
Foobar.js
export const foobar = 42;
Da notare che l’import dentro index si riferisce a un file FooBar
, mentre il file si chiama Foobar
.
La differenza è sottile ed è quello che rende il problema spinoso e difficile da individuare.
Build su Mac Os X
La build può essere eseguita con il comando npx webpack
. L’output del comando ne dimostra la corretta esecuzione
Hash: 449c8fcaf39b09803703 Version: webpack 4.42.0 Time: 91ms Built at: 03/05/2020 7:32:46 PM Asset Size Chunks Chunk Names main.js 980 bytes 0 [emitted] main Entrypoint main = main.js [0] ./src/index.js + 1 modules 93 bytes {0} [built] | ./src/index.js 67 bytes [built] | ./src/FooBar.js 26 bytes [built]
Build tramite docker
Ho approntato anche un dockerfile che esegue una build in un container linux, case sensitive, usando lo stesso comando npx webpack
.
Lanciando il comando docker image build -t itFails .
vediamo che fallisce per non aver trovato il file giusto.
ERROR in ./src/index.js Module not found: Error: Can't resolve './FooBar' in '/usr/src/app/src' @ ./src/index.js 1:0-31 3:26-32
Case insensitive: cosa possiamo fare
A meno che tutti gli ambienti coinvolti siano case insensitive, è necessario che il casing dei file e dei rispettivi import corrisponda.
La soluzione più semplice è quella di affidarsi alla continuous integration che ci informerà quanto prima della build fallita e avremo così modo di identificare e correggere il problema.
Se però siamo alla ricerca di una soluzione più proattiva, che renda visibile il problema già sull’ambiente di sviluppo in locale, esistono varie possibilità. Di seguito ne cito due, come rappresentanti di due categorie.
Il primo approccio è quello di far fallire la build anche in locale. Questo può essere ottenuto ad esempio con il plugin di webpack case-sensitive-paths: se il casing dei file importati non corrisponde, il plugin si occuperà di far fallire la build con un errore.
Il secondo approccio è quello di sfruttare eslint configurandolo in modo che evidenzi il problema direttamente nell’ide. Una estensione che fornisce questa funzionalità è eslint-plugin-import che fornisce la regola no-unresolved
con l’opzione caseSensitive
Conclusioni
Nello scenario presentato, lo sviluppatore si troverà in una situazione dove il sistema in locale funziona ma fallisce la build di produzione. Il messaggio di errore sembrerà criptico perché ad una prima lettura non si noterà il diverso casing tra il file vero e il nome riportato nell’errore.
Spero che con la lettura di questo articolo l’informazione torni in mente al momento giusto permettendo di evitare inutili perdite di tempo dietro a un errore banale.