Frontend Guide.es - jjaroztegi/BuildingSignalSimulator GitHub Wiki
El frontend del Simulador de Distribución de Señal está construido utilizando HTML, JavaScript (ES6) y Tailwind CSS. Esta guía proporciona información detallada sobre la estructura del frontend, sus componentes y cómo trabajar con ellos.
webapp/
├── index.html # Página principal
├── css/
│ └── tailwind.css # Estilos de Tailwind
├── js/
│ ├── script.js # Punto de entrada JavaScript
│ └── modules/ # Módulos JavaScript
│ ├── servlet.js # Comunicación con API
│ ├── ui.js # Componentes de UI
│ ├── forms.js # Manejo de formularios
│ ├── tabs.js # Sistema de pestañas
│ ├── theme.js # Gestión de tema
│ └── utils.js # Utilidades
└── assets/ # Imágenes y otros recursos
El sistema de pestañas permite una navegación fluida entre diferentes secciones de la aplicación:
// Ejemplo de uso del sistema de pestañas
import { initTabs } from './modules/tabs.js';
const tabs = initTabs({
container: '#tabContainer',
onChange: (tabId) => {
// Lógica de cambio de pestaña
}
});
Los formularios utilizan validación del lado del cliente y manejo de envío asíncrono:
// Ejemplo de manejo de formulario
import { initForm } from './modules/forms.js';
const configForm = initForm('#configForm', {
onSubmit: async (data) => {
// Envío de datos al servidor
},
validate: (data) => {
// Validación de datos
}
});
Todas las llamadas API se manejan a través del módulo servlet.js
:
// Ejemplo de llamada API
import { api } from './modules/servlet.js';
const getComponents = async () => {
try {
const components = await api.get('/components');
return components;
} catch (error) {
console.error('Error al obtener componentes:', error);
}
};
El estado local se maneja utilizando clases y módulos JavaScript:
// Ejemplo de gestión de estado local
class ConfigurationState {
constructor() {
this.currentConfig = null;
this.components = [];
this.subscribers = new Set();
}
update(newState) {
Object.assign(this, newState);
this.notify();
}
subscribe(callback) {
this.subscribers.add(callback);
}
notify() {
this.subscribers.forEach(callback => callback(this));
}
}
Los datos persistentes se almacenan en localStorage:
// Ejemplo de persistencia
const saveConfiguration = (config) => {
localStorage.setItem('currentConfig', JSON.stringify(config));
};
const loadConfiguration = () => {
return JSON.parse(localStorage.getItem('currentConfig'));
};
El modo oscuro se implementa utilizando clases de Tailwind y el módulo theme.js
:
// Ejemplo de cambio de tema
import { toggleTheme } from './modules/theme.js';
const themeToggle = document.querySelector('#themeToggle');
themeToggle.addEventListener('click', () => {
toggleTheme();
});
Ejemplos de clases comunes utilizadas:
<!-- Ejemplo de componente con Tailwind -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-4">
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
Configuración
</h2>
<div class="mt-4 space-y-4">
<!-- Contenido -->
</div>
</div>
Los errores de API se manejan de manera consistente:
// Ejemplo de manejo de errores
import { handleApiError } from './modules/utils.js';
try {
await api.post('/configurations', data);
} catch (error) {
handleApiError(error, {
400: 'Datos de configuración inválidos',
500: 'Error del servidor'
});
}
Implementación de notificaciones y mensajes de error:
// Ejemplo de notificación
import { showNotification } from './modules/ui.js';
showNotification({
message: 'Configuración guardada exitosamente',
type: 'success',
duration: 3000
});
Implementación de carga diferida para módulos grandes:
// Ejemplo de carga diferida
const loadCalculationModule = async () => {
const { calculate } = await import('./modules/calculation.js');
return calculate;
};
Implementación de caché para recursos frecuentes:
// Ejemplo de caché
const componentCache = new Map();
const getComponent = async (id) => {
if (componentCache.has(id)) {
return componentCache.get(id);
}
const component = await api.get(`/components/${id}`);
componentCache.set(id, component);
return component;
};
- Usar ES6+ features
- Preferir
const
sobrelet
- Usar async/await para código asíncrono
- Documentar funciones complejas
- Usar elementos semánticos
- Mantener accesibilidad
- Seguir BEM para clases personalizadas
- Usar utilidades de Tailwind
- Minimizar CSS personalizado
- Mantener consistencia en espaciado
Ejemplo de prueba unitaria:
// Ejemplo de prueba
import { validateConfig } from './modules/validation.js';
describe('validateConfig', () => {
test('debería validar una configuración correcta', () => {
const config = {
name: 'Test Config',
components: []
};
expect(validateConfig(config)).toBe(true);
});
});
Ejemplo de prueba de integración:
// Ejemplo de prueba de integración
describe('Flujo de configuración', () => {
test('debería crear y guardar una configuración', async () => {
await page.click('#newConfig');
await page.fill('#configName', 'Test');
await page.click('#saveConfig');
const saved = await page.textContent('#status');
expect(saved).toContain('guardado');
});
});
- Chrome DevTools
- Network tab para llamadas API
- Console para logs
- Elements para DOM
Implementación de sistema de logging:
// Ejemplo de sistema de logging
const logger = {
debug: (message, ...args) => {
if (process.env.NODE_ENV === 'development') {
console.log(message, ...args);
}
},
error: (message, error) => {
console.error(message, error);
// Enviar a servicio de monitoreo
}
};
Lista de verificación para despliegue:
- Minimizar JavaScript
- Optimizar imágenes
- Actualizar manifiestos
- Verificar rutas API
Pasos para el despliegue:
- Ejecutar pruebas
- Construir assets
- Validar build
- Desplegar a producción