Este manual cubre desde los fundamentos de JavaScript hasta conceptos avanzados, con ejemplos prácticos aplicables en entornos laborales y en sistemas Linux.
JavaScript es un lenguaje de programación interpretado, orientado a objetos y multiplataforma. A diferencia de lo que su nombre podría sugerir, no tiene relación directa con Java.
JavaScript puede ejecutarse en diferentes entornos:
rhino
o node
Instalar Node.js en Linux (Debian/Ubuntu):
Crear un archivo JavaScript:
// hola.js
const mensaje = "Hola desde Linux!";
console.log(mensaje);
Ejecutar el script:
// Variables (pueden cambiar)
let nombre = "Carlos";
nombre = "Juan"; // Correcto
// Constantes (no pueden cambiar)
const PI = 3.1416;
// PI = 3.14; // Error!
Nota: Evita usar var
en código moderno. Prefiere let
y const
por su mejor manejo de scope.
Tipo | Descripción | Ejemplo |
---|---|---|
String | Cadena de texto | "Hola mundo" |
Number | Números (enteros o decimales) | 42 , 3.14 |
Boolean | Verdadero o falso | true , false |
Array | Colección ordenada | [1, 2, 3] |
Object | Colección de pares clave-valor | {nombre: "Juan", edad: 30} |
Null | Valor nulo intencional | null |
Undefined | Variable no definida | undefined |
// Aritméticos
let suma = 5 + 3; // 8
let modulo = 10 % 3; // 1
// Comparación
let igual = 5 == '5'; // true (solo valor)
let estrictamenteIgual = 5 === '5'; // false (valor y tipo)
// Lógicos
let and = true && false; // false
let or = true || false; // true
let not = !true; // false
// if-else
let edad = 18;
if (edad >= 18) {
console.log("Eres mayor de edad");
} else {
console.log("Eres menor de edad");
}
// switch
let dia = "Lunes";
switch (dia) {
case "Lunes":
console.log("Inicio de semana");
break;
case "Viernes":
console.log("¡Fin de semana cerca!");
break;
default:
console.log("Día laboral");
}
// for
for (let i = 0; i < 5; i++) {
console.log("Iteración:", i);
}
// while
let contador = 0;
while (contador < 3) {
console.log("Contador:", contador);
contador++;
}
// for...of (para arrays)
const frutas = ["manzana", "banana", "naranja"];
for (const fruta of frutas) {
console.log(fruta);
}
// Función tradicional
function saludar(nombre) {
return `Hola, ${nombre}`;
}
// Función flecha (arrow function)
const sumar = (a, b) => a + b;
// Ejemplo práctico: procesar archivos en Linux
const procesarArchivos = (directorio, extension) => {
// Simulación: en un entorno real usaríamos el módulo 'fs' de Node.js
const archivos = [
"documento.txt",
"imagen.jpg",
"reporte.pdf",
"config.json"
];
return archivos.filter(archivo => archivo.endsWith(extension));
};
// Uso en terminal Linux
const archivosJson = procesarArchivos("./", ".json");
console.log("Archivos JSON:", archivosJson);
// Parámetros por defecto
function crearUsuario(nombre, rol = "usuario") {
return { nombre, rol };
}
// Argumentos variables (rest parameters)
function sumarNumeros(...numeros) {
return numeros.reduce((total, num) => total + num, 0);
}
// Ejemplo laboral: calcular total de ventas
const totalVentas = sumarNumeros(1200, 850, 430, 920);
console.log("Total de ventas:", totalVentas);
const empleados = [
{ id: 1, nombre: "Ana", departamento: "Ventas", salario: 3200 },
{ id: 2, nombre: "Luis", departamento: "TI", salario: 3800 },
{ id: 3, nombre: "Marta", departamento: "Marketing", salario: 3500 },
{ id: 4, nombre: "Carlos", departamento: "Ventas", salario: 3100 }
];
// filter: filtrar empleados de ventas
const ventas = empleados.filter(emp => emp.departamento === "Ventas");
// map: crear array solo con nombres
const nombres = empleados.map(emp => emp.nombre);
// reduce: calcular nómina total
const nominaTotal = empleados.reduce((total, emp) => total + emp.salario, 0);
// sort: ordenar por salario (descendente)
const empleadosOrdenados = [...empleados].sort((a, b) => b.salario - a.salario);
// find: buscar empleado por ID
const empleado = empleados.find(emp => emp.id === 2);
// Creación de objetos
const servidor = {
hostname: "web01",
ip: "192.168.1.100",
os: "Ubuntu 20.04",
servicios: ["nginx", "mysql", "node"],
verificarEstado() {
// Simulación: en un entorno real podríamos ejecutar comandos SSH
return `Servidor ${this.hostname} operativo`;
}
};
// Acceder a propiedades
console.log(servidor.ip); // 192.168.1.100
console.log(servidor['os']); // Ubuntu 20.04
// Añadir nueva propiedad
servidor.ubicacion = "Centro de datos #2";
// Eliminar propiedad
delete servidor.servicios;
// Método del objeto
console.log(servidor.verificarEstado());
// Ejemplo: simular lectura de archivo en Linux
const leerArchivo = (ruta, callback) => {
// Simulamos un retraso de lectura
setTimeout(() => {
const contenido = `Contenido del archivo ${ruta}`;
const error = null; // En caso de error, aquí iría el objeto error
callback(error, contenido);
}, 1000);
};
// Uso del callback
leerArchivo("/var/log/syslog", (err, data) => {
if (err) {
console.error("Error:", err);
return;
}
console.log("Contenido:", data);
});
// Ejemplo laboral: verificar conectividad a servidores
const verificarServidor = (servidor) => {
return new Promise((resolve, reject) => {
// Simulamos una verificación de red con tiempo variable
const tiempoRespuesta = Math.random() * 2000;
const exito = tiempoRespuesta < 1500; // 75% de probabilidad de éxito
setTimeout(() => {
if (exito) {
resolve({
servidor,
estado: "online",
tiempoRespuesta: tiempoRespuesta.toFixed(2)
});
} else {
reject(new Error(`Timeout en servidor ${servidor}`));
}
}, tiempoRespuesta);
});
};
// Uso de la promesa
verificarServidor("web01.example.com")
.then(resultado => {
console.log("Estado:", resultado.estado);
console.log("Tiempo de respuesta:", resultado.tiempoRespuesta, "ms");
})
.catch(error => {
console.error("Error:", error.message);
});
// Ejemplo avanzado: monitoreo de servidores
const servidores = ["web01", "db01", "app01", "cache01"];
async function monitorearServidores() {
try {
// Usamos Promise.all para ejecutar verificaciones en paralelo
const resultados = await Promise.all(
servidores.map(servidor => verificarServidor(servidor))
);
console.log("=== Reporte de estado ===");
resultados.forEach(({ servidor, estado, tiempoRespuesta }) => {
console.log(
`${servidor.padEnd(8)} | ${estado.padEnd(6)} | ${tiempoRespuesta.padStart(6)} ms`
);
});
const todosOnline = resultados.every(r => r.estado === "online");
return todosOnline ? "Todos los servidores operativos" : "Problemas detectados";
} catch (error) {
console.error("Error en el monitoreo:", error);
return "Fallo en el monitoreo";
}
}
// Ejecutar la función asíncrona
monitorearServidores().then(resumen => console.log(resumen));
// config.js - Módulo que exporta configuración
const config = {
entorno: process.env.NODE_ENV || "development",
servidor: {
host: "0.0.0.0",
port: 3000
},
db: {
host: "localhost",
nombre: "app_db"
}
};
export default config;
// logger.js - Módulo con exportaciones nombradas
const logInfo = (mensaje) => {
console.log(`[INFO] ${new Date().toISOString()} - ${mensaje}`);
};
const logError = (mensaje) => {
console.error(`[ERROR] ${new Date().toISOString()} - ${mensaje}`);
};
export { logInfo, logError };
// app.js - Módulo que importa otros módulos
import config from './config.js';
import { logInfo, logError } from './logger.js';
logInfo(`Iniciando aplicación en entorno ${config.entorno}`);
logInfo(`Servidor escuchando en ${config.servidor.host}:${config.servidor.port}`);
// Ejemplo práctico: script de backup en Linux
// backup.js
const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');
const crearBackup = (directorioOrigen, directorioDestino) => {
const fecha = new Date().toISOString().replace(/[:.]/g, '-');
const nombreArchivo = `backup-${fecha}.tar.gz`;
const rutaCompleta = path.join(directorioDestino, nombreArchivo);
return new Promise((resolve, reject) => {
const comando = `tar -czf ${rutaCompleta} -C ${directorioOrigen} .`;
exec(comando, (error, stdout, stderr) => {
if (error) {
reject(new Error(`Error al crear backup: ${stderr}`));
return;
}
resolve({
mensaje: "Backup creado exitosamente",
archivo: nombreArchivo,
ruta: rutaCompleta,
tamaño: fs.statSync(rutaCompleta).size()
});
});
});
};
// Exportamos la función para que pueda ser usada por otros módulos
module.exports = { crearBackup };
// Uso en terminal Linux:
// node -e "const { crearBackup } = require('./backup'); crearBackup('/var/www', '/backups').then(console.log).catch(console.error);"
async function procesarDatos(datos) {
try {
// Validación de entrada
if (!datos || !Array.isArray(datos)) {
throw new Error("Datos de entrada no válidos");
}
// Procesamiento que podría fallar
const resultado = datos.map(item => {
if (!item.id) {
throw new Error("Item sin ID");
}
return { ...item, procesado: true };
});
return resultado;
} catch (error) {
console.error("Error en procesarDatos:", error.message);
// Podemos lanzar un error personalizado
throw new Error(`Fallo en el procesamiento: ${error.message}`);
}
}
// Uso con manejo de errores
async function ejecutarProcesamiento() {
try {
const datos = [{ id: 1 }, { id: 2 }, {}]; // Datos con error
const resultado = await procesarDatos(datos);
console.log(resultado);
} catch (error) {
console.error("Error en ejecutarProcesamiento:", error.message);
// En una aplicación real, podríamos registrar el error en un sistema de monitoreo
}
}
ejecutarProcesamiento();
// Clase de error personalizado para la aplicación
class AppError extends Error {
constructor(mensaje, codigo = "APP_ERROR", detalles = {}) {
super(mensaje);
this.name = "AppError";
this.codigo = codigo;
this.detalles = detalles;
this.fecha = new Date();
}
toJSON() {
return {
error: this.name,
codigo: this.codigo,
mensaje: this.message,
detalles: this.detalles,
fecha: this.fecha.toISOString()
};
}
}
// Ejemplo de uso en una API
function obtenerUsuario(id) {
if (!id) {
throw new AppError("ID de usuario requerido", "VALIDATION_ERROR", {
campo: "id",
tipo: "requerido"
});
}
// Simulamos que el usuario no existe
throw new AppError("Usuario no encontrado", "NOT_FOUND", { id });
}
// Manejo del error
try {
obtenerUsuario();
} catch (error) {
if (error instanceof AppError) {
console.error("Error de aplicación:", error.toJSON());
} else {
console.error("Error inesperado:", error);
}
}
// Ejemplo avanzado: procesamiento de logs en Linux
const fs = require('fs').promises;
const path = require('path');
async function analizarLogs(rutaLog) {
try {
// Verificar si el archivo existe
try {
await fs.access(rutaLog);
} catch {
throw new Error(`Archivo de log no encontrado: ${rutaLog}`);
}
// Leer el archivo
const datos = await fs.readFile(rutaLog, 'utf-8');
// Procesar las líneas
const lineas = datos.split('\n').filter(linea => linea.trim() !== '');
// Analizar tipos de mensajes
const resumen = {
total: lineas.length,
errores: lineas.filter(linea => linea.includes('ERROR')).length,
advertencias: lineas.filter(linea => linea.includes('WARN')).length,
informativos: lineas.filter(linea => linea.includes('INFO')).length
};
// Generar reporte
const nombreReporte = `reporte-${path.basename(rutaLog)}.json`;
const rutaReporte = path.join(path.dirname(rutaLog), nombreReporte);
await fs.writeFile(rutaReporte, JSON.stringify(resumen, null, 2));
return {
archivoLog: rutaLog,
archivoReporte: rutaReporte,
resumen
};
} catch (error) {
console.error("Error al analizar logs:", error.message);
throw error; // Re-lanzamos el error para que lo maneje el llamador
}
}
// Uso en terminal Linux:
// node -e "const { analizarLogs } = require('./analizador'); analizarLogs('/var/log/apache2/error.log').then(console.log).catch(console.error);"
// Ejemplo: monitorear cambios en un directorio de configuración
const fs = require('fs');
const path = require('path');
class ConfigWatcher {
constructor(directorio) {
this.directorio = directorio;
this.archivos = new Map();
this.watchers = new Map();
this.iniciar();
}
iniciar() {
console.log(`Monitoreando directorio: ${this.directorio}`);
// Leer directorio inicial
fs.readdir(this.directorio, (err, archivos) => {
if (err) {
console.error("Error al leer directorio:", err);
return;
}
archivos.forEach(archivo => {
this.agregarArchivo(archivo);
});
});
// Configurar watcher para el directorio
this.dirWatcher = fs.watch(this.directorio, (eventType, filename) => {
if (filename) {
if (eventType === 'rename') {
// Verificar si el archivo fue creado o eliminado
fs.stat(path.join(this.directorio, filename), (err, stats) => {
if (err) {
// Archivo eliminado
this.eliminarArchivo(filename);
} else {
// Archivo creado
this.agregarArchivo(filename);
}
});
}
}
});
}
agregarArchivo(nombreArchivo) {
const rutaCompleta = path.join(this.directorio, nombreArchivo);
// Solo monitorear archivos (no directorios) con extensión .conf
if (!nombreArchivo.endsWith('.conf')) return;
// Obtener contenido inicial
fs.readFile(rutaCompleta, 'utf8', (err, contenido) => {
if (err) {
console.error(`Error al leer ${nombreArchivo}:`, err);
return;
}
this.archivos.set(nombreArchivo, contenido);
console.log(`Archivo agregado: ${nombreArchivo}`);
// Configurar watcher para este archivo
const watcher = fs.watch(rutaCompleta, (eventType) => {
if (eventType === 'change') {
fs.readFile(rutaCompleta, 'utf8', (err, nuevoContenido) => {
if (err) {
console.error(`Error al leer cambios en ${nombreArchivo}:`, err);
return;
}
const contenidoAnterior = this.archivos.get(nombreArchivo);
if (contenidoAnterior !== nuevoContenido) {
console.log(`Archivo modificado: ${nombreArchivo}`);
this.archivos.set(nombreArchivo, nuevoContenido);
this.emitirEvento('cambio', nombreArchivo, nuevoContenido);
}
});
}
});
this.watchers.set(nombreArchivo, watcher);
});
}
eliminarArchivo(nombreArchivo) {
if (this.archivos.has(nombreArchivo)) {
const watcher = this.watchers.get(nombreArchivo);
if (watcher) watcher.close();
this.archivos.delete(nombreArchivo);
this.watchers.delete(nombreArchivo);
console.log(`Archivo eliminado: ${nombreArchivo}`);
this.emitirEvento('eliminado', nombreArchivo);
}
}
emitirEvento(evento, ...args) {
// En una implementación real, usaríamos EventEmitter
console.log(`Evento: ${evento}`, args);
}
detener() {
this.watchers.forEach(watcher => watcher.close());
if (this.dirWatcher) this.dirWatcher.close();
console.log("Monitoreo detenido");
}
}
// Uso en producción:
// const watcher = new ConfigWatcher('/etc/nginx/conf.d');
// Para detener: watcher.detener();
/*
Estructura recomendada para un proyecto Node.js:
mi-proyecto/
├── src/
│ ├── controllers/ # Controladores de la aplicación
│ ├── models/ # Modelos de datos
│ ├── services/ # Lógica de negocio
│ ├── routes/ # Definición de rutas
│ ├── middlewares/ # Middlewares
│ ├── utils/ # Utilidades compartidas
│ ├── config/ # Configuración
│ └── app.js # Punto de entrada
├── tests/ # Pruebas
├── scripts/ # Scripts utilitarios (ej: despliegue, migraciones)
├── .env # Variables de entorno (no versionado)
├── package.json
└── README.md
*/
// Ejemplo de archivo app.js estructurado
const express = require('express');
const config = require('./config');
const logger = require('./utils/logger');
// Inicialización
const app = express();
// Middlewares
app.use(express.json());
app.use(require('./middlewares/requestLogger'));
// Rutas
app.use('/api', require('./routes/api'));
// Manejo de errores
app.use(require('./middlewares/errorHandler'));
// Iniciar servidor
app.listen(config.PORT, () => {
logger.info(`Servidor escuchando en puerto ${config.PORT}`);
});
// Patrón Factory: creación de objetos complejos
class Logger {
constructor(tipo = 'console') {
this.tipo = tipo;
}
log(mensaje) {
throw new Error('Método log debe ser implementado');
}
}
class ConsoleLogger extends Logger {
log(mensaje) {
console.log(`[CONSOLE] ${mensaje}`);
}
}
class FileLogger extends Logger {
constructor() {
super('file');
this.fs = require('fs');
this.path = './logs.txt';
}
log(mensaje) {
this.fs.appendFileSync(
this.path,
`[FILE] ${new Date().toISOString()} - ${mensaje}\n`
);
}
}
// Factory function
function crearLogger(tipo) {
switch (tipo) {
case 'console':
return new ConsoleLogger();
case 'file':
return new FileLogger();
default:
throw new Error(`Tipo de logger desconocido: ${tipo}`);
}
}
// Uso en producción
const logger = crearLogger(process.env.LOGGER_TYPE || 'console');
logger.log("Este es un mensaje de prueba");
// Instalación en Linux:
// npm install --save-dev jest
// Ejemplo: pruebas para una función de utilidad
// stringUtils.js
function capitalizar(str) {
if (typeof str !== 'string') {
throw new Error('Se esperaba una cadena de texto');
}
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
}
function formatearNombreCompleto(nombre, apellido) {
if (!nombre || !apellido) {
throw new Error('Nombre y apellido son requeridos');
}
return `${capitalizar(nombre)} ${capitalizar(apellido)}`;
}
module.exports = { capitalizar, formatearNombreCompleto };
// stringUtils.test.js
const { capitalizar, formatearNombreCompleto } = require('./stringUtils');
describe('capitalizar', () => {
test('capitaliza correctamente una cadena', () => {
expect(capitalizar('hola')).toBe('Hola');
expect(capitalizar('MUNDO')).toBe('Mundo');
});
test('lanza error con entrada no string', () => {
expect(() => capitalizar(123)).toThrow('Se esperaba una cadena de texto');
});
});
describe('formatearNombreCompleto', () => {
test('formatea correctamente nombre y apellido', () => {
expect(formatearNombreCompleto('juan', 'perez')).toBe('Juan Perez');
expect(formatearNombreCompleto('MARIA', 'GOMEZ')).toBe('Maria Gomez');
});
test('lanza error con parámetros faltantes', () => {
expect(() => formatearNombreCompleto('Juan')).toThrow('Nombre y apellido son requeridos');
expect(() => formatearNombreCompleto()).toThrow();
});
});
// Ejecutar pruebas:
// npx jest
// Ejemplo de código para depurar
function procesarDatos(datos) {
// Punto de ruptura (breakpoint) se puede agregar aquí
const resultado = datos
.map(item => {
if (!item.id) {
console.warn('Item sin ID:', item);
return null;
}
return { ...item, procesado: true };
})
.filter(item => item !== null);
return resultado;
}
// Métodos para depurar:
// 1. Usando 'debugger' en el código
// 2. Ejecutando Node.js en modo inspect:
// node --inspect-brk script.js
// (luego conectar con Chrome DevTools en chrome://inspect)
// 3. Usando el inspector integrado en VS Code
// Ejemplo de datos para probar
const datos = [
{ id: 1, valor: "A" },
{ valor: "B" }, // Sin ID
{ id: 2, valor: "C" }
];
// Ejecutar la función
const resultado = procesarDatos(datos);
console.log(resultado);
Importante: La seguridad es crítica en aplicaciones JavaScript, especialmente del lado del servidor.
// Ejemplo: validación y sanitización de entrada
const validator = require('validator');
const xss = require('xss');
function validarYSanitizarUsuario(datosUsuario) {
const errores = [];
const usuarioSanitizado = {};
// Validar y sanitizar nombre
if (!datosUsuario.nombre || !validator.isLength(datosUsuario.nombre, { min: 2, max: 50 })) {
errores.push('Nombre debe tener entre 2 y 50 caracteres');
} else {
usuarioSanitizado.nombre = xss(datosUsuario.nombre.trim());
}
// Validar y sanitizar email
if (!validator.isEmail(datosUsuario.email)) {
errores.push('Email no válido');
} else {
usuarioSanitizado.email = validator.normalizeEmail(datosUsuario.email);
}
// Validar y sanitizar contraseña
if (!validator.isStrongPassword(datosUsuario.password, {
minLength: 8,
minLowercase: 1,
minUppercase: 1,
minNumbers: 1,
minSymbols: 1
})) {
errores.push('La contraseña debe tener al menos 8 caracteres, incluyendo mayúsculas, minúsculas, números y símbolos');
} else {
// Nunca guardes contraseñas en texto plano en logs o respuestas
usuarioSanitizado.password = '***'; // En realidad, aquí debería ir el hash
}
if (errores.length > 0) {
throw new Error(`Errores de validación: ${errores.join(', ')}`);
}
return usuarioSanitizado;
}
// Uso:
try {
const usuario = {
nombre: '<script>alert("xss")</script> Juan',
email: ' JUAN@Example.COM ',
password: 'Passw0rd!'
};
const usuarioSanitizado = validarYSanitizarUsuario(usuario);
console.log('Usuario sanitizado:', usuarioSanitizado);
} catch (error) {
console.error(error.message);
}
// Ejemplo: configuración segura para una aplicación Node.js en producción
// config/security.js
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
// Configuración de Helmet (seguridad HTTP)
const helmetConfig = helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'", "cdn.example.com"],
styleSrc: ["'self'", "'unsafe-inline'", "fonts.googleapis.com"],
imgSrc: ["'self'", "data:", "cdn.example.com"],
connectSrc: ["'self'", "api.example.com"]
}
},
hsts: {
maxAge: 31536000, // 1 año en segundos
includeSubDomains: true,
preload: true
},
referrerPolicy: { policy: 'same-origin' }
});
// Limitador de tasa para prevenir ataques de fuerza bruta
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutos
max: 100, // límite de 100 peticiones por IP
message: 'Demasiadas peticiones desde esta IP, por favor intenta de nuevo más tarde'
});
// Configuración de CORS segura
const corsOptions = {
origin: process.env.ALLOWED_ORIGINS ? process.env.ALLOWED_ORIGINS.split(',') : [],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
optionsSuccessStatus: 200
};
module.exports = { helmetConfig, limiter, corsOptions };
// Uso en app.js:
// app.use(security.helmetConfig);
// app.use('/api/', security.limiter);
// app.use(cors(security.corsOptions));
// Configuración recomendada en Linux:
// 1. Ejecutar Node.js como usuario no root
// 2. Usar un proxy inverso como Nginx
// 3. Configurar firewall adecuadamente
// 4. Mantener el sistema y las dependencias actualizadas
// Ejemplo: configuración de entorno
// config.js
const requireEnv = (name) => {
if (!process.env[name]) {
throw new Error(`Variable de entorno requerida: ${name}`);
}
return process.env[name];
};
module.exports = {
entorno: process.env.NODE_ENV || 'development',
servidor: {
host: process.env.HOST || '0.0.0.0',
port: parseInt(process.env.PORT || '3000', 10)
},
db: {
host: requireEnv('DB_HOST'),
puerto: requireEnv('DB_PORT'),
nombre: requireEnv('DB_NAME'),
usuario: requireEnv('DB_USER'),
password: requireEnv('DB_PASSWORD')
},
jwt: {
secreto: requireEnv('JWT_SECRET'),
expiracion: '7d'
}
};
// Ejemplo de .env (no versionado)
/*
NODE_ENV=production
HOST=0.0.0.0
PORT=3000
DB_HOST=localhost
DB_PORT=5432
DB_NAME=mi_app_prod
DB_USER=mi_app_user
DB_PASSWORD=contraseñaSegura123!
JWT_SECRET=miSuperSecretoMuySeguro
*/
// Archivo de configuración de PM2 (ecosystem.config.js)
module.exports = {
apps: [{
name: 'mi-aplicacion',
script: './src/app.js',
instances: 'max', // Usar todos los núcleos CPU
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'development'
},
env_production: {
NODE_ENV: 'production',
PORT: 3000
}
}]
};
// Comandos útiles de PM2:
// Iniciar aplicación en producción:
// pm2 start ecosystem.config.js --env production
// Monitorear aplicaciones:
// pm2 monit
// Listar aplicaciones:
// pm2 list
// Ver logs:
// pm2 logs
// Reiniciar aplicación:
// pm2 restart mi-aplicacion
// Detener aplicación:
// pm2 stop mi-aplicacion
// Configurar inicio automático en Linux:
// pm2 startup
// pm2 save
Este manual cubre los conceptos fundamentales y avanzados de JavaScript con un enfoque práctico para entornos laborales y Linux. Para profundizar en cada tema, se recomienda consultar la documentación oficial y practicar con proyectos reales.