optimizacion y preload de rutas y imagenes

This commit is contained in:
luis cespedes 2025-05-06 12:12:00 -04:00
parent ee8d0d0889
commit b30722bf68
16 changed files with 283 additions and 33 deletions

66
.dockerignore Normal file
View File

@ -0,0 +1,66 @@
# Dependencias
node_modules
npm-debug.log
yarn-debug.log
yarn-error.log
# Archivos de compilación
/dist
/tmp
/out-tsc
/bazel-out
# Archivos de IDE y editores
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
.vscode/*
# Archivos del sistema
.DS_Store
Thumbs.db
# Archivos de entorno (excepto los de ejemplo)
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# Archivos de Docker (para evitar recursión)
Dockerfile
Dockerfile.*
docker-compose.yml
docker-compose.*.yml
# Archivos Git
.git
.gitignore
# Archivos de test y coverage
/coverage
/tests
*.spec.ts
# Archivos de configuración
.angular/cache
.sass-cache/
connect.lock
libpeerconnection.log
testem.log
/typings
# Archivos de build temporales
.build
.buildinfo
.cache
# Otros archivos innecesarios
README.md
CHANGELOG.md
*.md
LICENSE

3
.gitignore vendored
View File

@ -42,4 +42,5 @@ testem.log
Thumbs.db
.sonarlint
.vscode
.scannerwork
.scannerwork
package-lock.json

67
.htaccess Normal file
View File

@ -0,0 +1,67 @@
# Habilitar compresión GZIP
<IfModule mod_deflate.c>
# Comprimir HTML, CSS, JavaScript, Text, XML y fonts
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font
AddOutputFilterByType DEFLATE application/x-font-opentype
AddOutputFilterByType DEFLATE application/x-font-otf
AddOutputFilterByType DEFLATE application/x-font-truetype
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE font/otf
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
# Eliminar bugs de navegadores antiguos
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
# No comprimir imágenes (ya están comprimidas)
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|webp)$ no-gzip
</IfModule>
# Habilitar caché de navegador
<IfModule mod_expires.c>
ExpiresActive On
# Imágenes
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/webp "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
ExpiresByType image/x-icon "access plus 1 year"
# Video
ExpiresByType video/mp4 "access plus 1 year"
ExpiresByType video/mpeg "access plus 1 year"
# CSS, JavaScript
ExpiresByType text/css "access plus 1 month"
ExpiresByType text/javascript "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
# Otros
ExpiresByType application/pdf "access plus 1 month"
ExpiresByType application/x-shockwave-flash "access plus 1 month"
</IfModule>
# Reglas de SPA para Angular
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]

28
Dockerfile Normal file
View File

@ -0,0 +1,28 @@
FROM node:20.19.1-alpine AS build
# Establecer directorio de trabajo
WORKDIR /app
# Copiar archivos de dependencias e instalar
COPY package*.json ./
RUN npm install
# Copiar el resto de archivos de la aplicación
COPY . .
# Compilar la aplicación
RUN npm run build:prod
# Segunda etapa: Nginx
FROM nginx:latest
# Copiar la configuración de Nginx
COPY nginx.conf /etc/nginx/nginx.conf
# Copiar archivos compilados desde la etapa anterior
COPY --from=build /app/dist/cronogramas-primeng/browser /usr/share/nginx/html
# Exponer puerto
EXPOSE 80
# Comando para iniciar Nginx (usa el predeterminado de la imagen)

View File

@ -29,13 +29,30 @@
{
"glob": "**/*",
"input": "public"
},
{
"glob": ".htaccess",
"input": ".",
"output": "/"
}
],
"styles": [
"src/styles.scss",
"node_modules/animate.css/animate.min.css",
"node_modules/primeflex/primeflex.css",
"node_modules/primeicons/primeicons.css"
{
"input": "node_modules/animate.css/animate.min.css",
"bundleName": "animate",
"inject": true
},
{
"input": "node_modules/primeflex/primeflex.css",
"bundleName": "primeflex",
"inject": true
},
{
"input": "node_modules/primeicons/primeicons.css",
"bundleName": "primeicons",
"inject": true
}
],
"scripts": [],
"allowedCommonJsDependencies": [
@ -45,7 +62,11 @@
},
"configurations": {
"production": {
"outputHashing": "all"
"outputHashing": "all",
"optimization": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true
},
"development": {
"optimization": false,
@ -83,6 +104,11 @@
{
"glob": "**/*",
"input": "public"
},
{
"glob": ".htaccess",
"input": ".",
"output": "/"
}
],
"styles": [

12
docker-compose.yml Normal file
View File

@ -0,0 +1,12 @@
version: '3.8'
services:
web:
build:
context: .
dockerfile: Dockerfile
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
restart: unless-stopped

27
nginx.conf Normal file
View File

@ -0,0 +1,27 @@
# the events block is required
events{}
http {
# include the default mime.types to map file extensions to MIME types
include /etc/nginx/mime.types;
server {
# set the root directory for the server (we need to copy our
# application files here)
root /usr/share/nginx/html;
# set the default index file for the server (Angular generates the
# index.html file for us and it will be in the above directory)
index index.html;
# specify the configuration for the '/' location
location / {
# try to serve the requested URI. if that fails then try to
# serve the URI with a trailing slash. if that fails, then
# serve the index.html file; this is needed in order to serve
# Angular routes--e.g.,'localhost:8080/customer' will serve
# the index.html file
try_files $uri $uri/ /index.html;
}
}
}

View File

@ -5,6 +5,7 @@
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"build:prod": "ng build --configuration production",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},

BIN
public/img/footer-logo.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
public/img/header2.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -1,5 +1,5 @@
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter, RouteReuseStrategy } from '@angular/router';
import { provideRouter, withPreloading, PreloadAllModules } from '@angular/router';
import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http';
import { routes } from './app.routes';
@ -7,12 +7,14 @@ import { provideAnimations } from '@angular/platform-browser/animations';
import { providePrimeNG } from 'primeng/config';
import Aura from '@primeng/themes/aura';
import { authInterceptor } from './interceptors/auth.interceptor';
import { CustomRouteReuseStrategy } from './utils/custom-route-reuse-strategy';
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes),
provideRouter(
routes,
withPreloading(PreloadAllModules)
),
provideAnimations(),
provideHttpClient(withFetch(), withInterceptors([authInterceptor])),
providePrimeNG({
@ -22,12 +24,6 @@ export const appConfig: ApplicationConfig = {
darkModeSelector: false || 'none'
}
}
}),
// Añadir estrategia de reuso de rutas personalizada para forzar
// recreación de componentes en cada navegación
{
provide: RouteReuseStrategy,
useClass: CustomRouteReuseStrategy
}
})
]
};

View File

@ -1,12 +1,6 @@
import { Routes } from '@angular/router';
import { Routes, PreloadAllModules } from '@angular/router';
import { LoginComponent } from './pages/login/login.component';
import { LayoutComponent } from './components/layout/layout.component';
import { HomeComponent } from './pages/home/home.component';
import { ConcesionesComponent } from './pages/concesiones/concesiones.component';
import { ActualizacionPdComponent } from './pages/actualizacion-pd/actualizacion-pd.component';
import { AjustePdComponent } from './pages/ajuste-pd/ajuste-pd.component';
import { ResumenComponent } from './pages/resumen/resumen.component';
import { UnidadInformacionComponent } from './pages/unidad-informacion/unidad-informacion.component';
import { authGuard } from './guards/auth.guard';
import { NotFoundComponent } from './pages/not-found/not-found.component';
@ -18,13 +12,41 @@ export const routes: Routes = [
canActivate: [authGuard],
children: [
{ path: '', redirectTo: 'inicio', pathMatch: 'full' },
{ path: 'inicio', component: HomeComponent, data: { title: 'Inicio' } },
{ path: 'unidad-concesiones', component: ConcesionesComponent, data: { title: 'Unidad de Concesiones' } },
{ path: 'ct-actualizacion', component: ActualizacionPdComponent, data: { title: 'Cronograma temporal por actualización de PD' } },
{ path: 'ct-ajuste', component: AjustePdComponent, data: { title: 'Cronograma temporal por ajuste de PD' } },
{ path: 'resumen', component: ResumenComponent, data: { title: 'Resumen' } },
{ path: 'unidad-informacion', component: UnidadInformacionComponent, data: { title: 'Unidad de Información' } },
{ path: '404', component: NotFoundComponent , data: { title: 'Error 404' } },
{
path: 'inicio',
loadComponent: () => import('./pages/home/home.component').then(m => m.HomeComponent),
data: { title: 'Inicio' }
},
{
path: 'unidad-concesiones',
loadComponent: () => import('./pages/concesiones/concesiones.component').then(m => m.ConcesionesComponent),
data: { title: 'Unidad de Concesiones' }
},
{
path: 'ct-actualizacion',
loadComponent: () => import('./pages/actualizacion-pd/actualizacion-pd.component').then(m => m.ActualizacionPdComponent),
data: { title: 'Cronograma temporal por actualización de PD' }
},
{
path: 'ct-ajuste',
loadComponent: () => import('./pages/ajuste-pd/ajuste-pd.component').then(m => m.AjustePdComponent),
data: { title: 'Cronograma temporal por ajuste de PD' }
},
{
path: 'resumen',
loadComponent: () => import('./pages/resumen/resumen.component').then(m => m.ResumenComponent),
data: { title: 'Resumen' }
},
{
path: 'unidad-informacion',
loadComponent: () => import('./pages/unidad-informacion/unidad-informacion.component').then(m => m.UnidadInformacionComponent),
data: { title: 'Unidad de Información' }
},
{
path: '404',
component: NotFoundComponent,
data: { title: 'Error 404' }
},
]
},
{ path: '**', redirectTo: '404' }

View File

@ -2,14 +2,13 @@
<footer class="footer mt-5">
<div class="footer-content">
<div class="footer-left">
<!-- <i class="pi pi-building"></i> -->
<div class="footer-text">
<div>Superintendencia de Servicios Sanitarios</div>
<div>&aacute;rea de Informaci&oacute;n y Tecnolog&iacute;as</div>
</div>
</div>
<div class="footer-center">
<img src="img/footer-logo.jpg" alt="SISS Logo" class="footer-logo">
<img src="img/footer-logo.webp" alt="SISS Logo" class="footer-logo" loading="lazy" width="150" height="50">
</div>
<div class="footer-right">
<div>Direcci&oacute;n: Moneda 673 Piso 9 - Metro Santa Luc&iacute;a</div>

View File

@ -3,7 +3,7 @@
<div class="header-container">
<div class="header-image">
<div class="water-drop-container">
<img src="img/gota.png" alt="gota" class="water-drop">
<img src="img/gota.png" alt="gota" class="water-drop" width="41" height="60" fetchpriority="high">
<div class="text-drop">1.0</div>
</div>
<div class="header-text">

View File

@ -227,10 +227,12 @@
position: relative;
width: 100%;
height: 250px;
background-image: url('/img/header2.jpg');
background-image: url('/img/header2.webp');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
will-change: transform;
contain: paint;
}
.water-drop-container {

View File

@ -6,6 +6,9 @@
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="preload" as="image" href="img/header2.webp" type="image/webp">
<link rel="preload" as="image" href="img/footer-logo.webp" type="image/webp">
<link rel="preload" as="image" href="img/gota.png" type="image/png">
</head>
<body>
<app-root></app-root>