¿Cómo implementar una aplicación web Node.js?
Node.js es un entorno de ejecución de JavaScript que le permite ejecutar código JavaScript fuera del navegador. Node.js se basa en el motor JavaScript Chrome V8 y presenta un modelo de E/S sin bloqueo y controlado por eventos que lo hace muy eficiente para crear aplicaciones del lado del servidor.
En este artículo, explorará las ventajas y limitaciones de Node.js para el desarrollo de aplicaciones del lado del servidor y las opciones de implementación para aplicaciones Node.js. Además, creará, acoplará e implementará una aplicación Node.js en Back4app Containers de forma gratuita.
Contents
Ventajas de Node.js para el desarrollo de aplicaciones web
Desde que se lanzó Node.js en 2009, ha sido una excelente opción para crear aplicaciones web del lado del servidor. Estas son algunas de las razones.
Eficiencia y escalabilidad
Como se mencionó anteriormente, Node.js se ejecuta en el motor V8 de Chrome, lo que le permite ejecutar código JavaScript.
Este motor utiliza compilación Justo a tiempo (JIT) para convertir código JavaScript nativo en código de máquina.
En tiempo de ejecución, los componentes Turbofan y Crankshaft del V8 analizan el código de la máquina y lo vuelven a compilar para proporcionar el mejor rendimiento posible.
Además, gracias al modelo basado en eventos de Node.js, puede ejecutar código en respuesta a eventos, como la interacción del usuario, sin bloquear el hilo principal de la aplicación, lo que lo hace ideal para aplicaciones con mucho tráfico.
La arquitectura modular de Node.js y el soporte integrado para agrupación en clústeres hacen que las aplicaciones desarrolladas con él sean fáciles de escalar. Su arquitectura modular le permite dividir su aplicación en componentes que se pueden escalar de forma independiente.
Mientras que el módulo de clúster le permite generar múltiples instancias de su aplicación en múltiples núcleos o servidores.
Esto permite el escalado horizontal, donde la aplicación se puede escalar agregando más servidores al clúster.
Curva de aprendizaje superficial
Node.js está basado en JavaScript, un lenguaje de programación muy utilizado para el desarrollo web.
El uso de JavaScript en Node.js ha hecho que el desarrollo del lado del servidor con Node.js sea más accesible para los desarrolladores que ya están familiarizados con JavaScript.
Esto reduce la complejidad del desarrollo web y agiliza el proceso de desarrollo.
Gran ecosistema
Node.js tiene una comunidad grande y activa de desarrolladores que han creado un vasto ecosistema de módulos y paquetes.
El administrador de paquetes de Node.js, npm, aloja más de un millón de paquetes que puede utilizar para agregar funcionalidad a sus aplicaciones.
Estos paquetes pueden variar desde pequeñas bibliotecas de utilidades como lodash hasta grandes marcos Nest.js que pueden usarse para crear aplicaciones web complejas.
La disponibilidad de una amplia gama de módulos y paquetes puede reducir significativamente el tiempo y el esfuerzo necesarios para desarrollar aplicaciones web.
Puede aprovechar estos paquetes para agregar funciones como autenticación, integración de bases de datos y representación del lado del servidor a sus aplicaciones.
Limitaciones de Node.js para el desarrollo de aplicaciones web
Cuando se trata de desarrollo de aplicaciones web, Node.js ofrece muchos beneficios, como rendimiento eficiente, escalabilidad y un vasto ecosistema de módulos y paquetes.
Sin embargo, como cualquier tecnología, Node.js tiene algunas limitaciones. Algunas de las limitaciones incluyen las siguientes.
Gran consumo de memoria
Node.js utiliza un modelo de E/S sin bloqueo, lo que significa que puede manejar muchas solicitudes simultáneamente sin crear nuevos subprocesos. Sin embargo, cada solicitud aún requiere que se asigne memoria para su procesamiento.
Esto significa que las aplicaciones Node.js pueden consumir mucha memoria, especialmente si manejan muchas solicitudes simultáneas. Esto puede ser un problema para aplicaciones que se ejecutan en sistemas con memoria limitada.
Modelo de programación asincrónica
Si bien el modelo de programación asincrónica de Node.js es una ventaja significativa, también puede ser una fuente de complejidad para los desarrolladores.
La programación asincrónica requiere una forma diferente de pensar sobre el flujo del programa. Este cambio puede resultar un desafío para los desarrolladores acostumbrados a la programación sincrónica.
Además, la programación asincrónica puede provocar un infierno de devoluciones de llamadas, una situación en la que el código se vuelve difícil de leer y mantener debido a las devoluciones de llamadas anidadas.
Bucle de eventos de un solo subproceso
Node.js está diseñado para manejar tareas intensivas de E/S, como comunicación de red, E/S de archivos y operaciones de bases de datos.
Sin embargo, puede que no sea la mejor opción para tareas que requieren un uso intensivo de la CPU, como cálculos complejos, procesamiento de datos o aprendizaje automático.
Esto se debe a que Node.js utiliza un modelo de bucle de eventos de un solo subproceso, lo que significa que solo puede ejecutar una tarea a la vez.
Si una tarea tarda mucho en completarse, puede bloquear el bucle de eventos y hacer que la aplicación deje de responder.
Implementación de una aplicación web Node.js
Hay varias formas de implementar una aplicación Node.js. Exploremos algunas de ellas.
Servicios de alojamiento en la nube
Los servicios de alojamiento en la nube le permiten implementar su aplicación Node.js en servidores administrados por empresas como Amazon Web Services (AWS), Google Cloud Platform (GCP) o Microsoft Azure.
Ofrecen beneficios como escalabilidad, disponibilidad global, fácil implementación y precios de pago por uso. Además, se integran con otros servicios en la nube, como bases de datos y equilibrio de carga, para ayudarlo a crear mejores aplicaciones.
Simplemente implemente su aplicación Node.js en los servidores del proveedor de la nube para utilizar los servicios de alojamiento en la nube. Luego, puede acceder a su aplicación a través de un navegador web u otra aplicación cliente.
Algunos ejemplos de servicios de alojamiento en la nube para Node.js incluyen:
- AWS Elastic Beanstalk
- GCP App Engine
- Microsoft Azure App Service
Estas plataformas facilitan la implementación, escala y administración de sus aplicaciones Node.js sin preocuparse por la infraestructura subyacente. Además, ofrecen funciones como escalado automático, equilibrio de carga y monitoreo integrado para ayudarlo a mantener su aplicación funcionando sin problemas.
Servidores Privados Virtuales (VPS)
Los servidores privados virtuales (VPS, del inglés “Virtual Private Servers”) son máquinas virtuales que se ejecutan en servidores físicos, lo que le permite instalar y ejecutar su aplicación Node.js como si se estuviera ejecutando en un servidor dedicado.
Los servidores privados virtuales le brindan mayor control y opciones de personalización que el alojamiento compartido y, al mismo tiempo, brindan una alternativa más rentable a los servidores dedicados.
Para utilizar alojamiento VPS para su aplicación Node.js, seleccione un proveedor de alojamiento que ofrezca imágenes de Node.js preconfiguradas o instale Node.js y otras dependencias usted mismo.
Algunos ejemplos de proveedores de alojamiento VPS para Node.js incluyen:
- DigitalOcean
- Linode
- Vultr
Contenedorización
La contenedorización es una técnica para implementar y ejecutar aplicaciones en un entorno en contenedores que las aísla de la infraestructura subyacente.
Los contenedores proporcionan una alternativa ligera y flexible a las máquinas virtuales tradicionales, lo que los hace ideales para implementar aplicaciones Node.js.
Son portátiles, lo que le permite crear y probar aplicaciones en sus máquinas locales y luego implementarlas en cualquier plataforma que admita la contenedorización.
Los contenedores también se pueden ampliar o reducir fácilmente según la carga de trabajo, lo que proporciona una mayor escalabilidad.
Proporcionan coherencia entre diferentes plataformas, lo que facilita la gestión y el mantenimiento de las aplicaciones.
Algunos ejemplos de plataformas que ofrecen Containerización como Servicio (CaaS) incluyen:
- Back4app Containers
- AWS ECS
- Azure ACI
- Google GKE
Implementación de una aplicación Node.js en Back4app usando Back4app Containers
Back4app es una plataforma en la nube que le permite crear, administrar e implementar aplicaciones web utilizando una interfaz de usuario intuitiva o su herramienta CLI con todas las funciones. Back4app ofrece una gama de servicios, uno de los cuales es la contenedorización.
Back4app Containers eliminan la brecha entre desarrollo y producción al automatizar tareas repetitivas y administrar su infraestructura del lado del servidor, lo que garantiza que no tenga que preocuparse por DevOps.
En este artículo, creará e implementará una aplicación Node.js sencilla utilizando contenedores Back4app. La aplicación Node.js que creará es una API de librería simple compatible con la funcionalidad CRUD (Crear, Leer, Actualizar, Eliminar, del inglés “Create, Read, Update, Delete) functionality.”).
Configurando su entorno de desarrollo
Cree un nuevo directorio de proyecto e inicialice npm en el directorio del proyecto ejecutando el siguiente comando:
mkdir bookstoreapp && cd bookstoreapp && npm init -y
A continuación, instale las dependencias necesarias para el proyecto ejecutando el siguiente comando:
npm install express dotenv mysql knex
Las dependencias que instaló anteriormente son:
- Express.js: Express es un marco de Node.js que simplifica el proceso de desarrollo de aplicaciones Node.js.
- dotenv: dotenv es un paquete npm que puede utilizar para gestionar sus variables ambientales.
- MySQL: la dependencia de MySQL es el controlador Node.js para MySQL, que utilizará como base de datos para esta aplicación.
- Knex: Knex es un generador de consultas para JavaScript. Necesitará esta dependencia para interactuar con su base de datos sin escribir consultas SQL sin formato.
A continuación, cree un archivo route.js y un index.js en el directorio raíz de su proyecto.
Luego, agregue el siguiente bloque de código a su archivo 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}`);
});
El bloque de código anterior crea un servidor Express y escucha las solicitudes HTTP entrantes en el puerto 3000.
Utiliza funciones de middleware para analizar los datos entrantes y asocia un enrutador con la ruta raíz para manejar las solicitudes entrantes.
Finalmente, inicia el servidor y registra un mensaje en la consola indicando que el servidor se está ejecutando y escuchando en el puerto especificado.
A continuación, agregue un script start a su archivo package.json. De esta forma:
"start": "node index.js",
Connecting to Your Database
Knex requiere un archivo knex que contenga opciones de configuración para conectarse a una base de datos.
Ejecute el siguiente comando para crear un archivo knex:
knex init
Para configurar Knex para usar MySQL, reemplace el contenido de su archivo knexfile.js con el siguiente bloque de código:
// 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",
}
},
};
A continuación, cree una carpeta db en el directorio raíz de su proyecto y cree un archivo db.js.
Agregue el siguiente bloque de código a su archivo 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]);
El bloque de código anterior establece la variable environment en la variable de entorno NODE_ENV o development si NODE_ENV no está configurado.
De esta manera, le permite especificar diferentes configuraciones para diferentes entornos, como desarrollo o producción.
Crear archivos de migración
Ejecute el siguiente comando para crear archivos de migración para su base de datos:
knex migrate:make bookstore
El comando anterior crea un archivo de migración en la ruta del archivo especificada en knexfile.js(“./db/migrations”).
Luego, abra su archivo de migración y reemplace el código que contiene con el bloque de código a continuación:
/**
* @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");
};
Luego, ejecute el siguiente comando para ejecutar el archivo de migración:
knex migrate:latest
Implementación de enrutamiento
Finalmente, agregue el siguiente bloque de código a su archivo route.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;
El bloque de código anterior define varias rutas para manejar solicitudes HTTP, incluida la obtención de todos los libros, la creación de un libro nuevo, la actualización de un libro existente y la eliminación de un libro.
Creando un Dockerfile
Un Dockerfile es un archivo que contiene un conjunto de instrucciones, escritas en un formato específico, sobre cómo crear una imagen de Docker.
Una imagen de Docker es una instantánea de un contenedor que incluye todo lo necesario para ejecutar una aplicación, como el código de la aplicación, el tiempo de ejecución, las bibliotecas y las herramientas del sistema.
Para ejecutar una aplicación Node.js en Back4app Containers, debe crear un Dockerfile que contenga instrucciones para crear la imagen de Docker.
Ejecute el siguiente comando para crear un Dockerfile:
touch Dockerfile
A continuación, deberá elegir una imagen base para su aplicación Node.js. Una imagen base en Docker es el punto de partida para crear una nueva imagen de Docker. Es la base sobre la que se construye la imagen de Docker.
Agregue el siguiente bloque de código a su Dockerfile para especificar su imagen base:
# Specify base image
FROM node:18-alpine
Esta línea especifica la imagen base sobre la que se creará esta imagen de Docker. En este caso, la versión Node.js 18 se ejecuta en una distribución Alpine Linux.
A continuación, debe especificar su directorio de trabajo. Todos los comandos posteriores en Dockerfile se ejecutarán en relación con este directorio.
Agregue el siguiente bloque de código a su Dockerfile para especificar su directorio de trabajo:
# Specify working directory
WORKDIR /app
Luego, debe copiar sus archivos package.json y package-lock.json del directorio actual (es decir, el directorio que contiene el Dockerfile) al directorio de trabajo (/app).
Agregue el siguiente bloque de código a su Dockerfile para copiar los archivos:
# Copy package.json and package-lock.json
COPY package*.json ./
A continuación, debe ejecutar el comando npm install en el directorio de trabajo para instalar las dependencias de Node.js enumeradas en package.json y package-lock.json.
Agregue el siguiente código a su Dockerfile para instalar las dependencias:
# Install dependencies
RUN npm install
El comando anterior instalará todas las dependencias enumeradas en sus archivos package.json **** y package-lock.json y las almacenará en la carpeta node_modules en el directorio de trabajo especificado.
A continuación, debe copiar el código fuente de su aplicación en su directorio de trabajo.
Agregue el siguiente bloque de código a su Dockerfile para copiar el código fuente:
# Copy source code
COPY . .
A continuación, debe exponer un puerto a la máquina host. Exponer un puerto permite que el contenedor Docker reciba conexiones de red entrantes en el puerto expuesto cuando lo ejecuta.
Agregue el siguiente bloque de código a su Dockerfile para exponer el puerto 3000 a la máquina host:
# Expose port 3000
EXPOSE 3000
Finalmente, debe especificar el comando que debe ejecutarse cuando se inicia el contenedor Docker. Normalmente, las aplicaciones Node.js se inician mediante el comando npm start.
Agregue el siguiente bloque de código a su Dockerfile para especificar el comando:
# Run the app
CMD ["npm", "start"]
Su Dockerfile terminado debería verse como el siguiente bloque de código:
# 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"]
Después de crear su Dockerfile, envíe su código a GitHub.
Creando una nueva aplicación Back4app
El primer paso para implementar una aplicación Node.js en Back4app es crear una cuenta en Back4app (si no tiene una). Puede crear una siguiendo los pasos a continuación.
- Navegue al sitio web de Back4app.
- A continuación, haga clic en el botón Registrarse en la esquina superior derecha de la página de destino.
- Finalmente, complete el formulario de registro y envíelo.
Después de crear con éxito su cuenta Back4app, inicie sesión en su cuenta Back4app y haga clic en el botón NUEVA APLICACIÓN en la esquina superior derecha.
Al hacer clic en este botón, accederá a una página donde podrá elegir “¿Cómo le gustaría crear su nueva aplicación?”. Dado que está implementando mediante contenedores, elija Contenedores como Servicio, como se muestra en la imagen a continuación.
Luego, conecte su cuenta de GitHub a su cuenta Back4app. Puede optar por darle acceso a Back4app a todos los repositorios de su cuenta o a repositorios específicos.
Elija la aplicación que desea implementar, en este caso, la aplicación que creó en este tutorial, y haga clic en Seleccionar.
Al hacer clic en el botón Seleccionar, accederá a una página donde se le pedirá que complete cierta información sobre su aplicación, como el nombre, la rama, el directorio raíz y las variables ambientales.
Asegúrese de completar todas las variables ambientales que su aplicación requiere para funcionar. Después de haber completado los detalles requeridos, haga clic en Crear aplicación, como se muestra en la imagen a continuación.
Al hacer clic en el botón Crear aplicación se inicia el proceso de implementación. Cuando se complete el proceso de implementación, se especificará una URL desde la cual se puede acceder a la aplicación implementada en la esquina izquierda de la pantalla, como se muestra en la imagen a continuación.
Si el proceso de implementación lleva mucho tiempo, puede consultar los registros para ver si se produjo un error con la implementación o consultar la guía de solución de problemas de Back4app.
Conclusión
Node.js es un marco popular que ofrece muchas ventajas, como su rápido rendimiento, escalabilidad y flexibilidad. Sin embargo, también tiene algunas limitaciones, como su naturaleza de un solo subproceso, lo que puede dificultar el manejo de cargas de trabajo pesadas.
A pesar de estas limitaciones, hay varias opciones de implementación disponibles para las aplicaciones Node.js, incluido Back4app, que proporciona una plataforma confiable y fácil de usar para alojar y administrar aplicaciones Node.js.
Al crear una aplicación Node.js y seguir los pasos descritos en este artículo, puede implementar fácilmente sus aplicaciones Node.js en Back4app y aprovechar sus numerosos beneficios.
¿Aún está interesado en la implementación y el alojamiento de Node.js? Por favor, consulte estos dos tutoriales: