【问题标题】:Problems mounting a Vercel/Nextjs project as a subdirectory of a different Vercel/Nextjs project将 Vercel/Nextjs 项目安装为不同 Vercel/Nextjs 项目的子目录时出现问题
【发布时间】:2022-09-30 14:43:39
【问题描述】:

我有一个带有两个项目的 monorepo - webdocs。这些都是他们自己的 Vercel 项目,web 项目安装在 https://example.comdocs 安装在 https://docs.example.com。所有这些都按预期工作。

我现在想在https://example.com/docs 上提供docs 项目。在web 项目中,我在vercel.json 文件中设置了以下重写。

{
  \"rewrites\": [
    {
      \"source\": \"/docs/:match*\",
      \"destination\": \"https://docs.example.com/:match*\"
    },
    { \"source\": \"/(.*)\", \"destination\": \"/\" }
  ]
}

这适用于主索引文件,但所有相应的 css 和 js 文件都会导致 404\'s。浏览器在https://example.com/_next 寻找那些不正确的文件,它应该在https://docs.example.com/_next 寻找。

我该如何进行这项工作?

  • 您是否考虑过在文档应用程序中设置basePath
  • 我无法将webdocs 项目都设置为example.com。如果我在docs 应用程序中使用basePath,docs 应用程序将只是植根于docs.example.com/docs,这不是我想要的。
  • 在两个位置拥有相同的内容是不好的做法。选择 docs.example.com 或 example.com/docs 作为正确的位置。为此位置设置正确的 basePath。然后使用重定向而不是从另一个位置重写到这个位置。
  • @some-user 是的,这就是我真正想要的。我不知道如何让它工作。我无法将这两个项目都设置为在 example.com 上托管,所以我将一个项目设置为 docs.example.com,以为我可以重定向它。您能否更明确地说明每个项目应该使用什么域以及重写应该是什么?

标签: next.js url-rewriting vercel


【解决方案1】:

rewriteredirect

我们先来了解一下这个区别。

rewrite 是仅在服务器上发生的事情。服务器将重写已请求的 URL 并搜索该重写 URL 的内容。客户对此一无所知。例如。如果 /a.html 被重写为 /b.html,客户端将在两个 URL 上收到相同的内容。客户端不知道是否有两次相同的文件,或者是否一个(或两个)请求已被重写到其他资源。

另一方面,redirect 涉及客户端(即浏览器)。如果要求服务器提供应重定向的 URL,它将使用重写的目标 URL 回复客户端/浏览器。然后,客户端将发送新 URL 的另一个请求,并通过更改导航栏中的地址使最终用户可以看到它。如果 /a.html 被重定向到 /b.html,客户端在请求 a.html 时将不会收到 b.html 的实际内容,但浏览器会将地址更新为 b.html 并发送新的请求。

在您的情况下,重写有什么问题?

HTML 包含对使用绝对路径的其他资源的引用,例如就像是:

<script src="/_next/static/..."></script>

如果此文件应作为docs.example.comexample.com/docs 提供(例如使用重写),实际的HTML 不会改变。浏览器将因此尝试分别访问docs.example.com/_next/static/...example.com/_next/static/...。这适用于第一种情况(docs.example.com),但不适用于第二种情况。你已经注意到了。

您可以更改下一个的basePath,例如到/docs。然后 HTML 将包含&lt;script src="/docs/_next/..."&gt;。这将使浏览器分别请求docs.example.com/docs/_next/...example.com/docs/_next/...。这适用于第二种情况,但不适用于第一种情况。您可以使用更多的重写规则来治愈第一种情况,但我建议使用 KISS 解决方案。

怎么办?

如 cmets 中所述,将完全相同的内容放在两个不同的地址不是好的做法。你可以看到,这也导致了后续的困难。 (更不用说搜索引擎对重复内容的惩罚了。)

一个好的解决方案是决定在哪里存储内容。那应该是docs.example.comexample.com/docs,而不是两者。

使用 docs.example.com,将 example.com/docs/ 转发到 docs.example.com

我建议(并在本节中假设)采用docs.example.com 明确分离关注点。

因此,在 Vercel 中,您将设置两个项目。一个用于您的“主要”下一个实例,另一个用于“文档”下一个实例。 (两者都可以来自同一个仓库,没关系。)

然后,您将域分配给两个项目,例如www.example.com 到“主”项目,docs.example.com 到“文档”项目。 example.comdocs.example.com 现在应该可以工作了。 example.com/docs/ 应该会产生 404 错误。

然后通过添加vercel.json 为您的“主”项目添加重定向(而不是重写!),如下所示:

{
  "redirects": [
    { "source": "/docs/:path*", "destination": "https://docs.example.com/:path*" }
  ]
}

现在,如果您在浏览器中输入example.com/docs/foo,您应该会被重定向到docs.example.com/foo,并且页面应该可以正常加载。

仅使用 example.com/docs/

如果您决定仅将文档内容放在example.com/docs/,则解决方案如下:

  • basePath: '/docs' 添加到文档下一个项目的next.config.js。不要向这个 vercel 项目添加域。
  • 在“main”下一个项目中添加vercel.json,重写如下:
{
  "rewrites": [
    { "source": "/docs", "destination": "https://$domain-of-docs-project.vercel.app/docs" },
    { "source": "/docs/:path*", "destination": "https://$domain-of-docs-project.vercel.app/docs/:path*" }
  ]
}

如果您有其他问题或这不能解决问题,请发表评论。

【讨论】:

  • 酷,该重定向有效。如果我只想要example.com/docs 的内容,我该怎么做?
  • 我扩展了上面的解决方案以涵盖这种情况。
  • 谢谢。我将基本路径添加到docs 项目并删除了域(只保留了example-docs.vercel.app。然后我将重写添加到main 项目的vercel.json 文件中。现在当我转到example.com/docs 我得到此页面无法正常工作。重写太多了。.
  • 如果我从docs 项目中删除基本路径并将重写的目标指向https://example-docs.vercel.app/:path*,则重写工作,但它正在寻找https://example.com/_next/static/css 中的css 和其他资产,而不是https://example-docs.vercel.app/_next_static/css
  • 我添加了另一个重写规则可能会解决重定向问题,即使我无法重现它。请检查您的 vercel/next 配置以获取不应该存在的其他重定向。
【解决方案2】:

我认为你可以使用vercel.json像这样:

{
  "rewrites": [
    {
      "source": "/:path*",
      "has": [
        {
          "type": "host",
          "value": "docs.example.com"
        }
      ],
      "destination": "/docs/:path*"
    }
  ]
}

【讨论】:

  • 这对我不起作用。当我点击example.com/docs 时,我最终得到了 404。
【解决方案3】:

接下来提供了一个具体的例子。

您的“网络”项目应该处理重写,如 here 所示。 next.config.js:

const { DOCS_URL } = process.env //this should be the vercel URL NOT docs.example.com

/** @type {import('next').NextConfig} */
module.exports = {
  async rewrites() {
    return [
      {
        source: '/:path*',
        destination: `/:path*`,
      },
      {
        source: '/docs',
        destination: `${DOCS_URL}/docs`,
      },
      {
        source: '/blog/:path*',
        destination: `${BLOG_URL}/docs/:path*`,
      },
    ]
  },
}

您的“文档”应用程序需要设置一个基本路径,如 here 所示。 next.config.js:

    module.exports = {
      basePath: '/docs',
    }

然后,为了确保 docs.example.com 不再为文档提供服务,我只需删除 DNS 记录。相反,您将只有一个 vercel URL,您将在“web”中的重写中使用它。无需从 docs.example.com 指向该服务器。

Nextjs documentation for multi-zone

Nextjs example with multi-zones

【讨论】:

  • 这适用于除docs 项目中的/public 文件夹之外的所有内容。图像和字体都返回 404。它正在example.com/docs/_next/… 寻找他们。关于如何解决这个问题的任何想法?
  • 这些字体和图像是来自文档应用程序还是主应用程序?似乎“baseUrl”可能不会公开。试试这个,添加:{ source: '/docs/_next/:path*', destination: '${BLOG_URL}/_next/:path} 到你的 next.config.js
猜你喜欢
  • 2020-12-06
  • 2022-01-11
  • 2023-02-24
  • 2021-02-08
  • 2022-01-02
  • 2023-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多