COMPARTE ESTE ARTÍCULO Y MUESTRA LO QUE APRENDISTE

Tutorial: Publicar gratis una web estática con Flask + Frozen‑Flask en Netlify

Guía paso a paso, clara y genérica, para convertir una app Flask sencilla en un sitio estático y publicarla gratis en Netlify. Incluye requisitos, estructura, ejemplos de código, build, despliegue y una sección amplia de problemas comunes con sus soluciones.

1) Objetivo

  • Renderizar tus páginas Flask a HTML estático (sin servidor Python) y servirlas en Netlify.
  • Beneficios: hosting gratuito, CDN global, HTTPS automático y despliegues por Git.

2) Requisitos previos

  • Python 3.10+ instalado.
  • Git instalado y repositorio en GitHub/GitLab/Bitbucket (Netlify se integra con ellos).
  • Línea de comandos (Windows PowerShell, macOS Terminal o Linux Shell).

3) Estructura mínima del proyecto

.
├─ app.py                # App Flask con rutas
├─ freeze.py             # Script para "congelar" (generar HTML estático)
├─ netlify.toml          # Configuración de build en Netlify
├─ requirements.txt      # Dependencias
├─ templates/            # Plantillas Jinja2 (*.html)
└─ static/               # CSS, imágenes, JS

4) Dependencias

Archivo requirements.txt:

Flask>=3.0,<4.0
Frozen-Flask>=0.18

Instalación local (ejecuta línea por línea):

python -m venv venv
# Windows
venv\Scripts\Activate.ps1
# macOS/Linux
source venv/bin/activate

python -m pip install -r requirements.txt

5) Código mínimo

  1. app.py (app Flask básica):
from flask import Flask, render_template, url_for

app = Flask(__name__)

@app.get("/")
def index():
    return render_template("index.html")

@app.get("/about/")  # Nota: barra final para sitio estático
def about():
    return render_template("about.html")

if __name__ == "__main__":
    app.run(debug=True)
  1. templates/index.html (ejemplo mínimo):
<!doctype html>
<html lang="es">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Inicio · Mi Sitio</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" />
  </head>
  <body>
    <nav>
      <a href="/">Inicio</a>
      <a href="/about/">Sobre mí</a>
    </nav>
    <main>
      <h1>Hola Mundo</h1>
      <p>Este sitio está generado con Flask y servido como HTML estático.</p>
    </main>
  </body>
  </html>
  1. templates/about.html (ejemplo mínimo):
<!doctype html>
<html lang="es">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Sobre mí · Mi Sitio</title>
  </head>
  <body>
    <nav>
      <a href="/">Inicio</a>
      <a href="/about/">Sobre mí</a>
    </nav>
    <main>
      <h1>Sobre mí</h1>
      <p>Texto de ejemplo.</p>
    </main>
  </body>
  </html>
  1. static/css/styles.css (opcional):
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif; }
nav a { margin-right: 12px; text-decoration: none; color: #0a66c2; }

6) Congelación (generar HTML estático)

Archivo freeze.py:

from __future__ import annotations
import shutil
from flask_frozen import Freezer
from app import app

BUILD_DIR = "build"

def main() -> None:
    freezer = Freezer(app)

    @freezer.register_generator
    def static_pages():
        # Rutas con barra final para generar /about/index.html
        for path in ["/", "/about/"]:
            yield path

    # Limpia la salida y genera
    shutil.rmtree(BUILD_DIR, ignore_errors=True)
    freezer.freeze()

if __name__ == "__main__":
    main()

Generar el sitio:

python freeze.py

Se creará la carpeta build/ con:

  • build/index.html
  • build/about/index.html
  • build/static/... (assets referenciados con url_for('static', ...))

7) Configurar Netlify

  1. Crea el archivo netlify.toml en la raíz del repo:
[build]
  command = "pip install -r requirements.txt && python freeze.py"
  publish = "build"

[build.environment]
  PYTHON_VERSION = "3.11"
  1. Sube el repo a GitHub/GitLab/Bitbucket.

  2. En Netlify:

  • New site from Git → selecciona tu repositorio.
  • Deja el comando y directorio de publicación según netlify.toml.
  • Deploy.
  1. Para reconstrucciones limpias, usa “Clear cache and deploy site” en Deploys.

8) Buenas prácticas para sitios estáticos

  • Usa rutas con barra final (e.g., /about/) para que el host sirva .../index.html con Content-Type: text/html correcto.
  • Usa url_for('static', filename='...') para referenciar CSS/JS/imagenes.
  • Evita rutas relativas quebradizas; en plantillas, genera enlaces absolutos (/ruta/).
  • No dupliques manualmente assets a build/; Frozen-Flask copia lo necesario.
  • Verifica tu build/ localmente abriendo los HTML antes de publicar.

9) Problemas comunes y cómo resolverlos

  • “Veo el HTML como texto en el navegador”

    • Causa: generaste archivos about.html sueltos sin carpeta about/index.html o el host no infiere index.html.
    • Solución: usa rutas con barra final y registra esas rutas en freeze.py.
  • “404 en subpáginas al hacer clic”

    • Causa: enlaces sin barra final o rutas no registradas.
    • Solución: añade las rutas a static_pages() y usa enlaces como /about/.
  • “No carga el CSS o imágenes”

    • Causa: referencias a archivos con rutas manuales erróneas.
    • Solución: usa {{ url_for('static', filename='css/styles.css') }} y confirma que build/static/... existe.
  • “El build en Netlify falla”

    • Revisa Deploy logs: puede faltar requirements.txt, o el comando de build está mal.
    • Asegura PYTHON_VERSION compatible (3.10/3.11) en netlify.toml.
    • Verifica que freeze.py no copie manualmente a destinos ya existentes (evita copytree a build/...).
  • “Los cambios no se reflejan tras deploy”

    • Causa: caché de Netlify o navegador.
    • Solución: “Clear cache and deploy site”; recarga dura (Ctrl+F5) o abre en incógnito.
  • “En local funciona, en Netlify no”

    • Causa: rutas relativas o dependencias faltantes.
    • Solución: usa rutas absolutas (con /), revisa requirements.txt y el comando de build.
  • “Quiero SPA o rutas dinámicas”

    • Este flujo es para HTML estático renderizado por Flask en build-time. Para SPA usa frameworks JS o funciones serverless.

10) Checklist de publicación

  • [ ] requirements.txt con Flask y Frozen-Flask.
  • [ ] Rutas definidas (con barra final cuando aplique).
  • [ ] freeze.py limpia build/ y congela rutas necesarias.
  • [ ] build/ generado localmente con HTML + assets.
  • [ ] netlify.toml con publish = "build" y command correcto.
  • [ ] Deploy en Netlify finalizado sin errores.

11) Comandos rápidos

# Preparación
python -m venv venv
venv\Scripts\Activate.ps1   # Windows
# source venv/bin/activate   # macOS/Linux
python -m pip install -r requirements.txt

# Generar sitio estático
python freeze.py

# Git
git add .
git commit -m "Publicar sitio estático"
git push

# Netlify: Clear cache and deploy (en el panel web)

Con esto tendrás una web estática generada con Flask + Frozen‑Flask y publicada gratis en Netlify, de forma simple, reproducible y profesional.

COMPARTE ESTE ARTÍCULO Y MUESTRA LO QUE APRENDISTE

0 Comentarios

para escribir tu comentario

Artículos relacionados