Saltar al contenido principal

downloadFile

Paquete: @tiendana/utils

Descarga un archivo desde una URL programáticamente, creando un enlace temporal que simula un click del usuario. Útil para descargas automáticas o botones de descarga personalizados.

Características​

✅ Descarga desde cualquier URL
✅ Nombre de archivo personalizable
✅ Abre en nueva pestaña (target="_blank")
✅ Nombre automático desde URL si no se especifica
✅ Limpia el DOM después de la descarga
✅ Compatible con Blob URLs y URLs remotas

Firma​

function downloadFile(url: string, filename?: string | null): void

Parámetros​

ParámetroTipoDescripciónRequerido
urlstringURL del archivo a descargar✅
filenamestring | null | undefinedNombre del archivo descargado (con extensión)❌

Retorno​

Tipo: void

No retorna nada. Inicia la descarga automáticamente.

Ejemplos de Uso​

Descarga Básica​

import { downloadFile } from '@tiendana/utils';

downloadFile('https://example.com/document.pdf');
// Descarga como "document.pdf"

Con Nombre Personalizado​

downloadFile(
'https://example.com/file123.pdf',
'Mi_Documento_2024.pdf'
);
// Descarga como "Mi_Documento_2024.pdf"

Descargar Blob​

function downloadBlob() {
const blob = new Blob(['Hola Mundo'], { type: 'text/plain' });
const url = URL.createObjectURL(blob);

downloadFile(url, 'mensaje.txt');

// Cleanup después de un delay
setTimeout(() => URL.revokeObjectURL(url), 100);
}

Botón de Descarga​

function DownloadButton({ fileUrl, fileName }: { fileUrl: string; fileName: string }) {
const handleDownload = () => {
downloadFile(fileUrl, fileName);
};

return (
<button onClick={handleDownload}>
⬇️ Descargar {fileName}
</button>
);
}

Descargar CSV Generado​

function exportToCSV(data: any[]) {
const csvContent = data.map(row =>
Object.values(row).join(',')
).join('\n');

const blob = new Blob([csvContent], { type: 'text/csv' });
const url = URL.createObjectURL(blob);

downloadFile(url, 'data.csv');

setTimeout(() => URL.revokeObjectURL(url), 100);
}

Descargar JSON​

function downloadJSON(data: any, filename: string) {
const json = JSON.stringify(data, null, 2);
const blob = new Blob([json], { type: 'application/json' });
const url = URL.createObjectURL(blob);

downloadFile(url, filename);

setTimeout(() => URL.revokeObjectURL(url), 100);
}

// Uso
downloadJSON({ name: 'Juan', age: 30 }, 'user.json');

Descargar Imagen​

function DownloadImageButton({ imageUrl }: { imageUrl: string }) {
const handleDownload = () => {
downloadFile(imageUrl, 'imagen.jpg');
};

return <button onClick={handleDownload}>💾 Guardar imagen</button>;
}

Descargar Desde Canvas​

function downloadCanvasAsImage(canvas: HTMLCanvasElement) {
canvas.toBlob((blob) => {
if (blob) {
const url = URL.createObjectURL(blob);
downloadFile(url, 'canvas-image.png');
setTimeout(() => URL.revokeObjectURL(url), 100);
}
});
}

Descargar Reporte​

interface Report {
title: string;
content: string;
date: Date;
}

function DownloadReportButton({ report }: { report: Report }) {
const handleDownload = () => {
const content = `
Reporte: ${report.title}
Fecha: ${report.date.toLocaleDateString()}

${report.content}
`;

const blob = new Blob([content], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const filename = `${report.title.replace(/\s+/g, '_')}.txt`;

downloadFile(url, filename);

setTimeout(() => URL.revokeObjectURL(url), 100);
};

return <button onClick={handleDownload}>📥 Descargar reporte</button>;
}

Descargar Excel (Blob)​

async function downloadExcel() {
const response = await fetch('https://api.example.com/export/excel');
const blob = await response.blob();
const url = URL.createObjectURL(blob);

downloadFile(url, 'reporte.xlsx');

setTimeout(() => URL.revokeObjectURL(url), 100);
}

Descargar ZIP​

async function downloadZipFile(fileId: string) {
const response = await fetch(`/api/files/${fileId}/download`);
const blob = await response.blob();
const url = URL.createObjectURL(blob);

downloadFile(url, `archive_${fileId}.zip`);

setTimeout(() => URL.revokeObjectURL(url), 100);
}

Casos de Uso Comunes​

  • Descargar archivos: PDFs, imágenes, documentos
  • Exportar datos: CSV, JSON, Excel
  • Guardar reportes: Reportes generados dinámicamente
  • Descargar imágenes: Desde canvas, URLs remotas
  • Backup de datos: Exportar configuraciones, backups
  • Descargar archivos generados: Facturas, tickets, certificados
  • Guardar recursos: Videos, audio, archivos multimedia

Nombre de Archivo​

Nombre Automático​

Si no se proporciona filename, se extrae el nombre del último segmento de la URL:

downloadFile('https://example.com/docs/report.pdf');
// Descarga como "report.pdf"

downloadFile('https://example.com/files/123/download');
// Descarga como "download"

URL sin Último Segmento​

El nombre se calcula con url.split('/').pop() ?? 'file'. El valor 'file' solo se usa si pop() devuelve undefined, algo que no ocurre con una URL normal. Si la URL termina en /, el segmento es un string vacío y el atributo download queda vacío, así que el navegador decide el nombre:

downloadFile('https://example.com/');
// download="" → el navegador elige el nombre

Nombre Personalizado​

Es recomendable siempre proporcionar un nombre personalizado para mejor UX:

downloadFile(url, 'Mi_Reporte_2024.pdf');
// ✅ Mejor experiencia de usuario

Funcionamiento Interno​

La función:

  1. Crea un elemento <a> temporal
  2. Establece target="_blank" para abrir en nueva pestaña
  3. Establece href con la URL del archivo
  4. Establece atributo download con el nombre del archivo
  5. Añade el elemento al DOM
  6. Simula un click en el elemento
  7. Remueve el elemento del DOM
const link = document.createElement('a');
link.setAttribute('target', '_blank');
link.setAttribute('href', url);
link.setAttribute('download', filename);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);

Notas Técnicas​

  • CORS: Para URLs remotas, el servidor debe permitir CORS
  • Blob URLs: Debe llamar a URL.revokeObjectURL() después de la descarga
  • Same-origin: Funciona mejor con archivos del mismo dominio
  • Navegador: El navegador puede mostrar un diálogo de descarga
  • Extensión: Asegúrate de incluir la extensión en el filename
  • DOM cleanup: La función limpia automáticamente el elemento <a> creado

Limitaciones​

CORS para URLs remotas

Para descargar archivos de dominios externos, el servidor debe tener CORS habilitado:

// ❌ Puede fallar si el servidor no tiene CORS
downloadFile('https://external-site.com/file.pdf');

// ✅ Funciona con mismo dominio
downloadFile('/files/document.pdf');

// ✅ Funciona con Blob URLs
const blob = new Blob([data]);
const url = URL.createObjectURL(blob);
downloadFile(url, 'file.pdf');

Para archivos externos sin CORS, considera usar un proxy en tu servidor.

Blob URL Memory Leak

Cuando usas URL.createObjectURL(), debes liberar la memoria manualmente:

const url = URL.createObjectURL(blob);
downloadFile(url, 'file.pdf');

// ⚠️ IMPORTANTE: Liberar memoria después de la descarga
setTimeout(() => {
URL.revokeObjectURL(url);
}, 100);

El timeout es necesario para dar tiempo a que la descarga inicie.

Navegadores pueden bloquear descargas automáticas

Algunos navegadores pueden bloquear descargas que no son iniciadas directamente por un click del usuario. Asegúrate de llamar a downloadFile() dentro de un event handler de click:

// ✅ Funciona - iniciado por click
<button onClick={() => downloadFile(url)}>Descargar</button>

// ❌ Puede ser bloqueado
useEffect(() => {
downloadFile(url); // No iniciado por usuario
}, []);

Browser Support​

NavegadorVersiónNotas
ChromeTodosSoporte completo
FirefoxTodosSoporte completo
Safari10.1+Atributo download soportado
EdgeTodosSoporte completo
OperaTodosSoporte completo

Safari < 10.1​

En versiones antiguas de Safari, el atributo download no funciona. El archivo se abrirá en lugar de descargarse.

Ver También​