Express
Tutorial Express: Servir archivos estáticos
Aprende a configurar express.static() para servir archivos estáticos en Node.js con rutas virtuales y opciones avanzadas.
Aprende Express y certifícateConfiguración express.static()
El middleware express.static() es la función integrada de Express que permite servir archivos estáticos directamente desde el servidor. Este middleware elimina la necesidad de crear rutas específicas para cada archivo estático, proporcionando una solución eficiente y automática para entregar recursos como CSS, JavaScript, imágenes y documentos.
Sintaxis básica
La configuración más simple de express.static() requiere únicamente especificar la carpeta que contiene los archivos estáticos:
const express = require('express');
const app = express();
// Configuración básica para servir archivos estáticos
app.use(express.static('public'));
app.listen(3000, () => {
console.log('Servidor ejecutándose en puerto 3000');
});
Con esta configuración, Express servirá automáticamente cualquier archivo ubicado en la carpeta public
. Si tienes un archivo public/styles.css
, estará disponible en http://localhost:3000/styles.css
.
Configuración con rutas virtuales
Express permite crear rutas virtuales que no corresponden directamente con la estructura de carpetas del sistema de archivos. Esto proporciona mayor flexibilidad en la organización de URLs:
// Crear una ruta virtual '/assets' para la carpeta 'public'
app.use('/assets', express.static('public'));
// Crear múltiples rutas virtuales
app.use('/css', express.static('public/stylesheets'));
app.use('/js', express.static('public/javascripts'));
app.use('/images', express.static('public/img'));
Con esta configuración, un archivo public/logo.png
estaría disponible en http://localhost:3000/assets/logo.png
, mientras que public/stylesheets/main.css
se accedería mediante http://localhost:3000/css/main.css
.
Opciones de configuración avanzada
El middleware express.static() acepta un objeto de opciones como segundo parámetro para personalizar su comportamiento:
const path = require('path');
// Configuración con opciones avanzadas
app.use('/static', express.static(path.join(__dirname, 'public'), {
dotfiles: 'ignore', // Ignorar archivos que empiecen con punto
etag: false, // Deshabilitar generación de ETags
extensions: ['htm', 'html'], // Extensiones a buscar automáticamente
index: ['index.html', 'default.html'], // Archivos índice por defecto
maxAge: '1d', // Tiempo de caché en el navegador
redirect: false, // No redirigir cuando la URL termina en '/'
setHeaders: function (res, path, stat) {
res.set('x-timestamp', Date.now());
}
}));
Múltiples directorios estáticos
Express permite configurar múltiples directorios estáticos que se evalúan en el orden de registro. Esto resulta útil para organizar diferentes tipos de recursos:
// Configurar múltiples directorios en orden de prioridad
app.use(express.static('public'));
app.use(express.static('assets'));
app.use(express.static('uploads'));
// Con rutas virtuales específicas
app.use('/vendor', express.static('node_modules'));
app.use('/uploads', express.static('user-uploads'));
Cuando Express recibe una solicitud de archivo estático, busca en cada directorio configurado hasta encontrar el archivo solicitado, siguiendo el orden de registro.
Configuración con rutas absolutas
Para evitar problemas de rutas relativas, especialmente en aplicaciones complejas, es recomendable usar rutas absolutas con el módulo path
:
const path = require('path');
// Usar rutas absolutas para mayor seguridad
app.use(express.static(path.join(__dirname, 'public')));
app.use('/uploads', express.static(path.join(__dirname, 'storage', 'uploads')));
// Configuración para diferentes entornos
const staticPath = process.env.NODE_ENV === 'production'
? path.join(__dirname, 'dist')
: path.join(__dirname, 'public');
app.use(express.static(staticPath));
Configuración condicional por entorno
En aplicaciones profesionales, la configuración de archivos estáticos suele variar según el entorno de ejecución:
// Configuración específica por entorno
if (process.env.NODE_ENV === 'development') {
// En desarrollo: sin caché, con logs detallados
app.use(express.static('public', {
maxAge: 0,
etag: false,
setHeaders: (res, path) => {
console.log(`Sirviendo archivo: ${path}`);
}
}));
} else {
// En producción: con caché optimizado
app.use(express.static('dist', {
maxAge: '30d',
etag: true,
immutable: true
}));
}
Esta configuración permite optimizar el rendimiento en producción mientras mantiene la flexibilidad necesaria durante el desarrollo.
Estructura de carpetas públicas
La organización de carpetas públicas en Express requiere una planificación cuidadosa para mantener el código escalable y facilitar el mantenimiento. Una estructura bien definida no solo mejora la experiencia del desarrollador, sino que también optimiza el rendimiento del servidor y la carga de recursos en el navegador.
Estructura básica recomendada
La estructura estándar para archivos estáticos en Express sigue convenciones establecidas que facilitan la navegación y el mantenimiento:
proyecto/
├── public/
│ ├── css/
│ │ ├── main.css
│ │ ├── components/
│ │ │ ├── navbar.css
│ │ │ └── footer.css
│ │ └── vendor/
│ │ └── bootstrap.min.css
│ ├── js/
│ │ ├── app.js
│ │ ├── modules/
│ │ │ ├── auth.js
│ │ │ └── utils.js
│ │ └── vendor/
│ │ └── jquery.min.js
│ ├── images/
│ │ ├── logo.png
│ │ ├── icons/
│ │ │ ├── favicon.ico
│ │ │ └── apple-touch-icon.png
│ │ └── gallery/
│ │ ├── thumb/
│ │ └── full/
│ ├── fonts/
│ │ ├── roboto-regular.woff2
│ │ └── icons.ttf
│ └── docs/
│ ├── manual.pdf
│ └── api-docs.html
Esta estructura separa claramente los diferentes tipos de recursos, facilitando tanto el desarrollo como el despliegue de la aplicación.
Organización por funcionalidad
Para aplicaciones más complejas, la organización por módulos o funcionalidades puede resultar más eficiente:
// Configuración modular de archivos estáticos
app.use('/admin', express.static(path.join(__dirname, 'public/admin')));
app.use('/client', express.static(path.join(__dirname, 'public/client')));
app.use('/shared', express.static(path.join(__dirname, 'public/shared')));
public/
├── admin/
│ ├── css/
│ │ └── dashboard.css
│ ├── js/
│ │ └── admin-panel.js
│ └── images/
│ └── admin-icons/
├── client/
│ ├── css/
│ │ └── storefront.css
│ ├── js/
│ │ └── shopping-cart.js
│ └── images/
│ └── products/
└── shared/
├── css/
│ └── common.css
├── js/
│ └── utilities.js
└── fonts/
Gestión de versiones de archivos
La versionado de archivos estáticos es crucial para el control de caché en navegadores. Express permite implementar diferentes estrategias:
// Estructura con versionado manual
app.use('/v1', express.static(path.join(__dirname, 'public/v1')));
app.use('/v2', express.static(path.join(__dirname, 'public/v2')));
// Estructura con hash en nombres de archivo
app.use(express.static(path.join(__dirname, 'dist'), {
setHeaders: (res, path) => {
// Archivos con hash tienen caché largo
if (path.match(/\.[a-f0-9]{8}\./)) {
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
}
}
}));
dist/
├── css/
│ ├── main.a1b2c3d4.css
│ └── vendor.e5f6g7h8.css
├── js/
│ ├── app.i9j0k1l2.js
│ └── chunk.m3n4o5p6.js
└── images/
├── logo.q7r8s9t0.png
└── sprite.u1v2w3x4.svg
Separación de entornos
La configuración por entornos permite optimizar la entrega de archivos según el contexto de ejecución:
const isDevelopment = process.env.NODE_ENV === 'development';
const isProduction = process.env.NODE_ENV === 'production';
if (isDevelopment) {
// Desarrollo: archivos sin procesar
app.use(express.static(path.join(__dirname, 'src/assets')));
app.use('/dev-tools', express.static(path.join(__dirname, 'dev')));
}
if (isProduction) {
// Producción: archivos optimizados
app.use(express.static(path.join(__dirname, 'build/static')));
}
// Archivos comunes a todos los entornos
app.use('/uploads', express.static(path.join(__dirname, 'storage/uploads')));
Organización de archivos subidos por usuarios
Los archivos generados dinámicamente requieren una estructura específica que facilite su gestión y seguridad:
storage/
├── uploads/
│ ├── avatars/
│ │ ├── 2024/
│ │ │ ├── 01/
│ │ │ └── 02/
│ │ └── thumbs/
│ ├── documents/
│ │ ├── public/
│ │ └── private/
│ └── temp/
│ └── processing/
// Configuración para archivos de usuario
app.use('/uploads/avatars', express.static(
path.join(__dirname, 'storage/uploads/avatars'),
{
maxAge: '7d',
setHeaders: (res, filePath) => {
// Validar que el archivo existe y es accesible
res.setHeader('X-Content-Type-Options', 'nosniff');
}
}
));
// Archivos temporales con acceso restringido
app.use('/temp', (req, res, next) => {
// Lógica de autorización aquí
if (!req.user || !req.user.canAccessTemp) {
return res.status(403).send('Acceso denegado');
}
next();
}, express.static(path.join(__dirname, 'storage/temp')));
Optimización de estructura para CDN
Cuando se utiliza un CDN (Content Delivery Network), la estructura debe facilitar la sincronización y distribución:
public/
├── cdn/
│ ├── css/
│ ├── js/
│ ├── images/
│ └── fonts/
├── local/
│ ├── templates/
│ └── config/
└── hybrid/
├── critical.css
└── above-fold.js
// Configuración híbrida CDN/local
const cdnEnabled = process.env.CDN_ENABLED === 'true';
if (!cdnEnabled) {
// Servir desde servidor local cuando CDN no está disponible
app.use('/cdn', express.static(path.join(__dirname, 'public/cdn')));
}
// Archivos que siempre se sirven localmente
app.use('/local', express.static(path.join(__dirname, 'public/local')));
app.use('/critical', express.static(path.join(__dirname, 'public/hybrid')));
Esta aproximación permite flexibilidad en el despliegue y garantiza que la aplicación funcione correctamente independientemente de la disponibilidad del CDN.
Otras lecciones de Express
Accede a todas las lecciones de Express y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Expressjs
Introducción Y Entorno
Instalación De Express
Introducción Y Entorno
Estados Http
Routing
Métodos Delete
Routing
Parámetros Y Query Strings
Routing
Métodos Get
Routing
Ejercicios de programación de Express
Evalúa tus conocimientos de esta lección Servir archivos estáticos con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.