Skip to main content

Article

📦 Auditoría Técnica del Stack Frontend y Pipeline de Assets

# 📦 Auditoría Técnica del Stack Frontend y Pipeline de Assets


 

**Proyecto:** WatchTower  

**Fecha de auditoría:** 2026-05-14 08:39:38 -05  

**Alcance:** build frontend, manejo de assets, supply-chain, mantenibilidad y preparación para `pnpm`


 

## 🧭 Conclusión Ejecutiva


 

El stack frontend actual es **pequeño, comprensible y funcional**, lo cual juega a favor de una futura adopción de `pnpm`. La base es `npm` + `Webpack Encore` + `Webpack 5` + `Sass` + `Bootstrap 5`, con un solo entrypoint y sin monorepo ni workspaces.


 

El principal problema no está en complejidad extrema, sino en **riesgos de evolución**:


 

- ⚠️ La documentación indica `Node.js 18+`, pero varias dependencias activas ya exigen `>=20` o `>=20.19`.

- ⚠️ La build compila, pero con **21 warnings de deprecación Sass**, centrados en `@import` y funciones legacy de Sass/Bootstrap.

- ⚠️ Hay una **segunda supply-chain fuera de npm**: `htmx` se carga desde `unpkg` en runtime, y Google Fonts se carga externamente desde SCSS.

- ⚠️ El proyecto usa `^` en todas las dependencias directas y no declara `packageManager` ni `engines` en `package.json`.

- ✅ No se detectaron paquetes directos deprecated en el lockfile ni scripts lifecycle propios peligrosos en `package.json`.


 

**Evaluación general:** el proyecto está **bien posicionado para migrar a `pnpm`**, pero conviene hacerlo después de alinear versión de Node, endurecer política de dependencias y reducir deuda Sass.


 

---


 

## 🏗️ 1. Resumen General del Stack Frontend


 

### Estado actual


 

| Área | Hallazgo |

| ---- | -------- |

| Package manager activo | `npm` |

| Lockfile presente | `package-lock.json` (`lockfileVersion: 3`) |

| Bundler principal | `Webpack 5` vía `@symfony/webpack-encore` |

| Pipeline CSS | `Sass` + `sass-loader` + `Bootstrap 5` |

| Frameworks/librerías | `Bootstrap 5`, `HTMX` por CDN, `@popperjs/core` |

| Entrada principal | `assets/app.js` |

| Salida compilada | `public/build/` |

| Integración servidor | Symfony Encore Bundle + Twig `encore_entry_*()` |

| Monorepo / workspaces | No |


 

### Archivos relevantes encontrados


 

| Archivo | Estado | Observaciones |

| ------- | ------ | ------------- |

| `package.json` | ✅ | Dependencias y scripts frontend |

| `package-lock.json` | ✅ | Lockfile npm v3 |

| `webpack.config.js` | ✅ | Configuración principal de build |

| `config/packages/webpack_encore.yaml` | ✅ | Integración Symfony/Twig |

| `.nvmrc` | ✅ | Fija Node `24.12.0` |

| `.prettierrc.json` | ✅ | Configuración de formato |

| `.stylelintrc.json` | ✅ | Configuración SCSS |

| `yarn.lock` | ❌ | No existe |

| `pnpm-lock.yaml` | ❌ | No existe |

| `.npmrc` | ❌ | No existe |

| `.yarnrc*` | ❌ | No existe |

| `vite.config.*` | ❌ | No existe |


 

### Estructura de assets


 

- `assets/app.js` importa `./sass/main.scss` y expone `bootstrap` en `window`.

- `assets/sass/` sigue una estructura tipo **7-1 Sass** con `abstracts`, `base`, `components`, `layout`, `pages`, `themes`, `vendors`.

- `templates/base.html.twig` consume `{{ encore_entry_link_tags('app') }}` y `{{ encore_entry_script_tags('app') }}`.

- `public/build/` contiene `entrypoints.json`, `manifest.json`, `runtime.js`, un chunk compartido y el CSS/JS de `app`.


 

### Lectura arquitectónica


 

- ✅ Stack simple y centralizado.

- ✅ Un solo entrypoint reduce superficie de migración.

- ⚠️ Hay mezcla entre assets locales compilados y assets remotos no versionados por el lockfile.

- ⚠️ La ausencia de `.npmrc`, `packageManager` y `engines` deja demasiadas decisiones a cada máquina o CI runner.


 

---


 

## 📦 2. Auditoría de Dependencias


 

### Métricas generales


 

| Métrica | Valor |

| ------- | ----- |

| Dependencias directas de runtime | 4 |

| Dependencias directas de desarrollo | 14 |

| Total de paquetes resueltos en lockfile | 629 |

| Paquetes directos deprecated | 0 detectados |

| Paquetes con lifecycle install script detectados en lockfile | 3 |

| Duplicados transitorios por nombre con múltiples versiones | 42 |


 

### Dependencias principales


 

| Dependencia | Versión declarada | Versión resuelta | Estado | Observaciones |

| ----------- | ----------------- | ---------------- | ------ | ------------- |

| `bootstrap` | `^5.3.8` | `5.3.8` | ✅ | Base visual y SCSS principal |

| `@popperjs/core` | `^2.11.8` | `2.11.8` | ✅ | Soporte Bootstrap |

| `webpack` | `^5.102.1` | `5.106.2` | ✅ | Actual y soportado |

| `webpack-cli` | `^6.0.1` | `6.0.1` | ✅ | Actual |

| `@symfony/webpack-encore` | `^5.2.0` | `5.3.1` | ✅ | Abstracción estándar para Symfony |

| `sass` | `^1.93.1` | `1.99.0` | ⚠️ | Funcional, pero ya emite warnings de deprecación |

| `sass-loader` | `^16.0.5` | `16.0.7` | ✅ | Compatible con Webpack 5 |

| `core-js` | `^3.46.0` | `3.49.0` | ⚠️ | Tiene `postinstall`; además amplía superficie supply-chain |

| `regenerator-runtime` | `^0.14.1` | `0.14.1` | ✅ | Pequeña, estable |

| `eslint` | `^10.3.0` | `10.3.0` | ✅ | Moderna |

| `stylelint` | `^17.11.0` | `17.11.0` | ✅ | Moderna |

| `markdownlint-cli` | `^0.48.0` | `0.48.0` | ✅ | QA auxiliar |

| `prettier` | `^3.8.3` | `3.8.3` | ✅ | QA auxiliar |

| `@playwright/test` | `^1.59.1` | `1.59.1` | ⚠️ | Está instalado pero no se detectó uso real en tests/config del repo |


 

### Dependencias con señales de revisión


 

| Dependencia | Versión | Estado | Observaciones |

| ----------- | ------- | ------ | ------------- |

| `@playwright/test` | `1.59.1` | ⚠️ revisar | No hay `playwright.config.*` ni tests detectados; hoy parece peso adicional sin integración clara |

| `core-js` | `3.49.0` | ⚠️ revisar | Ejecuta `postinstall`; útil para polyfills, pero conviene justificar su necesidad real |

| `sass` | `1.99.0` | ⚠️ revisar | La herramienta está sana, pero el código actual depende de sintaxis Sass legacy |

| `bootstrap` | `5.3.8` | ⚠️ revisar | Compila, pero parte de los warnings vienen del stack Sass/Bootstrap actual |

| `@parcel/watcher` | `2.5.6` | ⚠️ revisar | Dependencia opcional/nativa transitiva de `sass`; añade complejidad multiplataforma |

| `fsevents` | `2.3.2` | ⚠️ revisar | Opcional y macOS-only; no es problema por sí mismo, pero es señal de diferencias por SO |

| `commander` | múltiples | ⚠️ revisar | Hay 5 versiones transitorias, síntoma de skew del árbol |

| `supports-color` | múltiples | ⚠️ revisar | Duplicación transitoria normal, pero suma ruido al árbol |


 

### Dependencias potencialmente abandonadas


 

No se detectaron dependencias directas marcadas como deprecated en el lockfile actual.


 

### Dependencias antiguas o con skew transitorio


 

No hay evidencia de dependencias directas obviously legacy, pero sí hay **fragmentación transitoria**:


 

- `commander`: 5 versiones

- `supports-color`: 4 versiones

- `string-width`: 3 versiones

- `ajv`: 2 versiones

- `webpack-sources`: 2 versiones

- `semver`: 2 versiones


 

Esto no es crítico hoy, pero sí indica un árbol con heterogeneidad suficiente como para que una migración a `pnpm` deba probarse con CI real.


 

### Lectura técnica


 

- ✅ El stack directo está bastante contenido.

- ✅ No hay señales de abandono fuerte en dependencias principales.

- ⚠️ Hay paquetes no usados con claridad.

- ⚠️ El uso universal de rangos `^` reduce control al regenerar lockfile.

- ⚠️ La salud aparente del árbol no elimina el riesgo de install scripts y dependencias opcionales nativas.


 

---


 

## 🔥 3. Revisión de Scripts npm


 

### Scripts definidos en `package.json`


 

| Script | Comando | Estado | Qué hace | Riesgo / impacto |

| ------ | ------- | ------ | -------- | ---------------- |

| `dev-server` | `encore dev-server` | ⚠️ | Levanta dev-server de Encore | No hay evidencia de uso en README/Makefile; puede quedar obsoleto |

| `dev` | `encore dev` | ✅ | Build de desarrollo | Bajo |

| `watch` | `encore dev --watch` | ✅ | Recompila al cambiar archivos | Bajo |

| `build` | `encore production --progress` | ✅ | Build optimizada de producción | Bajo, aunque hoy emite warnings |


 

### Lifecycle scripts propios


 

| Script lifecycle | Presente | Observación |

| ---------------- | -------- | ----------- |

| `preinstall` | ❌ | No definido |

| `install` | ❌ | No definido |

| `postinstall` | ❌ | No definido |

| `prepare` | ❌ | No definido |


 

### Scripts de instalación/build fuera de `package.json`


 

| Ubicación | Comando | Estado | Observaciones |

| --------- | ------- | ------ | ------------- |

| `Makefile:install` | `composer install` + `nvm use` + `npm install` | ⚠️ | Acopla instalación a `nvm` y a `npm` explícitamente |

| `Makefile:install-dev-tools` | `npm install --save-dev ...` | ⚠️ | Modifica `package.json` como parte del flujo operativo |

| `Makefile:check-updates-js` | `npm outdated` | ⚠️ | Depende de red |

| `Makefile:check-security-js` | `npm audit` | ⚠️ | Depende de red |


 

### Riesgos observados


 

- ⚠️ `make install` usa `npm install`, no `npm ci`. Eso reduce reproducibilidad frente a CI y frente a una migración controlada.

- ⚠️ `make install-dev-tools` vuelve a instalar dependencias que ya existen en `package.json`; esto mezcla bootstrap del repo con “mutación del manifiesto”.

- ⚠️ El flujo está hardcodeado a `npm`, no parametrizado para `pnpm`.

- ⚠️ `nvm use` en Makefile asume un entorno interactivo con NVM disponible.


 

### Compatibilidad con `pnpm`


 

- `dev`, `watch`, `build`: ✅ deberían migrar sin drama.

- `install`: ⚠️ requiere cambio explícito a `pnpm install --frozen-lockfile` o equivalente.

- `install-dev-tools`: ❌ el enfoque actual no es compatible como práctica estable; con `pnpm` conviene declarar herramientas una sola vez y no “autoinstalar” en flujos.

- Binarios `node_modules/.bin`: ✅ `pnpm` los expone, pero scripts/Makefile deberían probarse.


 

---


 

## 🔐 4. Revisión de Seguridad Supply-Chain


 

### Hallazgos principales


 

| Riesgo | Severidad | Recomendación |

| ------ | --------- | ------------- |

| Uso de rangos `^` en todas las dependencias directas | ⚠️ Media | Fijar política: mantener `^` solo si CI valida lockfile; para endurecer, usar versiones exactas o Renovate/Dependabot |

| `npm install` en lugar de `npm ci` | ⚠️ Media | Usar instalación determinista en CI y preferentemente también en entornos reproducibles |

| Falta de `packageManager` y `engines` en `package.json` | ⚠️ Media | Declarar gestor y rango de Node soportado |

| `core-js` ejecuta `postinstall` | ⚠️ Media | Documentar necesidad real y vigilar updates |

| `@parcel/watcher` ejecuta `install` y gestiona binarios/plataformas | ⚠️ Media | Aceptable si se mantiene Sass, pero debe figurar en el inventario de riesgo |

| `htmx` cargado desde `unpkg` en runtime | ⚠️ Media | Preferir empaquetarlo localmente con npm y Webpack |

| Google Fonts cargado externamente vía `@import url(...)` | ⚠️ Baja | Considerar self-hosting o al menos centralizar decisión |

| Auditoría automática `npm audit` dependiente de red | ⚠️ Baja | Ejecutarla en CI con conectividad real y publicar resultados |

| Lockfile presente y versionado | ✅ Positivo | Mantenerlo obligatorio |

| Secretos en scripts frontend | ✅ Positivo | No se detectaron secretos expuestos en `package.json` o scripts analizados |


 

### Dependencias con ejecución automática detectada


 

| Paquete | Tipo | Riesgo | Observaciones |

| ------- | ---- | ------ | ------------- |

| `core-js` | `postinstall` | ⚠️ | Ejecuta código al instalar |

| `@parcel/watcher` | `install` | ⚠️ | Build/source logic de módulo nativo |

| `fsevents` | nativo opcional | ⚠️ | Diferencias por plataforma, macOS-only |


 

### Auditoría dinámica


 

`npm audit --json` **no pudo completarse en esta auditoría** por falta de acceso a `registry.npmjs.org` desde el entorno analizado:


 

```text

getaddrinfo ENOTFOUND registry.npmjs.org

```


 

Interpretación correcta:


 

- ❌ No significa que el árbol esté libre de vulnerabilidades.

- ✅ Sí significa que el pipeline necesita una ejecución real de `npm audit` en CI o en un runner con salida a internet.


 

### Typosquatting


 

No se observan nombres de dependencias directas sospechosos. El set directo está compuesto por paquetes ampliamente conocidos.


 

### Riesgo de binarios externos


 

- `@playwright/test` puede implicar ecosistema de navegadores/binarios si llega a usarse realmente.

- `@parcel/watcher` y `fsevents` introducen piezas nativas por SO.

- No se detectaron descargas custom en scripts propios del proyecto.


 

---


 

## ⚙️ 5. Análisis de Webpack / Sistema de Build


 

### Configuración actual


 

| Aspecto | Estado |

| ------- | ------ |

| Bundler | `Webpack 5` |

| Capa de abstracción | `@symfony/webpack-encore` |

| Entrypoints | 1 (`app`) |

| Output | `public/build/` |

| Public path | `/build` |

| Split chunks | ✅ activado |

| Runtime chunk | ✅ activado |

| Source maps | ✅ solo en no producción |

| Versionado/hash | ✅ en producción |

| Limpieza previa | ✅ `cleanupOutputBeforeBuild()` |

| Polyfills | ✅ `@babel/preset-env` con `useBuiltIns: 'usage'` y `corejs = '3.38'` |

| SASS | ✅ `enableSassLoader()` |


 

### Entry points y salida real


 

La build actual genera:


 

- `runtime.*.js`

- `336.*.js` como chunk compartido

- `app.*.js`

- `app.*.css`

- `entrypoints.json`

- `manifest.json`


 

### Loaders y plugins observables


 

Por la configuración y la ejecución real de build:


 

- `babel-loader`

- `mini-css-extract-plugin`

- `css-loader`

- `resolve-url-loader`

- `sass-loader`

- `TerserPlugin`

- `CssMinimizerPlugin`

- `WebpackManifestPlugin`


 

### Manejo de SASS/CSS


 

- El proyecto usa `main.scss` como entry único.

- Se apoya en `@import`, no en `@use` / `@forward`.

- Se importa `bootstrap/scss/bootstrap` completo.

- Hay overrides previos de variables Bootstrap.


 

### Manejo de imágenes/fonts


 

- Los favicons viven fuera del pipeline JS principal.

- Las fuentes no se empaquetan localmente: se cargan desde `fonts.googleapis.com`.


 

### Complejidad del setup


 

| Área | Evaluación |

| ---- | ---------- |

| Webpack config | ✅ simple |

| Symfony integration | ✅ estándar |

| Número de entrypoints | ✅ bajo |

| Personalización de loaders/plugins | ✅ baja |

| Complejidad SCSS | ⚠️ media |

| Complejidad operativa global | ⚠️ media |


 

### Configuración legacy o con deuda


 

| Hallazgo | Estado | Observación |

| -------- | ------ | ----------- |

| `@import` Sass | ❌ crítico a medio plazo | Ya deprecado; removido en Sass 3.0 |

| Warnings desde Bootstrap/Sass functions | ⚠️ | No rompe hoy, pero anticipa futura fricción |

| `vendors/_vendors.scss` reimporta Bootstrap completo | ⚠️ revisar | Hoy `main.scss` ya importa Bootstrap; este archivo merece revisión para evitar ambigüedad conceptual |

| `dev-server` en scripts | ⚠️ revisar | No se observó integración clara en docs/flujo |


 

### Resultado real de build


 

La build de producción terminó correctamente, pero con:


 

- `webpack compiled with 21 warnings`

- warnings centrados en:

  - `Sass @import rules are deprecated`

  - funciones Sass globales deprecadas

  - sintaxis legacy usada por Bootstrap/Sass actual


 

Interpretación:


 

- ✅ El pipeline funciona hoy.

- ⚠️ El pipeline ya está avisando de ruptura futura.


 

---


 

## 🚀 6. Compatibilidad con `pnpm`


 

### Matriz resumida


 

| Área | Compatibilidad con pnpm |

| ---- | ----------------------- |

| Dependencias | ⚠️ |

| Webpack | ✅ |

| Scripts | ⚠️ |

| CI/CD | ⚠️ |

| Monorepo readiness | ⚠️ |


 

### Evaluación detallada


 

#### Dependencias


 

- ✅ No hay dependencias directas obviously incompatibles con `pnpm`.

- ⚠️ Existen paquetes con módulos nativos y opcionales por plataforma (`@parcel/watcher`, `fsevents`).

- ⚠️ `playwright` añade peso operativo y puede requerir atención si se activa en CI.


 

#### Webpack / Encore


 

- ✅ Webpack 5 y Encore suelen convivir bien con `pnpm`.

- ✅ Un solo entrypoint simplifica troubleshooting.

- ⚠️ Si algún plugin o loader asumiera resolución plana, el primer sitio donde se vería sería durante `pnpm install` + `pnpm build`, no por diseño del config actual.


 

#### Scripts


 

- ⚠️ `Makefile` está escrito para `npm`.

- ⚠️ `make install-dev-tools` muta dependencias; esto es mala base para `pnpm`.

- ⚠️ `node_modules/.bin/...` suele funcionar, pero debe validarse con `pnpm` en CI.


 

#### CI/CD


 

- ⚠️ Hoy no se ve una política explícita de lockfile inmutable.

- ⚠️ Falta declarar `packageManager` y `engines`.

- ⚠️ `npm audit` y `npm outdated` dependen de runners con red.


 

#### Monorepo readiness


 

- ❌ No hay monorepo.

- ✅ Justamente por eso, la adopción de `pnpm` es más simple.

- ⚠️ Aun así, no existe `pnpm-workspace.yaml`, así que la preparación es “single-package”, no monorepo.


 

### Riesgos concretos de migración


 

| Riesgo | Estado | Comentario |

| ------ | ------ | ---------- |

| Dependencias que asumen `node_modules` plano | ⚠️ posible | No detectado explícitamente, pero debe probarse |

| Tooling acoplado a `npm` | ⚠️ claro | Está en Makefile y documentación |

| Lifecycle scripts transitivos | ⚠️ claro | Seguirán ejecutándose salvo política explícita |

| Diferencias por SO | ⚠️ claro | `fsevents` y `@parcel/watcher` |

| Build frontend | ✅ favorable | Simple y centralizada |


 

---


 

## 🧪 7. Recomendaciones Técnicas


 

### ✅ Quick Wins


 

1. Declarar `engines.node` en `package.json` y alinear README con la realidad actual.

2. Declarar `packageManager`, por ejemplo `pnpm@<version>` cuando se decida la migración, o al menos fijar `npm` mientras tanto.

3. Cambiar CI de `npm install` a instalación determinista (`npm ci` ahora, `pnpm install --frozen-lockfile` después).

4. Ejecutar `npm audit` y `npm outdated` en CI con conectividad real y publicar resultados.

5. Revisar si `@playwright/test` debe quedarse; hoy parece dependencia huérfana.

6. Mover `htmx` desde CDN a dependencia local gestionada por lockfile.

7. Evaluar self-hosting de fuentes o al menos registrar la dependencia externa como excepción aceptada.


 

### 🛠️ Refactors recomendados


 

1. Reescribir Sass desde `@import` hacia `@use` / `@forward`.

2. Revisar `vendors/_vendors.scss` para eliminar reimportaciones o ambigüedad con Bootstrap.

3. Simplificar `Makefile:install-dev-tools` para que no modifique el manifiesto en flujos normales.

4. Añadir una política de actualización controlada de dependencias con Renovate o Dependabot.

5. Añadir validación explícita de versión de Node en CI.


 

### 🔥 Riesgos críticos


 

1. **Desalineación Node real vs documentación**. Varias herramientas ya requieren `>=20`; mantener “Node 18+” induce fallos sutiles en onboarding y CI.

2. **Deuda Sass**. Los warnings actuales son aviso directo de incompatibilidad futura.

3. **Supply-chain partida**. Parte del frontend se sirve desde CDN y no desde el lockfile.

4. **Instalación no determinista**. `npm install` como flujo base sigue siendo una debilidad.


 

### 🚀 Roadmap sugerido para adopción gradual de `pnpm`


 

#### Fase 1: endurecimiento previo


 

1. Fijar política de Node.

2. Añadir `engines` en `package.json`.

3. Cambiar CI a instalación inmutable.

4. Validar que `npm run build`, lint y tests pasen en un runner limpio.


 

#### Fase 2: reducción de deuda


 

1. Eliminar o justificar `@playwright/test`.

2. Localizar `htmx` dentro del árbol npm.

3. Registrar excepciones de supply-chain externas.

4. Planificar migración Sass `@import` -> `@use`.


 

#### Fase 3: prueba controlada con `pnpm`


 

1. Generar rama de prueba.

2. Ejecutar `pnpm install`.

3. Correr `pnpm build`, lint y tests.

4. Revisar warnings de resolución y binarios opcionales por plataforma.


 

#### Fase 4: adopción formal


 

1. Crear `pnpm-lock.yaml`.

2. Actualizar `Makefile`, README y CI.

3. Añadir `packageManager` a `package.json`.

4. Eliminar dependencia operativa de `npm` en documentación y automatización.


 

---


 

## 📌 Observaciones Finales


 

### Estado de mantenibilidad


 

| Área | Estado |

| ---- | ------ |

| Tamaño del stack | ✅ bueno |

| Claridad arquitectónica | ✅ buena |

| Deuda de estilos | ⚠️ media |

| Riesgo supply-chain | ⚠️ medio |

| Preparación para `pnpm` | ⚠️ buena con ajustes previos |

| Riesgo de migración | ⚠️ moderado, manejable |


 

### Veredicto final


 

**WatchTower sí está en una posición razonable para adoptar `pnpm`, pero no conviene hacer la migración “en crudo”.**  

La secuencia profesional correcta es:


 

1. alinear versión de Node,

2. endurecer reproducibilidad,

3. reducir dependencias ambiguas y CDN runtime,

4. atacar deuda Sass,

5. recién entonces formalizar el cambio de package manager.


 

Si se sigue ese orden, la migración debería ser **de riesgo bajo a medio**, con buena probabilidad de éxito y con mejoras reales en gobernanza del pipeline frontend.