Firebase 托管上单页应用程序的深度路由问题

Trouble with deep routes on a single-page app on Firebase hosting

(在下面更新了更多信息)

我们有一个基于 React 的单页 Web 应用程序,它位于 Firebase 托管上。到目前为止,我们一直在使用基于哈希的路由(例如 mysite.com/#/path/to/content)。我们引入了 React Router,它允许我们拥有更漂亮的 URLs(例如 mysite.com/path/to/content),但现在当我们直接导航到深层路由时应用程序不会加载。详情如下:

使用 React Router 需要我们在 Firebase Hosting 中使用 URL 重写。说明非常简单——似乎您需要做的就是:

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

...在 firebase.json 文件中。事实上,我们完整的firebase.json文件如下:

{
"firebase": "",
"public": "dist",
"rules": "rules.json",
"ignore": [
    "firebase.json",
    "**/.*",
    "**/*.map",
    "**/node_modules/**"
],
"rewrites": [ 
    {
    "source": "**",
    "destination": "/index.html"
    }
]
}

没什么太复杂的(如果您想知道为什么 firebase 参数为空,我们正在构建脚本中执行 firebase deploy -f)。链接到 rules.json 的文件更简单:

{
   "rules":{
   ".write":"true",
   ".read":"true"
 }
}

当我通过转至基地 URL 并开始四处导航来加载应用程序时,一切都很好。如果我直接去一个深度的路线(例如 mysite.com/path),那也行。

然而

如果我直接进入深层路线,甚至进入带有尾部斜杠的顶级路线(例如 mysite.com/path/mysite.com/path/to/content),则应用程序不会负载。

具体来说,发生的是 index.html 页面加载,然后浏览器开始加载我们在 index.html 中引用的 webpack 创建的 bundle.js 文件,但是 Firebase 托管 [该 JS 文件的 =78=]s 是 index.html 文件的内容。那么,不出所料,我们在浏览器控制台中看到的是这个错误:

Uncaught SyntaxError: Unexpected token <

...在 "bundle file" 的第 1 行。如果我在 Chrome 的开发工具中查看捆绑文件的内容,捆绑文件的第 1 行实际上是这样的:

<!doctype html>

...然后是 index.html 文件中 HTML 的其余部分。

似乎正在发生的事情是 Firebase URL 重写规则在说 "oh, you're trying to reference a JS file--I see I'm supposed to return the content of index.html for everything, so here you go"。但不可能一直如此,否则网站在任何情况下都无法正常工作。那么,为什么如果我从站点根目录开始它可以工作,但如果我将深度 URL 粘贴到应用程序,它就会中断?我的想法为零。

如果有帮助,下面是我的 index.html 文件引用捆绑文件的方式:

<script src="bundle.ce843ef7a2ae68e9e319.js"></script></body>

所以这似乎是 Firebase 托管的问题,但我也可以看出,也许我在某种程度上不了解 React Router,所以我以某种方式搞砸了客户端代码一种强制服务器 return 错误的方式。

我希望这是我们缺少的一些愚蠢的配置。感谢您的帮助!

谢谢!

更新:我剥离了我们的应用程序,使其只有 returns "hello, world",它绕过了所有基于 React 的东西,包括 React Router,但问题仍然存在,所以我没有不再认为这与 React-Router 有任何关系,尽管我认为这仍然有很小的可能性与 React 有关。

我收到了 Firebase 托管的回复。显然,索引文件中引用的 bundle.js 文件需要在其前面加一个斜线,以使其成为绝对路径。所以这个:

<script src="/bundle.js"></script>

...而不是这个:

<script src="bundle.js"></script>

以防其他人犯同样的愚蠢错误,我希望这对您有用。

[tl;dr]

This answer is only for educational purposes and in-depth insight to the problem statement and its solution. For copy/paste purposes see . It is the short version and answers the question simply and nicely

每个link图片资源,css,js可以通过3种方式引用:

1) 绝对路径

<script src="http://app-url.com/bundle.js"></script>

这是绝对路径,资源将从指定路径加载,无需对提供的路径进行预处理。

2) 相对路径

<script src="bundle.js"></script>

这是相对路径,它指的是资源文件,就像它位于当前工作目录中一样。也就是说,当您在 app-url.com/lvl-1 上时,相对路径变为 app-url.com/bundle.js,这没有问题,因为那实际上是资源的路径。

问题

但是在进入另一个深度时,即 app-url.com/lvl-1/lvl-2,当前工作级别变为 app-url.com/lvl-1/ 并且相对路径被视为 app-url.com/lvl-1/bundle.js 但这实际上不是资源路径。因此 index.html 文件行为不当,因为它无法加载所需的文件。

3) 根目录相对路径

<script src="/bundle.js"></script>

在相对路径前加一个斜线(/) 使其成为根相对路径。在这种情况下,所有非绝对路径都被视为以当前域为根的路径。也就是说,在这种情况下,资源 /bundle.js 的路径被视为 app-url.com/bundle.js,即使 url 的当前工作级别是 app-url/lvl-1/lvl-2/lvl-3/...

Solution Do not use ~relative paths~. Either use absolute paths or root relative paths in all files. This way every path will be treated as expected.

我遇到了同样的问题,我修复了向 firebase.json 文件添加重写规则的问题。

这是我的 firebase.json 文件的样子。

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

对不起我的英语,我还在学习。

我遇到了相同的行为,但问题与 bundle.js 无关。

我在 firebase.jsonrewrites 部分看起来像这样:

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

我通过使用 根相对路径 而不是 index.html 相对路径 解决了这个问题。 (感谢阿舒!)

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