Tutorial > Creare una Web App con Node.js e React su Ubuntu 20.04

Creare una Web App con Node.js e React su Ubuntu 20.04

Pubblicato il: 08 settembre 2020

Node.js React Sviluppo Ubuntu

Node.js é una piattaforma Javascript open source utilizzata per l'esecuzione di codice Javascript server-side. Nel seguente tutorial vedremo come sfruttarlo per realizzare una semplice Web App con Node.js e come pubblicarla online sul tuo server Linux Ubuntu 18.04.

Vedremo inoltre come utilizzare il framework React per creare un’interfaccia web che utilizzi la nostra Web App. Utilizzeremo “Express” come framework per la gestione delle richieste web e SQLite per il salvataggio delle informazioni.

La nostra applicazione di esempio risponderà a delle chiamate REST, permettendo al client il salvataggio e la lettura di un archivio di libri.

Per iniziare dovrai connetterti al tuo server tramite una connessione SSH. Se non l’hai ancora fatto, ti consigliamo di seguire la nostra guida per connetterti in sicurezza con il protocollo SSH. In caso di server locale puoi passare al punto successivo e aprire il terminale del tuo server.

Installazione di Node.js

Installa Node.js tramite apt facendo attenzione a scaricare l'ultima versione disponibile. Per farlo aggiorna prima i tuoi repository, in questo modo:

$ sudo apt update && apt install nodejs

Prima di procedere aggiorna node all’ultima versione stabile lanciando i seguenti comandi:

$ sudo npm cache clean -f 
$ sudo npm install -g n 
$ sudo n stable

In seguito verifica la corretta installazione di Node.js mediante il comando:

$ nodejs -v

Se l'installazione è riuscita correttamente allora verrà visualizzata a schermo la versione installata.

Ora passiamo all'installazione di npm ovvero il "Node Package Manager" che ci servirà per installare moduli aggiuntivi per Node.js

$ sudo apt install npm

Creazione dell'applicazione server

Per creare un’applicazione compatibile con gli standard previsti da Node.js, devi prima di tutto inizializzare una configurazione base di npm.

Crea quindi una cartella per il progetto: in questo esempio la chiameremo "books", e spostati al suo interno.

cd /var/
sudo mkdir books
cd books

Avvia il seguente comando da console dentro la cartella appena creata:

npm init

Si avvierà una procedura guidata per la creazione di un file package.json, che conterrà tutte le informazione di base sul progetto e le sue dipendenze.

Utilizza i valori suggeriti per andare avanti, come sotto indicato:

This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install ` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (books)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to package.json:

{
  "name": "books",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Is this OK? (yes) yes

Rispondi in modo affermativo per completare la procedura.

Prosegui quindi installando i due moduli principali:

$ npm install --save express sqlite3
  • express: un framework in grado di gestire le richieste HTTP in ingresso;
  • sqlite3: un modulo client che ti permette di gestire piccoli database, dove andremo a salvare i nostri libri.

Aggiungendo il parametro --save , indichiamo a npm di aggiornare package.json, aggiungendo queste due dipendenze al progetto.

Puoi quindi procedere a creare il punto di ingresso per la tua applicazione, creando il file index.js nella stessa directory di package.json.

Utilizza il tuo editor di testo preferito per incollare il seguente contenuto nel file appena creato:

/**
 * Per prima cosa, includiamo i due moduli installati 
 * precedentemente
 */
var express = require('express');

var sqlite3 = require('sqlite3').verbose();

/**
 * A questo punto creiamo un database in memoria ( Ovvero 
 * non salvandolo su disco ) dove andremo a salvare i 
 * nostri dati
 */
var db = new sqlite3.Database(':memory:');

/**
 * Quindi creiamo una nuova tabella con solo due campi:
 * - title : Il titolo del libro
 * - author : Il nome completo dell'autore
 */
db.run("CREATE TABLE books (title TEXT, author TEXT)");

/**
 * Inizializziamo una nuova applicazione express
 */
var app = express();

/**
 * Utilizziamo al root principale del server per
 * elencare tutti i libri presenti
 */
app.get('/', function (req, res) {

    db.all(`SELECT * FROM books` , (err,rows) => {

        /**
         * Inviamo tutte le righe trovate nella tabella "books"
         */
        res.send( rows );
    });

});

/**
 * Invece per il salvataggio utilizzeremo il percorso
 * /save/ seguito dal titolo e dall'autore
 */
app.get('/save/:title/:author', function (req, res) {

    /**
     * Prepariamo l'istruzione di INSERT nella nostra tabella
     */
    var stmt = db.prepare("INSERT INTO books VALUES (?, ?)");

    /**
     * Ed eseguiamo la query di sopra, passando i dati presenti
     * nell url 
     */
    stmt.run( req.params.title, req.params.author , (err,rows) =>{

        /**
         * Infine inviamo uno stato "true" per indicare che il
         * salvataggio è avvenuto correttamente
         */
        res.send(true);
    });

    stmt.finalize();

});

/**
 * Avviamo quindi il server in ascolto sulla porta 80
 */

app.listen( 80, function () {
    console.log('Books server ready');
});

Completa installando le dipendenze del progetto, avviando il comando:

$ sudo npm install

Avviare il servizio

Per avviare la Web App in maniera persistente utilizzeremo forever: un software in grado di eseguire e mantenere in vita script, anche in caso di arresto del server.

Installalo utilizzando npm:

$ sudo npm install -g forever

Avvia quindi la tua Web App:

$ forever start index.js

Se tutto funziona correttamente, visitando la tua macchina virtuale al suo indirizzo IP, risponderà con:

[]

Utilizza quindi il browser per salvare i primi 3 libri visitando i seguenti URL:

http://IP_DEL_SERVER/save/Il%20Decamerone/Giovanni%20Boccaccio

http://IP_DEL_SERVER/save/Il%20fu%20Mattia%20Pascal/Luigi%20Pirandello

http://IP_DEL_SERVER/Il%20barone%20rampante/Italo%20Calvino

P.S.  Ricordati di sostituire sempre l’indirizzo IP con quello della tua istanza.

Assicurati quindi che i libri siano stati salvati navigando verso l'URL principale del server:

http://IP_DEL_SERVER/

Il server dovrebbe risponderti con il seguente contenuto:

[{"title":"Il Decamerone","author":"Giovanni Boccaccio"},{"title":"Il fu Mattia Pascal","author":"Luigi Pirandello"},{"title":"Il barone rampante","author":"Italo Calvino"}]

Creazione del frontend con React

Puoi quindi procedere con la creazione del frontend della tua applicazione React per poterti interfacciare con la Web App appena creata, iniziando dalla sua installazione.

Assicurati di trovarti nella directory principale “books”, quindi prosegui digitando i seguenti comandi:

$ npx create-react-app react-books
cd react-books

Una volta completato, troverai una directory “react-books” appena creata dal tool di React con all’interno il seguente contenuto:

/react-books 
      /node_modules 
      /public 
      /src

La directory più importante è sicuramente “src” poichè contiene il sorgente della nostra applicazione: sostituisci quindi il contenuto del file “App.js” presente in “src” con il seguente listato elencato sotto.

Inizia importando tutti i moduli necessari:

import React from 'react';
import './App.css';
import superagent from 'superagent';

Prosegui quindi creando una classe per gestire l’inserimento dei nuovi libri:

class InsertForm extends React.Component {

 constructor(props){
   super(props);

   // Imposto uno stato di base del componente
   this.state = {
     title: '', // Titolo del libro
     author: '' // ed autore
   };

   this.onSubmit = this.onSubmit.bind(this);
 }

 // Funzione chiamata per effettuare il salvataggio del libro
 onSubmit( se ){
   se.preventDefault();

   // Raccolgo le informazioni inserite dall'utente
   const title = encodeURIComponent(this.state.title);

   const author = encodeURIComponent(this.state.author);

   // Resetto i campi input
   this.setState({
     title: '',
     author: ''
   });

   // Effettuo la chiamat Ajax al server per salvare il libro
   superagent.get( `http://IP_DEL_SERVER:8080/save/${title}/${author}` ).then( msg => {

     // Avviso il componente contenitore del salvataggio avvenuto
     this.props.onSave();
   });

 }

render(){
   return <form onSubmit={this.onSubmit}>

     <div>
       <label>Title</label>
       <input type="title" value={this.state.title}
         onChange={se=>{this.setState({title: se.target.value})}}/>
     </div>

     <div>
       <label>Author</label>
       <input type="author" value={this.state.author}
         onChange={se=>{this.setState({author: se.target.value})}} />
     </div>

     <button onClick={this.onSubmit}>Salva</button>
    
   </form>;
 }

} 

Quindi puoi definire la classe principale che verrà richiamata dal file principale, creato automaticamente da create-react-app:

class App extends React.Component {

 constructor(props){
   super(props);

   // Imposto una lista vuota come partenza
   this.state = {
     data: []
   };

   this.reloadData = this.reloadData.bind( this );
 }

 // Funzione per ricaricare via Ajax i dati dal server
 reloadData(){
   superagent.get( 'http://IP_DEL_SERVER:8080/' ).then( msg => {

     // Imposto come stato i dati letti dal server
     this.setState( {data: msg.body} );
   });

 }

 // Al caricamento del componente carico i dati dal server
 componentDidMount(){
   this.reloadData();
 }

 render(){
   return <div style={{margin: '20px'}}>

     <div >

       <h2>Books list</h2>

       <ul> {/* Itero tutti i libri ricevuti dal server e genero dei <li /> */}
         {this.state.data.map( book => {
           return <li>{book.title} ({book.author})</li>
         })}
       </ul>
     </div>

     <h2>Save book</h2>

     {/* Inserisco il componente definito sopra e, in caso di salvaggio
         aggiorno la lista dei libri */}
     <InsertForm onSave={this.reloadData} />

   </div>;
 }
}

P.S. Assicurati di cambiare l’indirizzo IP utilizzato in questo tutorial con quello del tuo server.

Concludi infine la scrittura del file esportando la classe “App”:

export default App;

Una volta completata l'esportazione, dalla directory “react-books” lancia il seguente comando per compilare la tua applicazione:

$ npm run-script build

Il comando di sopra, preparerà una nuova cartella “build” contenente una versione compatta del sorgente Javascript pronta per essere utilizzata da un comune web server oppure, come nel nostro caso, dalla libreria Express usata dalla Web App.

Prima di concludere è necessario apportare una piccola modifica al nostro server, modificando la porta di ascolto, indicata precedentemente con :

app.listen( 80, function () {
    console.log('Books server ready');
});

con una nuova porta, la 8080:

app.listen( 8080, function () {
    console.log('Books server ready');
});

Quindi aggiungi la seguente porzione di codice per servire i file statici di React presenti nella directory “build”:

var reactApp = express();

reactApp.use( '/' , express.static( 'react-books/build' ) );

reactApp.listen( 80 , function() {
	console.log( 'React app ready' );
} );

Riavvia infine tutto lanciando il comando:

$ forever restartall

Esecuzione e test dell'applicazione

Procedi utilizzando un browser a tuo piacere e visita l’URL del tuo server, ad esempio “http://IP_DEL_SERVER/”

Se tutto funziona correttamente, dovresti vedere la seguente schermata:
Test inserimento libro

Procedi quindi inserendo un libro:
Test inserimento libro

E premi il pulsante “Salva”:
Test inserimento libro

Perfetto! Se tutto funziona correttamente, vuol dire che avrai creato con successo la tua prima Web App con Node.js e Redis.

Puoi consultare la documentazione ufficiale di React per approfondire il suo utilizzo. Valuta anche di utilizzare un web server più robusto, come ad esempio NGINX, per servire i file statici di React e le richieste API.