wandres.dev
STATIC ASSETS · la paridad con Pages

SPA y multipágina: el arte de not_found_handling

Qué servir cuando una URL no corresponde a ningún archivo: el campo `not_found_handling` y sus estrategias opuestas. `single-page-application` para reenviar todo al `index.html` y dejar decidir al enrutador del cliente; `404-page` para servir una página de error con el estado correcto en un sitio multipágina; y `none` como base cruda. Por qué esa elección define la naturaleza del sitio.

⏱ 15 min

Servir un archivo que existe es trivial; lo interesante empieza cuando llega una petición a una ruta que no corresponde a ningún archivo. Ese hueco —qué contestar ante /productos/42 cuando en disco no hay ningún productos/42.html— es donde se decide la naturaleza del sitio. Una aplicación de página única quiere que esa ruta cargue su index.html y deje que el enrutador de JavaScript resuelva; un sitio multipágina quiere una página de error honesta con estado 404. El campo not_found_handling codifica esa decisión en una sola línea, y elegir mal produce sitios que devuelven 200 a todo o que se rompen al recargar una ruta interna.

🎯 Al terminar esta lección sabrás
  • Entender el problema del asset ausente y por qué su resolución define el tipo de sitio.
  • Configurar not_found_handling con el valor single-page-application para una SPA.
  • Configurar 404-page para servir una página de error con el estado HTTP correcto.
  • Reconocer el impacto de cada estrategia en el SEO, el enrutado del cliente y la recarga en frío.

El problema del asset ausente

Cuando el edge recibe una petición, primero busca un asset que coincida con la ruta. Si lo encuentra, lo sirve y ahí acaba todo. La pregunta difícil es qué hacer cuando no lo encuentra, y la respuesta correcta depende por completo de cómo está construido tu sitio.

not_found_handling acepta tres valores, y cada uno describe una filosofía distinta de arquitectura web. El valor por defecto es none: si no hay archivo, se devuelve una respuesta 404 vacía. Sirve para APIs de assets crudos, pero rara vez es lo que quiere un sitio real.

{
  "assets": {
    "directory": "./dist",
    "not_found_handling": "single-page-application"
  }
}

Las dos opciones que importan —single-page-application y 404-page— resuelven el hueco de formas casi opuestas, y entender la diferencia es entender la diferencia entre las dos grandes familias de front-end: la que enruta en el cliente y la que enruta en el servidor.

flowchart TD
R[Peticion a una ruta sin archivo] --> C{Valor de not_found_handling}
C -->|single-page-application| SPA[Sirve index.html con estado 200]
C -->|404-page| P[Sirve el 404.html mas cercano con estado 404]
C -->|none| N[Respuesta 404 vacia]
style SPA fill:#89b4fa,color:#11111b
style P fill:#f9e2af,color:#11111b

La estrategia SPA: todo cae en el índice

Una aplicación de página única carga una sola vez su index.html, y a partir de ahí el enrutador de JavaScript —el de React, el de Vue, el que sea— pinta cada vista sin volver a pedir HTML al servidor. El problema aparece cuando el usuario recarga estando en /productos/42 o comparte ese enlace: el navegador pide esa URL al edge, que no tiene ningún productos/42.html en disco.

Sin ayuda, eso sería un 404, y la aplicación parecería rota justo al entrar por una ruta profunda. El valor single-page-application lo resuelve reenviando cualquier ruta sin archivo al index.html, pero con estado 200. El navegador recibe el shell de la aplicación, el JavaScript arranca, lee la URL actual y el enrutador del cliente pinta la vista de /productos/42 como si nunca se hubiera ido.

El servidor, por tanto, no sabe nada de tus rutas: solo sabe entregar siempre el mismo punto de entrada y ceder el control a tu código. Toda la autoridad sobre qué significa una URL se traslada al cliente, incluida la de declarar que una ruta no existe:

// El enrutador del cliente decide qué es una ruta desconocida
const vista = rutas[window.location.pathname];
render(vista ?? PaginaNoEncontrada);
⚠️
Un 200 para todo tiene consecuencias

Reenviar cada ruta ausente al índice con estado 200 significa que, para un rastreador o un monitor, ninguna URL falla jamás: hasta /pagina-que-nunca-existio responde 200 con el shell de tu app. Eso es correcto para una SPA, pero te obliga a gestionar los verdaderos “no encontrado” desde dentro del cliente —pintando tu propia vista de error cuando el enrutador no reconoce la ruta— porque el edge ya no distinguirá una ruta válida de una inventada. Ganas recarga en frío a cambio de perder la señal de error del protocolo.

La estrategia multipágina: un 404 honesto

Un sitio multipágina —un blog, una documentación, un catálogo generado estáticamente— tiene un archivo HTML real por cada página. Aquí una ruta sin archivo casi siempre significa lo que parece: la página no existe. La respuesta correcta no es reenviar al índice, sino servir una página de error con el estado 404, para que navegadores, buscadores y clientes de API entiendan que esa URL no lleva a ningún sitio.

El valor 404-page hace justo eso: ante una ruta sin archivo, busca el 404.html más cercano subiendo por el árbol de directorios y lo sirve con estado 404. Puedes tener un 404.html en la raíz como respaldo global y otros más específicos dentro de subcarpetas —docs/404.html para la documentación—, y el edge elegirá el más próximo a la ruta pedida.

Es la simetría exacta de la estrategia SPA: allí toda ruta desconocida era válida y la autoridad vivía en el cliente; aquí toda ruta desconocida es un error declarado como tal, y la autoridad vive en el servidor que sirve los archivos.

Cómo elegir sin equivocarte

La elección no es de gusto: se deriva de dónde vive el enrutado de tu sitio. Si tus rutas las resuelve JavaScript en el navegador, necesitas SPA; si cada URL corresponde a un archivo generado, necesitas 404-page. Confundirlas produce los dos sitios rotos más comunes de la web.

🧭

Elige single-page-application

Tu sitio carga un shell y el enrutador del cliente pinta las vistas. Quieres que recargar una ruta profunda funcione y gestionas los “no encontrado” desde tu propio código.

📄

Elige 404-page

Cada URL válida tiene un archivo HTML real detrás. Quieres que una ruta inexistente devuelva un 404 honesto que buscadores y clientes respeten.

⚖️

El criterio decisivo

Pregúntate quién debe tener autoridad sobre el significado de una URL: si el navegador, es SPA; si el servidor de archivos, es multipágina.

El código de estado es una afirmación semántica, no un adorno

La elección entre single-page-application y 404-page parece un detalle de configuración, pero es en realidad una toma de posición sobre qué significa una URL en tu sistema. Un código de estado HTTP no es decoración: es una afirmación que tu servidor hace ante el resto de la web sobre la naturaleza de una respuesta. Un 200 declara “esto es contenido legítimo y completo”; un 404 declara “esto no existe, no lo indexes, no lo caches como válido, dile al usuario que se equivocó”. Cuando eliges single-page-application estás afirmando que en tu mundo las rutas no viven en el servidor sino en el cliente, y que el servidor no tiene autoridad para negar ninguna: su trabajo es entregar el intérprete —el index.html— y callar. Cuando eliges 404-page estás afirmando lo contrario: que cada URL válida tiene un archivo que la respalda, y que la ausencia de archivo es información veraz que debes propagar con el estado correcto. La mayoría de los sitios rotos que has visto —el que devuelve la home cuando pides una página borrada, el que muestra un error de JavaScript al recargar una ruta interna— son sitios que eligieron la estrategia equivocada para su naturaleza. No hay una opción correcta en abstracto; hay una coherencia que respetar entre cómo construyes las rutas y cómo respondes a su ausencia. Configurar not_found_handling bien es, en el fondo, decidir quién tiene la autoridad sobre el significado de una URL en tu aplicación: el edge o el navegador. Esa decisión gobierna el SEO, la compartibilidad de los enlaces y la honestidad de tu sitio ante el protocolo, y por eso una línea de configuración termina siendo una de las decisiones más arquitectónicas que tomarás.

⚔️ Compara las dos filosofías en vivo
  1. Monta un sitio con un index.html y configúralo con not_found_handling a single-page-application; pide una ruta inventada como /foo/bar y confirma con las herramientas de red que llega el índice con estado 200.
  2. Cambia el valor a 404-page, añade un 404.html en la raíz y repite la petición; verifica que ahora el estado es 404 y que se sirve la página de error.
  3. Coloca un segundo 404.html dentro de una subcarpeta docs y comprueba que una ruta ausente bajo /docs/ recibe esa página más específica y no la de la raíz.
  4. Con la estrategia SPA activa, escribe en tu JavaScript una vista de “no encontrado” para cuando el enrutador del cliente no reconozca la ruta, y razona por qué esa lógica es ahora responsabilidad del cliente.
  5. Argumenta, para un blog estático y para un panel de administración, cuál de las dos estrategias es la correcta y por qué la otra produciría un sitio incoherente.