agrovision / scripts /inline_js.py
alexp97's picture
build(deploy): pipeline Astro (build+inline) + deploy_prod rsconnect + .rscignore
f514b00
Raw
History Blame Contribute Delete
4.17 kB
"""
Archivo: inline_js.py
Fecha de modificación: 04/06/2026
Autor: Equipo AgroVisión
Descripción:
Post-procesa el HTML del build de Astro para que funcione bajo **sub-paths dinámicos**
(como los slugs `/_w_xxxx/` de ShinyApps.io). Inyecta inline los scripts que Astro
hubiera emitido en `/_astro/*.js` y normaliza las rutas de assets (favicon, JS) de
**absolutas a relativas**, ya que el host sirve la app desde una ruta distinta de la raíz.
Es la implementación de la "Regla de Oro" de `docs/doc_guia/plan_replication.md`.
Nota: nuestra UI ya usa scripts `is:inline` y `inlineStylesheets: 'always'`, por lo que
normalmente no hay `/_astro/*.js` externos; este script es idempotente y a prueba de
futuro (si se añade una isla/componente que genere JS externo, queda inlineado).
Acciones Principales:
- Inyecta el contenido de los scripts `/_astro/*.js` directamente en el HTML.
- Convierte las rutas absolutas de favicon a relativas.
- Normaliza cualquier referencia absoluta restante a `/_astro/`.
Estructura Interna:
- `inline_scripts`: inyecta el código JS externo inline.
- `fix_favicon_paths`: relativiza las rutas de iconos.
- `fix_absolute_asset_refs`: relativiza las rutas absolutas restantes.
- `main`: orquesta el post-proceso sobre `frontend/dist/index.html`.
Entradas / Dependencias:
- Biblioteca estándar (`re`, `pathlib`).
Salidas / Efectos:
- Reescribe `frontend/dist/index.html` in place.
Ejecución:
uv run python scripts/inline_js.py
"""
from __future__ import annotations
import re
import sys
from pathlib import Path
DIST = Path("frontend/dist")
HTML_FILE = DIST / "index.html"
def inline_scripts(html: str) -> str:
"""
Reemplaza cada `<script ... src="/_astro/...">` por su contenido inline.
Args:
html (str): HTML de entrada.
Returns:
str: HTML con los scripts de Astro embebidos inline.
"""
def _replace(match: re.Match) -> str: # type: ignore[type-arg]
src = match.group(1)
rel = src.lstrip("/") # la URL parte de "/"; el archivo es relativo a DIST
js_path = DIST / rel
if js_path.exists():
content = js_path.read_text(encoding="utf-8")
return f'<script type="module">{content}</script>'
print(f" [WARN] JS no encontrado: {js_path}", file=sys.stderr)
return match.group(0)
pattern = (
r'<script\s[^>]*type=["\']module["\'][^>]*'
r'src=["\'](\/_astro\/[^"\']+)["\'][^>]*>\s*</script>'
)
return re.sub(pattern, _replace, html)
def fix_favicon_paths(html: str) -> str:
"""Convierte rutas absolutas `/favicon.*` a relativas `./favicon.*`."""
html = re.sub(r'href="\/favicon\.', 'href="./favicon.', html)
html = re.sub(r"href='\/favicon\.", "href='./favicon.", html)
return html
def fix_absolute_asset_refs(html: str) -> str:
"""Convierte cualquier referencia absoluta restante a `/_astro/` en relativa."""
html = html.replace('href="/_astro/', 'href="./_astro/')
html = html.replace("href='/_astro/", "href='./_astro/")
html = html.replace('src="/_astro/', 'src="./_astro/')
html = html.replace("src='/_astro/", "src='./_astro/")
return html
def main() -> None:
"""
Aplica el post-proceso sobre `frontend/dist/index.html` in place.
Raises:
SystemExit: si no existe el HTML del build (código 1).
"""
if not HTML_FILE.exists():
print(f"[ERROR] No se encontró {HTML_FILE}. Ejecuta 'pnpm build' (en frontend/) primero.")
sys.exit(1)
html = HTML_FILE.read_text(encoding="utf-8")
original_len = len(html)
html = inline_scripts(html)
html = fix_favicon_paths(html)
html = fix_absolute_asset_refs(html)
HTML_FILE.write_text(html, encoding="utf-8")
remaining = re.findall(r'["\']/_astro/', html)
if remaining:
print(f"[WARN] Aún quedan {len(remaining)} referencias a /_astro/ sin convertir.")
else:
print(f"[OK] inline_js.py completado ({original_len} -> {len(html)} bytes).")
print(" No quedan referencias absolutas a /_astro/ en index.html.")
if __name__ == "__main__":
main()