Search code examples
firebasefirebase-hosting

Firebase hosting: rewrite rule failing when there is no trailing slash


I'm hosting two SPAs (that are built separately) in Firebase Hosting. My build process generates a directory structure like this:

/build
|
|-- index.html
|-- scripts.js
|-- style.css
|
|--- /app
     |
     |-- index.html
     |-- scripts.js
     |-- style.css

If I connect my domain, example.com, I would like https://example.com to serve the first SPA and https://example.com/app to serve the second SPA.

Also, I would like that every address of the form https://example.com/xxx was rewritten to https://example.com/index.html if the file doesn't exist and, similarly, everything pointing to https://example.com/app/xxxwas rewritten to https://example.com/app/index.html.

I managed to make it work with the following configuration:

{
  "hosting": {
    "public": "build",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "app/**",
        "destination": "/app/index.html"
      },
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}

but now, when I go to https://example.com/app WITHOUT SLASH, it serves the "root" SPA. If I instead go to https://example.com/app/ WITH SLASH, it serves the "nested" SPA as it should.

How can I make https://example.com/app serve the "nested" SPA?

WHAT I TRIED

  • Setting trailingSlash to true and false, respectively. No change. (see docs here)

  • Setting a 301 redirect in the configuration from https://example.com/app to https://example.com/app/. The site dies in my Chrome with Too many redirects.

Any ideas on what I'm doing wrong?


Solution

  • It doesn't look like there's a way to do this with a single rewrite rule.

    You'll need to add two rewrites, one for app, and another for app/.

    "rewrites": [
        {
            "source": "/app",
            "destination": "/app/index.html"
        },
        {
            "source": "/app/**",
            "destination": "/app/index.html"
        },
        {
            "source": "**",
            "destination": "/index.html"
        }
    ]