Come distribuire un’applicazione web Node.js?
Node.js è un ambiente di runtime JavaScript che consente di eseguire codice JavaScript al di fuori del browser.
Node.js è costruito sul motore JavaScript Chrome V8 e presenta un modello di I/O non bloccante e guidato dagli eventi che lo rende molto efficiente per la creazione di applicazioni lato server.
In questo articolo si analizzeranno i vantaggi e i limiti di Node.js per lo sviluppo di applicazioni lato server e le opzioni di distribuzione per le applicazioni Node.js.
Inoltre, costruirete, dockerizzerete e distribuirete gratuitamente un’applicazione Node.js su Back4app Containers.
Contents
- 1 Vantaggi di Node.js per lo sviluppo di applicazioni web
- 2 Limitazioni di Node.js per lo sviluppo di applicazioni web
- 3 Distribuzione di un’applicazione Web Node.js
- 4 Distribuzione di un’applicazione Node.js su Back4app utilizzando i contenitori Back4app
- 5 Conclusione
- 6 FAQ
- 7 Come distribuire un’applicazione Web Node.js?
Vantaggi di Node.js per lo sviluppo di applicazioni web
Da quando Node.js è stato rilasciato nel 2009, è stata una scelta privilegiata per la realizzazione di applicazioni web lato server. Ecco alcuni dei motivi.
Efficienza e scalabilità
Come accennato in precedenza, Node.js viene eseguito sul motore V8 di Chrome, che consente di eseguire codice JavaScript. Questo motore utilizza la compilazione Just-in-time (JIT) per convertire il codice JavaScript nativo in codice macchina.
In fase di esecuzione, i componenti Turbofan e Crankshaft del V8 analizzano il codice macchina e lo ricompilano per fornire le migliori prestazioni possibili.
Inoltre, grazie al modello event-driven di Node.js, è in grado di eseguire codice in risposta a eventi, come l’interazione dell’utente, senza bloccare il thread principale dell’applicazione, il che lo rende ideale per le applicazioni con un traffico elevato.
L’architettura modulare di Node.js e il supporto integrato per il clustering rendono le applicazioni sviluppate con esso facilmente scalabili. La sua architettura modulare consente di suddividere l’applicazione in componenti che possono essere scalati in modo indipendente.
Il modulo cluster consente di creare istanze multiple dell’applicazione su più core o server. Ciò consente di scalare orizzontalmente l’applicazione aggiungendo altri server al cluster.
Curva di apprendimento poco profonda
Node.js è basato su JavaScript, un linguaggio di programmazione ampiamente utilizzato per lo sviluppo web. L’uso di JavaScript in Node.js ha reso lo sviluppo lato server con Node.js più accessibile agli sviluppatori che hanno già familiarità con JavaScript.
Questo riduce la complessità dello sviluppo web e snellisce il processo di sviluppo.
Grande ecosistema
Node.js ha una grande e attiva comunità di sviluppatori che hanno creato un vasto ecosistema di moduli e pacchetti.
Il gestore di pacchetti Node.js, npm, ospita oltre un milione di pacchetti che possono essere utilizzati per aggiungere funzionalità alle proprie applicazioni.
Questi pacchetti possono spaziare da piccole librerie di utilità come lodash a grandi framework Nest.js che possono essere usati per costruire applicazioni web complesse.
La disponibilità di un’ampia gamma di moduli e pacchetti può ridurre significativamente il tempo e lo sforzo necessari per sviluppare applicazioni web.
È possibile sfruttare questi pacchetti per aggiungere alle proprie applicazioni funzionalità quali l’autenticazione, l’integrazione con i database e il rendering lato server.
Limitazioni di Node.js per lo sviluppo di applicazioni web
Quando si parla di sviluppo di applicazioni web, Node.js offre molti vantaggi, come prestazioni efficienti, scalabilità e un vasto ecosistema di moduli e pacchetti. Tuttavia, come ogni tecnologia, Node.js presenta alcune limitazioni. Alcune di queste limitazioni sono le seguenti.
Grande consumo di memoria
Node.js utilizza un modello di I/O non bloccante, il che significa che può gestire molte richieste in contemporanea senza creare nuovi thread. Tuttavia, ogni richiesta richiede comunque l’allocazione di memoria per la sua elaborazione.
Ciò significa che le applicazioni Node.js possono consumare molta memoria, soprattutto se gestiscono molte richieste simultanee. Questo può essere un problema per le applicazioni in esecuzione su sistemi con memoria limitata.
Modello di programmazione asincrona
Il modello di programmazione asincrona di Node.js è un vantaggio significativo, ma può anche essere fonte di complessità per gli sviluppatori.
La programmazione asincrona richiede un modo diverso di pensare al flusso del programma. Questo cambiamento può essere impegnativo per gli sviluppatori abituati alla programmazione sincrona.
Inoltre, la programmazione asincrona può portare al callback hell, una situazione in cui il codice diventa difficile da leggere e da mantenere a causa dei callback annidati.
Ciclo di eventi a thread singolo
Node.js è stato progettato per gestire attività ad alta intensità di I/O, come la comunicazione di rete, l’I/O dei file e le operazioni di database.
Tuttavia, potrebbe non essere la scelta migliore per attività ad alta intensità di CPU come calcoli complessi, elaborazione di dati o apprendimento automatico.
Questo perché Node.js utilizza un modello di loop di eventi a thread singolo, il che significa che può eseguire solo un task alla volta.
Se un’attività richiede molto tempo per essere completata, può bloccare il ciclo degli eventi e rendere l’applicazione non reattiva.
Distribuzione di un’applicazione Web Node.js
Esistono diversi modi per distribuire un’applicazione Node.js. Esploriamone alcuni.
Servizi di hosting cloud
I servizi di hosting cloud consentono di distribuire l’applicazione Node.js su server gestiti da aziende come Amazon Web Services (AWS), Google Cloud Platform (GCP) o Microsoft Azure.
Offrono vantaggi come la scalabilità, la disponibilità globale, la facilità di implementazione e il prezzo pay-as-you-go. Inoltre, si integrano con altri servizi cloud come i database e il bilanciamento del carico per aiutarvi a creare applicazioni migliori.
È sufficiente distribuire l’applicazione Node.js sui server del provider cloud per utilizzare i servizi di cloud hosting. Quindi, è possibile accedere all’applicazione tramite un browser web o un’altra applicazione client.
Alcuni esempi di servizi di cloud hosting per Node.js includono:
- AWS Elastic Beanstalk
- GCP App Engine
- Microsoft Azure App Service
Queste piattaforme consentono di distribuire, scalare e gestire facilmente le applicazioni Node.js senza preoccuparsi dell’infrastruttura sottostante.
Inoltre, offrono funzioni come il ridimensionamento automatico, il bilanciamento del carico e il monitoraggio integrato per aiutarvi a mantenere l’applicazione in funzione senza problemi.
Server privati virtuali (VPS)
I server privati virtuali (VPS) sono macchine virtuali che girano su server fisici, consentendo di installare ed eseguire la propria applicazione Node.js come se fosse in esecuzione su un server dedicato.
I server privati virtuali offrono un maggiore controllo e opzioni di personalizzazione rispetto all’hosting condiviso e rappresentano un’alternativa più economica rispetto ai server dedicati.
Per utilizzare l’hosting VPS per la vostra applicazione Node.js, scegliete un provider di hosting che offra immagini Node.js preconfigurate o installate voi stessi Node.js e le altre dipendenze.
Alcuni esempi di fornitori di hosting VPS per Node.js sono:
- DigitalOcean
- Linode
- Vultr
Containerizzazione
La containerizzazione è una tecnica per distribuire ed eseguire le applicazioni in un ambiente containerizzato che le isola dall’infrastruttura sottostante.
I container offrono un’alternativa leggera e flessibile alle macchine virtuali tradizionali, rendendoli ideali per la distribuzione di applicazioni Node.js.
Sono portatili e consentono di costruire e testare le applicazioni sulle loro macchine locali, per poi distribuirle su qualsiasi piattaforma che supporti la containerizzazione.
Inoltre, i container possono essere facilmente scalati verso l’alto o verso il basso a seconda del carico di lavoro, garantendo una maggiore scalabilità. Forniscono coerenza tra le diverse piattaforme, facilitando la gestione e la manutenzione delle applicazioni.
Alcuni esempi di piattaforme che offrono la containerizzazione come servizio (CaaS) sono:
- Back4app Containers
- AWS ECS
- Azure ACI
- Google GKE
Distribuzione di un’applicazione Node.js su Back4app utilizzando i contenitori Back4app
Back4app è una piattaforma cloud che consente di creare, gestire e distribuire applicazioni web utilizzando un’interfaccia utente intuitiva o uno strumento CLI completo. Back4app offre una serie di servizi, uno dei quali è la containerizzazione.
I container di Back4app eliminano il divario tra sviluppo e produzione automatizzando le attività ripetitive e gestendo l’infrastruttura lato server, garantendo che non dobbiate preoccuparvi di DevOps.
In questo articolo, costruirete e distribuirete una semplice applicazione Node.js utilizzando i container Back4app. L’applicazione Node.js che costruirete è una semplice libreria API con supporto per le funzionalità CRUD (Create, Read, Update, Delete).
Impostazione dell’ambiente di sviluppo
Creare una nuova cartella di progetto e inizializzare npm nella cartella di progetto, eseguendo il comando seguente:
mkdir bookstoreapp && cd bookstoreapp && npm init -y
Quindi, installate le dipendenze necessarie per il progetto eseguendo il comando seguente:
npm install express dotenv mysql knex
Le dipendenze installate in precedenza sono:
- Express.js: Express è un framework Node.js che semplifica il processo di sviluppo delle applicazioni Node.js.
- dotenv: dotenv è un pacchetto npm che si può usare per gestire le variabili ambientali.
- MySQL: La dipendenza MySQL è il driver Node.js per MySQL, che verrà utilizzato come database per questa applicazione.
- Knex: Knex è un costruttore di query per JavaScript. Questa dipendenza è necessaria per interagire con il database senza scrivere query SQL.
Quindi, creare un file routes.js
e un file index.js
nella cartella principale del progetto.
Quindi, aggiungere il blocco di codice sottostante al file index.js
:
//index.js
require("dotenv").config();
const express = require("express");
const app = express();
const port = 3000;
const router = require("./routes.js");
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use("/", router);
app.listen(port, () => {
console.log(`App listening at ${port}`);
});
Il blocco di codice precedente crea un server Express e ascolta le richieste HTTP in arrivo sulla porta 3000. Utilizza funzioni middleware per analizzare i dati in arrivo e associa un router al percorso principale per gestire le richieste in arrivo.
Infine, avvia il server e registra un messaggio nella console che indica che il server è in esecuzione e in ascolto sulla porta specificata.
Quindi, aggiungere uno script di avvio
al file package.json
. In questo modo:
"start": "node index.js",
Connessione al database
Knex richiede un file knex contenente le opzioni di configurazione per la connessione a un database.
Eseguire il comando seguente per creare un file knex:
knex init
Per configurare Knex in modo che utilizzi MySQL, sostituite il contenuto del file knexfile.js
con il blocco di codice sottostante:
// Update with your config settings.
require("dotenv").config()
/**
* @type { Object.<string, import("knex").Knex.Config> }
*/
module.exports = {
development: {
client: "mysql",
connection: {
host: process.env.DEV_HOST,
user: process.env.DEV_USER,
password: process.env.DEV_PASSWORD,
database: process.env.DEV_NAME,
},
migrations: {
directory: "./db/migrations",
}
},
production: {
client: "mysql",
connection: {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
},
migrations: {
directory: "./db/migrations",
}
},
};
Quindi, creare una cartella db
nella cartella principale del progetto e creare un file db.js.
Aggiungere il blocco di codice sottostante al file db.js
:
//db.js
const knex = require("knex");
const knexFile = require("../knexfile.js");
const environment = process.env.NODE_ENV || "development";
module.exports = knex(knexFile[environment]);
Il blocco di codice precedente imposta la variabile d'ambiente
sulla variabile d’ambiente NODE_ENV
o su development
, se NODE_ENV
non è impostato. In questo modo, si possono specificare configurazioni diverse per ambienti diversi, come sviluppo o produzione.
Creazione dei file di migrazione
Eseguite il comando seguente per creare i file di migrazione per il vostro database:
knex migrate:make bookstore
Il comando precedente crea un file di migrazione nel percorso del file knexfile.js
specificato (“./db/migrations”).
Quindi, aprire il file di migrazione e sostituire il codice in esso contenuto con il blocco di codice sottostante:
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.up = function (knex) {
return knex.schema.createTable("books", (table) => {
table.increments("id").primary();
table.string("title");
table.string("author");
table.string("genre");
table.timestamps(true, true);
});
};
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.down = function (knex) {
return knex.schema.dropTableIfExists("books");
};
Quindi, eseguire il comando seguente per eseguire il file di migrazione:
knex migrate:latest
Implementazione del routing
Infine, aggiungere il blocco di codice sottostante al file routes.js:
const express = require("express");
const router = express.Router();
const db = require("./db/db.js");
// GET /books
router.get("/books", async (req, res) => {
try {
const books = await db("books");
res.json(books);
} catch (err) {
console.error(err);
res.status(500).send("Internal Server Error");
}
});
//POST /books/new
router.post("/books/new", async (req, res) => {
try {
const { title, author, genre } = req.body;
const book = await db("books").insert({
title,
author,
genre,
});
res.status(201).json(book);
} catch (err) {
console.error(err);
res.status(500).send("Internal Server Error");
}
});
//PUT /books/:id
router.put("/books/:id", async (req, res) => {
const { id } = req.params;
try {
const { title, author, genre } = req.body;
const book = await db("books").where({ id }).update(
{
title,
author,
genre,
},
["id", "title", "author", "genre"]
);
if (book.length !== 0) {
res.status(201).send(book);
} else {
res.status(404).json({ error: "Book not found" });
}
} catch (err) {
console.error(err);
res.status(500).send("Internal Server Error");
}
});
//DELETE /books/:id
router.delete("/books/:id", async (req, res) => {
const { id } = req.params;
try {
const book = await db("books").where({ id }).del();
if (book !== 0) {
res.status(200).json({ message: "Book deleted" });
} else {
res.status(404).json({ error: "Book not found" });
}
} catch (err) {
console.error(err);
res.status(500).send("Internal Server Error");
}
});
module.exports = router;
Il blocco di codice precedente definisce diverse rotte per gestire le richieste HTTP, tra cui ottenere tutti i libri, creare un nuovo libro, aggiornare un libro esistente e cancellare un libro.
Creare un file Docker
Un Dockerfile è un file che contiene un insieme di istruzioni, scritte in un formato specifico, su come costruire un’immagine Docker. Un’immagine Docker è un’istantanea di un contenitore che include tutto ciò che è necessario per eseguire un’applicazione, come il codice dell’applicazione, il runtime, le librerie e gli strumenti di sistema.
Per eseguire un’applicazione Node.js su Back4app Containers, è necessario creare un file Docker contenente le istruzioni per la creazione dell’immagine Docker.
Eseguite il comando seguente per creare un file Docker:
touch Dockerfile
Successivamente, è necessario scegliere un’immagine di base per l’applicazione Node.js. Un’immagine di base in Docker è il punto di partenza per la creazione di una nuova immagine Docker. È la base su cui viene costruita l’immagine Docker.
Aggiungete il blocco di codice sottostante al vostro file Docker per specificare l’immagine di base:
# Specify base image
FROM node:18-alpine
Questa riga specifica l’immagine di base su cui verrà costruita l’immagine Docker. In questo caso, la versione 18 di Node.js è in esecuzione su una distribuzione Alpine Linux.
Successivamente, è necessario specificare la propria directory di lavoro. Tutti i comandi successivi del file Docker saranno eseguiti relativamente a questa directory.
Aggiungete il blocco di codice sottostante al vostro file Docker per specificare la vostra directory di lavoro:
# Specify working directory
WORKDIR /app
Quindi, è necessario copiare i file package.json
e package-lock.json
dalla directory corrente (cioè quella che contiene il file Docker) alla directory di lavoro(/app
).
Aggiungete il blocco di codice sottostante al vostro file Docker per copiare i file:
# Copy package.json and package-lock.json
COPY package*.json ./
Successivamente, è necessario eseguire il comando npm install
nella cartella di lavoro per installare le dipendenze di Node.js elencate in package.json
e package-lock.json
.
Aggiungete il codice sottostante al vostro file Docker per installare le dipendenze:
# Install dependencies
RUN npm install
Il comando precedente installerà tutte le dipendenze elencate nei file package.json
****e package-lock.json
e le memorizzerà nella cartella node_modules
nella directory di lavoro specificata.
Successivamente, è necessario copiare il codice sorgente dell’applicazione nella cartella di lavoro.
Aggiungete il blocco di codice sottostante al vostro file Docker per copiare il codice sorgente:
# Copy source code
COPY . .
Successivamente, è necessario esporre una porta alla macchina host. L’esposizione di una porta consente al contenitore Docker di ricevere connessioni di rete in entrata sulla porta esposta quando viene eseguito.
Aggiungete il blocco di codice sottostante al vostro file Docker per esporre la porta 3000 alla macchina host:
# Expose port 3000
EXPOSE 3000
Infine, è necessario specificare il comando da eseguire all’avvio del contenitore Docker. In genere, le applicazioni Node.js vengono avviate con il comando npm start
.
Aggiungete il blocco di codice sottostante al vostro file Docker per specificare il comando:
# Run the app
CMD ["npm", "start"]
Il file Docker finito dovrebbe assomigliare al blocco di codice sottostante:
# Specify base image
FROM node:18-alpine
# Specify working directory
WORKDIR /app
# Copy package.json and package-lock.json
COPY package*.json ./
# Install dependencies
RUN npm install
# Copy source code
COPY . .
# Expose port 3000
EXPOSE 3000
# Run the app
CMD ["npm", "start"]
Dopo aver creato il file di Docker, inviate il codice a GitHub.
Creare una nuova applicazione Back4app
Il primo passo per distribuire un’applicazione Node.js su Back4app è creare un account su Back4app (se non ne avete uno). È possibile crearne uno seguendo i passaggi seguenti.
- Accedere al sito Web di Back4app.
- Quindi, fare clic sul pulsante Iscriviti nell’angolo in alto a destra della pagina di destinazione.
- Infine, compilate il modulo di iscrizione e inviatelo.
Dopo aver creato con successo il vostro account Back4app, accedete al vostro account Back4app e fate clic sul pulsante NUOVA APP nell’angolo in alto a destra.
Facendo clic su questo pulsante si accede a una pagina in cui si sceglie “Come si desidera creare la nuova applicazione?”. Poiché la distribuzione avviene tramite containerizzazione, scegliere Containers as a Service, come mostrato nell’immagine seguente.
Quindi, collegare l’account GitHub all’account Back4app. Potete scegliere di dare a Back4app l’accesso a tutti i repository del vostro account o a repository specifici.
Scegliere l’applicazione che si desidera distribuire, in questo caso l’applicazione costruita in questa esercitazione, e fare clic su Seleziona.
Facendo clic sul pulsante di selezione si accede a una pagina in cui vengono richieste alcune informazioni sulla propria applicazione, come il nome, il ramo, la directory principale e le variabili ambientali.
Assicurarsi di compilare tutte le variabili ambientali necessarie al funzionamento dell’applicazione. Dopo aver compilato i dati richiesti, fare clic su Crea applicazione, come mostrato nell’immagine seguente.
Facendo clic sul pulsante Crea applicazione si avvia il processo di distribuzione. Al termine del processo di distribuzione, nell’angolo sinistro della schermata verrà specificato un URL da cui è possibile accedere all’applicazione distribuita, come mostrato nell’immagine seguente.
Se il processo di distribuzione richiede molto tempo, è possibile controllare i registri per verificare se si è verificato un errore nella distribuzione o consultare la guida alla risoluzione dei problemi di Back4app.
Conclusione
Node.js è un framework molto diffuso che offre molti vantaggi, come la velocità delle prestazioni, la scalabilità e la flessibilità. Tuttavia, presenta anche alcune limitazioni, come la sua natura single-thread, che può rendere difficile la gestione di carichi di lavoro pesanti.
Nonostante queste limitazioni, sono disponibili diverse opzioni di distribuzione per le applicazioni Node.js, tra cui Back4app, che offre una piattaforma affidabile e facile da usare per l’hosting e la gestione delle applicazioni Node.js.
Creando un’applicazione Node.js e seguendo i passaggi descritti in questo articolo, potrete facilmente distribuire le vostre applicazioni Node.js su Back4app e sfruttare i suoi numerosi vantaggi.
Siete ancora interessati al deployment e all’hosting di Node.js? Consultate questi due tutorial:
FAQ
Come distribuire un’applicazione Web Node.js?
– Imposta il tuo ambiente di sviluppo
– Connettiti al tuo database
– Crea file di migrazione
– Implementa il routing
– Crea un Dockerfile
– Crea una nuova applicazione Back4app