Con Firebase Hosting, puedes configurar un comportamiento de alojamiento personalizado para solicitudes a tu sitio.
¿Qué puedes configurar para Hosting?
Especifica qué archivos en el directorio de tu proyecto local deseas implementar en Firebase Hosting. Aprender cómo.
Ofrece una página 404/No encontrada personalizada. Aprender cómo.
Configure
redirects
para páginas que haya movido o eliminado. Aprender cómo.Configure
rewrites
para cualquiera de estos propósitos:Muestra el mismo contenido para varias URL. Aprender cómo.
Realizar una función o acceder a un contenedor de Cloud Run desde una URL de hosting. Aprenda cómo: función o contenedor .
Cree un enlace dinámico de dominio personalizado. Aprender cómo.
Agregue
headers
para transmitir información adicional sobre una solicitud o respuesta, como cómo los navegadores deben manejar la página y su contenido (autenticación, almacenamiento en caché, codificación, etc.). Aprender cómo.Configure reescrituras de internacionalización (i18n) para ofrecer contenido específico según la preferencia de idioma y/o el país del usuario. Aprenda cómo (página diferente).
¿Dónde defines tu configuración de Hosting?
Usted define su configuración de Firebase Hosting en su archivo firebase.json
. Firebase crea automáticamente su archivo firebase.json
en la raíz del directorio de su proyecto cuando ejecuta el comando firebase init
.
Puede encontrar un ejemplo de configuración completo firebase.json
(que cubre solo Firebase Hosting) en la parte inferior de esta página. Tenga en cuenta que un archivo firebase.json
también puede contener configuraciones para otros servicios de Firebase .
Puede verificar el contenido firebase.json
implementado utilizando la API REST de Hosting .
Orden de prioridad de las respuestas de Hosting
Las diferentes opciones de configuración de Firebase Hosting descritas en esta página a veces pueden superponerse. Si hay un conflicto, Hosting determina su respuesta utilizando el siguiente orden de prioridad:
- Espacios de nombres reservados que comienzan con un segmento de ruta
/__/*
- Redirecciones configuradas
- Contenido estático de coincidencia exacta
- Reescrituras configuradas
- Página 404 personalizada
- Página 404 predeterminada
Si está utilizando reescrituras de i18n , la coincidencia exacta y el orden de prioridad de manejo 404 se amplían en alcance para adaptarse a su "contenido i18n".
Especificar qué archivos implementar
Los atributos predeterminados ( public
e ignore
) incluidos en el archivo firebase.json
predeterminado definen qué archivos en el directorio de su proyecto deben implementarse en su proyecto de Firebase.
La configuración hosting
predeterminada en un archivo firebase.json
se ve así:
"hosting": {
"public": "public", // the only required attribute for Hosting
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
público
Requerido
El atributo public
especifica qué directorio implementar en Firebase Hosting. El valor predeterminado es un directorio llamado public
, pero puede especificar la ruta de cualquier directorio, siempre que exista en el directorio de su proyecto.
El siguiente es el nombre especificado predeterminado del directorio a implementar:
"hosting": {
"public": "public"
// ...
}
Puede cambiar el valor predeterminado al directorio que desea implementar:
"hosting": {
"public": "dist/app"
// ...
}
ignorar
Opcional
El atributo ignore
especifica los archivos que se ignorarán durante la implementación. Puede aceptar globos de la misma manera que Git maneja .gitignore
.
Los siguientes son los valores predeterminados que los archivos deben ignorar:
"hosting": {
// ...
"ignore": [
"firebase.json", // the Firebase configuration file (the file described on this page)
"**/.*", // files with a leading period should be hidden from the system
"**/node_modules/**" // contains dependencies used to create your site but not run it
]
}
Personalizar una página 404/No encontrada
Opcional
Puede mostrar un error 404 Not Found
personalizado cuando un usuario intenta acceder a una página que no existe.
Cree un nuevo archivo en el directorio public
de su proyecto, asígnele el nombre 404.html
y luego agregue su contenido personalizado 404 Not Found
al archivo.
Firebase Hosting mostrará el contenido de esta página 404.html
personalizada si un navegador activa un error 404 Not Found
en su dominio o subdominio.
Configurar redirecciones
Opcional
Utilice una redirección de URL para evitar enlaces rotos si ha movido una página o para acortar las URL. Por ejemplo, puede redirigir un navegador desde example.com/team
a example.com/about.html
.
Especifique redireccionamientos de URL creando un atributo redirects
que contenga una matriz de objetos (llamado "reglas de redireccionamiento"). En cada regla, especifique un patrón de URL que, si coincide con la ruta de la URL de solicitud, haga que Hosting responda con una redirección a la URL de destino especificada.
Aquí está la estructura básica de un atributo redirects
. Este ejemplo redirige las solicitudes a /foo
realizando una nueva solicitud a /bar
.
"hosting": {
// ...
// Returns a permanent redirect to "/bar" for requests to "/foo" (but not "/foo/**")
"redirects": [ {
"source": "/foo",
"destination": "/bar",
"type": 301
} ]
}
"hosting": {
// ...
// Add the "redirects" attribute within "hosting"
"redirects": [ {
// Returns a permanent redirect to "/bar" for requests to "/foo" (but not "/foo/**")
"source": "/foo",
"destination": "/bar",
"type": 301
}, {
// Returns a permanent redirect to "/bar" for requests to both "/foo" and "/foo/**"
"source": "/foo{,/**}"
"destination": "/bar"
"type": 301
}, {
// Returns a temporary redirect for all requests to files or directories in the "firebase" directory
"source": "/firebase/**",
"destination": "https://firebase.google.com/",
"type": 302
}, {
// A regular expression-based redirect equivalent to the above behavior
"regex": "/firebase/.*",
"destination": "https://firebase.google.com/",
"type": 302
} ]
}
El atributo redirects
contiene una serie de reglas de redireccionamiento, donde cada regla debe incluir los campos de la siguiente tabla.
Firebase Hosting compara el valor source
o regex
con todas las rutas URL al inicio de cada solicitud (antes de que el navegador determine si existe un archivo o carpeta en esa ruta). Si se encuentra una coincidencia, el servidor de origen de Firebase Hosting envía una respuesta de redireccionamiento HTTPS indicándole al navegador que realice una nueva solicitud en la URL destination
.
Campo | Descripción | |
---|---|---|
redirects | ||
source (recomendado)o regex | Un patrón de URL que, si coincide con la URL de solicitud inicial, hace que Hosting aplique la redirección
| |
destination | Una URL estática donde el navegador debería realizar una nueva solicitud. Esta URL puede ser una ruta relativa o absoluta. | |
type | El código de respuesta HTTPS
|
Capture segmentos de URL para redireccionamientos
Opcional
A veces, es posible que necesite capturar segmentos específicos del patrón de URL de una regla de redireccionamiento ( source
o valor regex
) y luego reutilizar estos segmentos en la ruta destination
de la regla.
Si está utilizando un campo source
(es decir, especificando un global para su patrón de URL), puede capturar segmentos incluyendo un prefijo :
para identificar el segmento. Si también necesita capturar la ruta URL restante después del segmento, incluya un *
inmediatamente después del segmento. Por ejemplo:
"hosting": { // ... "redirects": [ { "source": "/blog/:post*", // captures the entire URL segment beginning at "post" "destination": "https://blog.myapp.com/:post", // includes the entire URL segment identified and captured by the "source" value "type": 301 }, { "source": "/users/:id/profile", // captures only the URL segment "id", but nothing following "destination": "/users/:id/newProfile", // includes the URL segment identified and captured by the "source" value "type": 301 } ] }
Si está utilizando un campo regex
(es decir, especificando una expresión regular RE2 para su patrón de URL), puede capturar segmentos utilizando grupos de captura RE2 con o sin nombre. Los grupos de captura con nombre se pueden usar en el campo destination
con un prefijo :
, mientras que se puede hacer referencia a los grupos de captura sin nombre por su índice numérico en el valor regex
, indexado desde 1. Por ejemplo:
"hosting": { // ... "redirects": [ { "regex": "/blog/(?P<post>.+)", // if you're familiar with PCRE, be aware that RE2 requires named capture groups to begin with ?P "destination": "https://blog.myapp.com/:post", // includes the entire URL segment identified and captured by the `regex` value "type": 301 }, { "regex": "/users/(\d+)/profile", // uses the \d directive to only match numerical path segments "destination": "/users/:1/newProfile", // the first capture group to be seen in the `regex` value is named 1, and so on "type": 301 } ] }
Configurar reescrituras
Opcional
Utilice una reescritura para mostrar el mismo contenido para varias URL. Las reescrituras son particularmente útiles con la coincidencia de patrones, ya que puede aceptar cualquier URL que coincida con el patrón y dejar que el código del lado del cliente decida qué mostrar.
También puede utilizar reescrituras para admitir aplicaciones que utilizan HTML5 pushState para la navegación. Cuando un navegador intenta abrir una ruta URL que coincide con la source
especificada o el patrón de URL regex
, en su lugar se le proporcionará al navegador el contenido del archivo en la URL destination
.
Especifique reescrituras de URL creando un atributo rewrites
que contenga una matriz de objetos (llamado "reglas de reescritura"). En cada regla, especifique un patrón de URL que, si coincide con la ruta de la URL de solicitud, haga que Hosting responda como si el servicio recibiera la URL de destino especificada.
Aquí está la estructura básica de un atributo rewrites
. Este ejemplo sirve index.html
para solicitudes a archivos o directorios que no existen.
"hosting": {
// ...
// Serves index.html for requests to files or directories that do not exist
"rewrites": [ {
"source": "**",
"destination": "/index.html"
} ]
}
"hosting": { // ... // Add the "rewrites" attribute within "hosting" "rewrites": [ { // Serves index.html for requests to files or directories that do not exist "source": "**", "destination": "/index.html" }, { // Serves index.html for requests to both "/foo" and "/foo/**" // Using "/foo/**" only matches paths like "/foo/xyz", but not "/foo" "source": "/foo{,/**}", "destination": "/index.html" }, { // A regular expression-based rewrite equivalent to the above behavior "regex": "/foo(/.*)?", "destination": "/index.html" }, { // Excludes specified pathways from rewrites "source": "!/@(js|css)/**", "destination": "/index.html" } ] }
El atributo rewrites
contiene una serie de reglas de reescritura, donde cada regla debe incluir los campos de la siguiente tabla.
Firebase Hosting solo aplica una regla de reescritura si un archivo o directorio no existe en una ruta URL que coincida con la source
especificada o el patrón de URL regex
. Cuando una solicitud activa una regla de reescritura, el navegador devuelve el contenido real del archivo destination
especificado en lugar de una redirección HTTP.
Campo | Descripción | |
---|---|---|
rewrites | ||
source (recomendado)o regex | Un patrón de URL que, si coincide con la URL de solicitud inicial, hace que Hosting aplique la reescritura
| |
destination | Un archivo local que debe existir. Esta URL puede ser una ruta relativa o absoluta. |
Solicitudes directas a una función
Puedes usar rewrites
para realizar una función desde una URL de Firebase Hosting. El siguiente ejemplo es un extracto de la entrega de contenido dinámico mediante Cloud Functions .
Por ejemplo, para dirigir todas las solicitudes de la página /bigben
en su sitio de alojamiento para ejecutar la función bigben
:
"hosting": {
// ...
// Directs all requests from the page `/bigben` to execute the `bigben` function
"rewrites": [ {
"source": "/bigben",
"function": {
"functionId": "bigben",
"region": "us-central1" // optional (see note below)
"pinTag": true // optional (see note below)
}
} ]
}
Si se omite
region
de un bloquefunction
de la configuraciónhosting.rewrites
, Firebase CLI intenta detectar automáticamente la región desde el código fuente de la función que, si no se especifica, el valor predeterminado esus-central1
. Si el código fuente de la función no está disponible, la CLI intenta detectar la región de la función implementada. Si la función está en varias regiones, la CLI requiere que se especifiqueregion
en la configuraciónhosting.rewrites
.
La función
pinTag
solo está disponible en Cloud Functions para Firebase (segunda generación). Con esta característica, puede asegurarse de que cada función para generar el contenido dinámico de su sitio se mantenga sincronizada con sus recursos de alojamiento estático y su configuración de alojamiento. Además, esta función le permite obtener una vista previa de sus reescrituras en funciones en los canales de vista previa de Hosting.Si agrega
"pinTag": true
a un bloque defunction
de la configuraciónhosting.rewrites
, entonces la función "fijada" se implementará junto con sus recursos y configuración de alojamiento estático, incluso cuando ejecute. Si revierte una versión de su sitio, la función "fijada" también se revierte.
firebase deploy --only hosting Esta función se basa en las etiquetas de Cloud Run , que tienen un límite de 1000 etiquetas por servicio y 2000 etiquetas por región. Esto significa que después de cientos de implementaciones, las versiones más antiguas de un sitio pueden dejar de funcionar.
Después de agregar esta regla de reescritura e implementarla en Firebase (usando firebase deploy
), se puede acceder a su función a través de las siguientes URL:
Tus subdominios de Firebase:
PROJECT_ID .web.app/bigben
yPROJECT_ID .firebaseapp.com/bigben
Cualquier dominio personalizado conectado:
CUSTOM_DOMAIN /bigben
Al redirigir solicitudes a funciones con Hosting, los métodos de solicitud HTTP admitidos son GET
, POST
, HEAD
, PUT
, DELETE
, PATCH
y OPTIONS
. Otros métodos como REPORT
o PROFIND
no son compatibles.
Solicitudes directas a un contenedor de Cloud Run
Puedes usar rewrites
para acceder a un contenedor de Cloud Run desde una URL de Firebase Hosting. El siguiente ejemplo es un extracto de la entrega de contenido dinámico mediante Cloud Run .
Por ejemplo, para dirigir todas las solicitudes de la página /helloworld
en su sitio de Hosting para activar el inicio y la ejecución de una instancia de contenedor helloworld
:
"hosting": {
// ...
// Directs all requests from the page `/helloworld` to trigger and run a `helloworld` container
"rewrites": [ {
"source": "/helloworld",
"run": {
"serviceId": "helloworld", // "service name" (from when you deployed the container image)
"region": "us-central1" // optional (if omitted, default is us-central1)
}
} ]
}
Con esta función, puede asegurarse de que la revisión de su servicio Cloud Run para generar el contenido dinámico de su sitio se mantenga sincronizada con sus recursos de alojamiento estático y su configuración de alojamiento. Además, esta función le permite obtener una vista previa de sus reescrituras en los canales de vista previa de Cloud Run en Hosting.
Si agrega
"pingTag": true
a un bloquerun
de la configuraciónhosting.rewrites
, sus recursos y configuración de hosting estáticos se anclarán a la revisión más reciente del servicio Cloud Run, en el momento de la implementación. Si revierte una versión de su sitio, también se revierte la revisión del servicio Cloud Run "fijado".Esta función se basa en las etiquetas de Cloud Run , que tienen un límite de 1000 etiquetas por servicio y 2000 etiquetas por región. Esto significa que después de cientos de implementaciones, las versiones más antiguas de un sitio pueden dejar de funcionar.
Después de agregar esta regla de reescritura e implementarla en Firebase (usando firebase deploy
), se puede acceder a la imagen de su contenedor a través de las siguientes URL:
Tus subdominios de Firebase:
PROJECT_ID .web.app/helloworld
yPROJECT_ID .firebaseapp.com/helloworld
Cualquier dominio personalizado conectado:
CUSTOM_DOMAIN /helloworld
Al redirigir solicitudes a contenedores de Cloud Run con Hosting, los métodos de solicitud HTTP admitidos son GET
, POST
, HEAD
, PUT
, DELETE
, PATCH
y OPTIONS
. Otros métodos como REPORT
o PROFIND
no son compatibles.
Para obtener el mejor rendimiento, coloque su servicio Cloud Run con Hosting utilizando las siguientes regiones:
-
us-west1
-
us-central1
-
us-east1
-
europe-west1
-
asia-east1
Las reescrituras en Cloud Run desde Hosting se admiten en las siguientes regiones:
-
asia-east1
-
asia-east2
-
asia-northeast1
-
asia-northeast2
-
asia-northeast3
-
asia-south1
-
asia-south2
-
asia-southeast1
-
asia-southeast2
-
australia-southeast1
-
australia-southeast2
-
europe-central2
-
europe-north1
-
europe-southwest1
-
europe-west1
-
europe-west12
-
europe-west2
-
europe-west3
-
europe-west4
-
europe-west6
-
europe-west8
-
europe-west9
-
me-central1
-
me-west1
-
northamerica-northeast1
-
northamerica-northeast2
-
southamerica-east1
-
southamerica-west1
-
us-central1
-
us-east1
-
us-east4
-
us-east5
-
us-south1
-
us-west1
-
us-west2
-
us-west3
-
us-west4
-
us-west1
-
us-central1
-
us-east1
-
europe-west1
-
asia-east1
Crear enlaces dinámicos de dominio personalizados
Puede utilizar rewrites
para crear enlaces dinámicos de dominio personalizados. Visite la documentación de Dynamic Links para obtener información detallada sobre cómo configurar un dominio personalizado para Dynamic Links .
Utilice su dominio personalizado solo para enlaces dinámicos
"hosting": { // ... "appAssociation": "AUTO", // required for Dynamic Links (default is AUTO if not specified) // Add the "rewrites" attribute within "hosting" "rewrites": [ { "source": "/**", // the Dynamic Links start with "https://CUSTOM_DOMAIN/" "dynamicLinks": true } ] }
Especifique prefijos de ruta de dominio personalizados para usar en enlaces dinámicos
"hosting": { // ... "appAssociation": "AUTO", // required for Dynamic Links (default is AUTO if not specified) // Add the "rewrites" attribute within "hosting" "rewrites": [ { "source": "/promos/**", // the Dynamic Links start with "https://CUSTOM_DOMAIN/promos/" "dynamicLinks": true }, { "source": "/links/share/**", // the Dynamic Links start with "https://CUSTOM_DOMAIN/links/share/" "dynamicLinks": true } ] }
La configuración de Dynamic Links en su archivo firebase.json
requiere lo siguiente:
Campo | Descripción | |
---|---|---|
appAssociation | Debe configurarse en
| |
rewrites | ||
source | Una ruta que desea utilizar para enlaces dinámicos A diferencia de las reglas que reescriben rutas a URL, las reglas de reescritura para vínculos dinámicos no pueden contener expresiones regulares. | |
dynamicLinks | Debe establecerse en true |
Configurar encabezados
Opcional
Los encabezados permiten al cliente y al servidor pasar información adicional junto con una solicitud o respuesta. Algunos conjuntos de encabezados pueden afectar la forma en que el navegador maneja la página y su contenido, incluido el control de acceso, la autenticación, el almacenamiento en caché y la codificación.
Especifique encabezados de respuesta personalizados y específicos de archivos creando un atributo headers
que contenga una matriz de objetos de encabezado. En cada objeto, especifique un patrón de URL que, si coincide con la ruta de URL de la solicitud, haga que Hosting aplique los encabezados de respuesta personalizados especificados.
Aquí está la estructura básica de un atributo headers
. Este ejemplo aplica un encabezado CORS para todos los archivos de fuentes.
"hosting": {
// ...
// Applies a CORS header for all font files
"headers": [ {
"source": "**/*.@(eot|otf|ttf|ttc|woff|font.css)",
"headers": [ {
"key": "Access-Control-Allow-Origin",
"value": "*"
} ]
} ]
}
"hosting": { // ... // Add the "headers" attribute within "hosting" "headers": [ { // Applies a CORS header for all font files "source": "**/*.@(eot|otf|ttf|ttc|woff|font.css)", "headers": [ { "key": "Access-Control-Allow-Origin", "value": "*" } ] }, { // Overrides the default 1 hour browser cache with a 2 hour cache for all image files "source": "**/*.@(jpg|jpeg|gif|png)", "headers": [ { "key": "Cache-Control", "value": "max-age=7200" } ] }, { // A regular expression-based rewrite equivalent to the above behavior "regex": ".+/\w+\.(jpg|jpeg|gif|png)$", "headers": [ { "key": "Cache-Control", "value": "max-age=7200" } ] }, { // Sets the cache header for 404 pages to cache for 5 minutes "source": "404.html", "headers": [ { "key": "Cache-Control", "value": "max-age=300" } ] } ] }
El atributo headers
contiene una serie de definiciones, donde cada definición debe incluir los campos de la siguiente tabla.
Campo | Descripción | ||
---|---|---|---|
headers | |||
source (recomendado)o regex | Un patrón de URL que, si coincide con la URL de solicitud inicial, hace que Hosting aplique el encabezado personalizado
Para crear un encabezado que coincida con su página 404 personalizada , use | ||
conjunto de (sub) headers | Los encabezados personalizados que Hosting aplica a la ruta de solicitud Cada subencabezado debe incluir un par | ||
key | El nombre del encabezado, por ejemplo Cache-Control | ||
value | El valor del encabezado, por ejemplo max-age=7200 |
Puede obtener más información sobre Cache-Control
en la sección Alojamiento que describe cómo ofrecer contenido dinámico y microservicios de alojamiento. También puede obtener más información sobre los encabezados CORS .
Controlar extensiones .html
Opcional
El atributo cleanUrls
le permite controlar si las URL deben incluir o no la extensión .html
.
Cuando true
, Hosting elimina automáticamente la extensión .html
de las URL de los archivos cargados. Si se agrega una extensión .html
en la solicitud, Hosting realiza una redirección 301
a la misma ruta pero elimina la extensión .html
.
A continuación se explica cómo controlar la inclusión de .html
en las URL mediante la inclusión de un atributo cleanUrls
:
"hosting": {
// ...
// Drops `.html` from uploaded URLs
"cleanUrls": true
}
Controlar las barras diagonales
Opcional
El atributo trailingSlash
le permite controlar si las URL de contenido estático deben incluir barras diagonales.
- Cuando
true
, Hosting redirige las URL para agregar una barra diagonal. - Cuando
false
, Hosting redirige las URL para eliminar una barra diagonal. - Cuando no se especifica, Hosting solo utiliza barras diagonales para los archivos de índice de directorio (por ejemplo,
about/index.html
).
A continuación se explica cómo controlar las barras diagonales agregando un atributo trailingSlash
:
"hosting": {
// ...
// Removes trailing slashes from URLs
"trailingSlash": false
}
El atributo trailingSlash
no afecta las reescrituras de contenido dinámico proporcionado por Cloud Functions o Cloud Run.
Coincidencia de patrones globales
Las opciones de configuración de Firebase Hosting hacen un uso extensivo de la notación de coincidencia de patrones glob con extglob, similar a cómo Git maneja las reglas gitignore
y Bower maneja las reglas ignore
. Esta página wiki es una referencia más detallada, pero las siguientes son explicaciones de los ejemplos utilizados en esta página:
firebase.json
: solo coincide con el archivofirebase.json
en la raíz del directoriopublic
**
— Coincide con cualquier archivo o carpeta en un subdirectorio arbitrario*
: solo coincide con archivos y carpetas en la raíz del directoriopublic
**/.*
: coincide con cualquier archivo que comience con.
(normalmente archivos ocultos, como en la carpeta.git
) en un subdirectorio arbitrario**/node_modules/**
— Coincide con cualquier archivo o carpeta en un subdirectorio arbitrario de una carpetanode_modules
, que a su vez puede estar en un subdirectorio arbitrario del directoriopublic
**/*.@(jpg|jpeg|gif|png)
— Coincide con cualquier archivo en un subdirectorio arbitrario que termine exactamente con uno de los siguientes:.jpg
,.jpeg
,.gif
o.png
Ejemplo de configuración de hosting completo
El siguiente es un ejemplo de configuración completo firebase.json
para Firebase Hosting. Tenga en cuenta que un archivo firebase.json
también puede contener configuraciones para otros servicios de Firebase .
{
"hosting": {
"public": "dist/app", // "public" is the only required attribute for Hosting
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"redirects": [ {
"source": "/foo",
"destination": "/bar",
"type": 301
}, {
"source": "/firebase/**",
"destination": "https://www.firebase.com",
"type": 302
} ],
"rewrites": [ {
// Shows the same content for multiple URLs
"source": "/app/**",
"destination": "/app/index.html"
}, {
// Configures a custom domain for Dynamic Links
"source": "/promos/**",
"dynamicLinks": true
}, {
// Directs a request to Cloud Functions
"source": "/bigben",
"function": "bigben"
}, {
// Directs a request to a Cloud Run containerized app
"source": "/helloworld",
"run": {
"serviceId": "helloworld",
"region": "us-central1"
}
} ],
"headers": [ {
"source": "**/*.@(eot|otf|ttf|ttc|woff|font.css)",
"headers": [ {
"key": "Access-Control-Allow-Origin",
"value": "*"
} ]
}, {
"source": "**/*.@(jpg|jpeg|gif|png)",
"headers": [ {
"key": "Cache-Control",
"value": "max-age=7200"
} ]
}, {
"source": "404.html",
"headers": [ {
"key": "Cache-Control",
"value": "max-age=300"
} ]
} ],
"cleanUrls": true,
"trailingSlash": false,
// Required to configure custom domains for Dynamic Links
"appAssociation": "AUTO",
}
}