Hai sviluppato il tuo progetto con ReactJS ed ora vuoi avere un codice ottimizzato per produzione. La fase di build e rilascio in produzione non è una cosa da sottovalutare. In questo articolo ti farò vedere qual’è il passo successivo che devi attuare per avere un codice ottimizzato e performante.
Se ancora non ti senti a tuo agio con ReactJS potresti dare un’occhiata alla guida su come imparare ReactJS.
Build e rilascio in produzione con Express
In questa guida darò per scontato che conosci ReactJS a pieno e che hai iniziato il tuo progetto o da zero o sfruttando create-react-app.
Il punto focale sta nel fatto che, chi come me utilizza Heroku per pubblicare le web app, senza una configurazione starà eseguendo sia in locale che sulla piattaforma sempre il comando “npm run start”.
Questo comando, che spesso va a richiamare lo script “react-scripts start”, non fa altro che creare una build di development corredata da source maps e tira su un WebpackDevServer.
Quello che vogliamo fare noi è creare una build ottimizzata per produzione e capire come funziona Express.
Da dove parte tutto?
Il motivo reale per cui ho creato questa guida sta nel fatto che moltissime persone ancora non capiscono bene come rilasciare il proprio codice, non sanno nemmeno che viene creata una build, e non comprendono l’importanza della fase di build e rilascio in produzione.
Inoltre mi chiedono come devono fare per eliminare i source maps generati dalla build della web app.
I source maps sono molto comodi per attività di debug ed assistenza, ma senza entrare nel merito di quale sia la migliore strada da intraprendere, in questa guida voglio farti vedere come puoi gestire tutte queste logiche.
Il bello di create-react-app infatti è che è un progetto totalmente indipendente dalla piattaforma sulla quale andremo a fare il rilascio o del modo in cui lo facciamo.
Vediamo insieme quindi cos’è Express e capiamo come migliorare la fase di build e rilascio in produzione di una web app.
Cos’è Express?
Express è un framework per applicazioni web su NodeJS che oltre a fornire tante funzioni avanzate lasciando intaccato Node, è in grado specialmente di gestire le chiamate che vengono fatte da un client al nostro server Node.
Il risultato che vogliamo ottenere è creare un server Express che risponda a tutte le chiamate alla nostra applicazione lasciando integrate le routes e fornendo una build ottimizzata per produzione.
Cosa utilizziamo?
Per prima cosa questa guida darà per scontato che utilizzi react-scripts per generare la build, per far partire Node, per far girare i tests, ecc.
Di conseguenza, se non lo hai già, puoi installare react-scripts:
npm install --save react-scripts
Questo passaggio non devi farlo se hai creato la tua applicazione ReactJS con create-react-app.
Detto ciò ora è necessario installare Express:
npm install --save express
Dunque installeremo anche Path e Compression:
npm install --save path npm install --save compression
Cos’è Path?
Path ci permette tramite il metodo join di creare un path verso i file che ci interessano preoccupandosi lui dei separatori specifici a seconda della piattaforma su cui eseguiamo la web app.
Cos’è Compression?
Compression ci permette di eseguire il deflate e la compressione GZIP dei nostri file tanto amata da Google.
Build e Rilascio in Produzione
A questo punto devi creare nella root del tuo progetto un file denominato server.js.
Una volta creato questo file al suo interno andremo a scrivere il seguente codice che ti spiego in seguito:
const express = require('express'); const path = require("path"); var compression = require('compression'); const server = express(); server.use(compression()); server.use(express.static(path.join(__dirname, 'build'))); server.get('*', (req, res) => { if (req.url.indexOf("/external/") === 0 || req.url.indexOf("/css/") === 0 || req.url.indexOf("/media/") === 0 || req.url.indexOf("/js/") === 0 || req.url.indexOf(".js") === 0 || req.url.indexOf(".css") === 0 || req.url.indexOf(".map") === 0) { res.setHeader("Cache-Control", "public, max-age=2592000"); res.setHeader("Expires", new Date(Date.now() + 2592000000).toUTCString()); } res.sendFile(path.join(__dirname, 'build', 'index.html')); }); server.listen(process.env.PORT || 9443); console.log("Server running on port:", process.env.PORT || 9443);
Quello che stiamo facendo, in ordine, è:
- Importare express
- Importare path
- Infine importare compression
- Dunque creiamo il server
- Diciamo al server di utilizzare la compressione
- Dunque diciamo di prendere staticamente i file contenuti nella cartella “build”
- Quindi per ogni richiesta che arriva al server (per ogni url chiamato)
- Per prima cosa controlliamo se abbiamo un file con un url per la quale vogliamo impostare Cache-Control ed Expires
- Infine inviamo come risposta al client il file index.html presente nella cartella “build”
- Per concludere impostiamo la porta sulla quale rimane in ascolto Express scegliendo tra la porta definita nell’environment di Node o la porta 9443
Solitamente la seconda scelta è quella che viene effettuata durante l’esecuzione in locale
Il file package.json
Adesso dobbiamo mettere mano al file package.json.
Dobbiamo creare uno script che vada ad eseguire il nostro server.
Come avrai notato il nostro server richiede che la build sia già presente quindi il nostro script dovrà creare la build e poi, in maniera sequenziale, far partire il server.
Lo script che utilizzo spesso è il seguente:
"production": "react-scripts build && node server.js"
Le due & servono ad indicare che dovrà essere eseguita prima la build e solo dopo dovrà andare in esecuzione il server.
Come elimino le source maps?
Per eliminare le source maps ci sono due modi.
Il primo consiste nel chiamare lo script di build con una variabile di ambiente:
"build-no-sourcemaps": "GENERATE_SOURCEMAP=false react-scripts build"
Un altro modo consiste nel creare uno script di questo tipo:
"delete-map-files": "find ./build/static/js -name '*.map' -delete"
Utilizzi Heroku e hai l’errore R14?
L’errore R14 può presentarsi nei piani Free ed Hobby visto il limite di RAM.
Questo vuol dire che puoi creare uno script di questo tipo:
"delete-map-files": "find ./build/static/js -name '*.map' -delete", "production": "npm run delete-map-files && node server.js"
Poi devi creare un file chiamato “Procfile” senza estensione nella root del progetto contenente:
web: npm run production
Questo sarà il “goal” che Heroku chiamerà.
L’unica pecca è che dovrai eseguire il push anche della cartella “build” che dovrai generarti in locale.
Heroku infatti esegue lo script “production”. In questo caso eliminerà (ma è facoltativo) i source maps e poi farà partire il server. Il server si aspetta che già la cartella di build sia presente.
Conclusioni
Come avrai capito i react-scripts creano un server che risponde alle chiamate fatte dai client.
Noi stiamo facendo la stessa cosa, utilizzando Express al posto di WebpackDevServer, ed andiamo ad abilitare la compressione.
Ora sai come fare la build e rilascio in produzione con Express!
Inoltre sappiamo impostare la cache del browser e, tanto di guadagnato, abbiamo scoperto anche due modi per eliminare i source maps (che sia questo sbagliato o meno).
Se vuoi approfondire ReactJS con dei libri ti consiglio questo articolo.
Vuoi scoprire anche altro sulla programmazione? Guarda questo articolo.
Se vuoi iscriviti alla newsletter e non ti perderai i nuovi articoli. Mando da 1 a 4 mail al mese ricapitolando dove siamo arrivati con ogni guida. Con la newsletter hai anche accesso a libri ed ebook gratuiti, così come a coupon Udemy ? .
Per dubbi o domande scrivimi nei commenti ? .
Se ti è piaciuto l’articolo seguimi su Facebook e Twitter oppure rimani sempre aggiornato con la newsletter (da 1 a 4 mail al mese!).