Next.js: 功能要求:基本路径支持

创建于 2018-08-21  ·  73评论  ·  资料来源: vercel/next.js

功能要求

您的功能请求是否与问题有关? 请描述。

多区域是一项很棒的功能,它允许在同一域上运行多个next.js应用程序,但是它不允许定义将被next.js的所有部分接受的基本路径。 由于我们现在无法为应用程序命名空间,因此无法在各种应用程序中为页面使用相同的名称。

描述您想要的解决方案

我希望能够在next.config.js文件中配置basepath 。 由于有了此配置,next.js的所有部分(路由器,链接,静态资产等)都将了解基本路径,并将自动生成并匹配正确的路径。

描述您考虑过的替代方案

一种选择是将所有需要的页面嵌套到与基本路径匹配的文件夹中。 这仅解决了路由中的一个小问题,并且非常丑陋,因为我的大多数基本路径都不是一级路径。
第二个替代方案是以某种方式配置代理,该方式是在请求到达next.js应用程序之前自动删除基本路径,并且还实现一个自定义链接组件,该组件自动将基本路径添加到所有链接。 我只是不想维护next.js的自定义派生。 我认为这没有道理。

其他背景

assetPrefix解决方案使我们可以为每个应用程序定义一个不同的前缀。 但据我所知,它仅适用于不同的主机。

带区域示例

module.exports = {
  assetPrefix: NOW_URL ? `https://${alias}` : 'http://localhost:4000'
}

如果我向其添加基本路径,一切都会失败

module.exports = {
  assetPrefix: NOW_URL ? `https://${alias}/account` : 'http://localhost:4000/account'
}

screen shot 2018-08-21 at 10 47 08

我认为我们应该将其分为两个变量:

module.exports = {
  assetPrefix: NOW_URL ? `https://${alias}` : 'http://localhost:4000',
  basepath: '/account'
}

相关问题

story needs investigation

最有用的评论

关于此事的任何更新...去年大约这个时候,我遇到了这个问题。 一年后的今天,我正在开发一个新的应用程序,并且必须执行与去年相同的解决方法...有点“生产就绪”的预警。 基本路径应该是一种基本功能。

发布此内容后,我不确定您的期望。

我的团队(5人)正在全职工作Next.js,我们同时正在开发许多功能。 在过去的一年中,我们致力于以下方面:

有效地使Next.js应用程序(新的和现有的)显着缩小,更快并且更具可伸缩性。

如果您想为某个功能表达自己的“赞”,可以。 在初始线程上使用👍功能。

我绝对同意basePath应该是内置功能。 它已经在路线图上了,我什至写了一个初始PR,您可以通过回读线程来查看。

这是PR: https :

如果您想在财务上为实现此功能做出贡献,请随时与[email protected]联系

所有73条评论

cc @jxnblk

抄送@alexindigo @DullReferenceException

希望收到您的反馈👍

在玩完代码之后,我意识到将assetPrefix分成多个部分会容易得多:

module.exports = {
  host: NOW_URL ? `https://${alias}` : 'http://localhost:3000',
  basePath: '/account',
}

我们仍然可以将assetPrefix变量保留在内部,但用户应更精确地定义他需要的内容。

因为资产部分真的可以将这两个变量一起提供。
对于路由等,我们分别需要它们。
也许我们甚至可以将其一起提供在配置文件中,然后将其拆分到next.js代码库中。 在这种情况下,恐怕assetPrefix不是正确的名称。

作为副作用,这也导致较少的代码更改。
如果比较这两个PR,这是很明显的:
https://github.com/panter/next.js/pull/2 (拆分)
https://github.com/panter/next.js/pull/1 (同时通过)

在我看来,它们应该是分开的,其原因是保持assetPrefix并分别拥有basePath不会破坏并且更灵活。

那么assetPrefix是正确的名称吗? 这两个变量实际上都是前缀吗?

assetPrefix用于资产,例如:页面捆绑。 basePath将用于路由器。

它应该工作的方式是:

  • 如果定义了assetPrefix ,请使用assetPrefix加载捆绑包,请勿触摸路由器(当前行为)
  • 如果提供了assetPrefixbasePath ,请使用assetPrefix加载捆绑包,将basePath到路由器
  • 如果未定义assetPrefixbasePath是,请使用basePath加载捆绑包,然后向路由器添加basePath
  • 如果未定义assetPrefixbasePath ,我们不会做任何改变(未提供assetPrefix时的当前行为)

抄送@alexindigo @DullReferenceException @ 3rd-Eden

您能否对上述建议提供反馈: https :

@tomaswitek不确定当前assetPrefix到底对您不起作用,这是我们在生产中使用的资产前缀: "assetPrefix":"https://static.trulia-cdn.com/javascript" ,它可以按预期工作。

通常,我们在同一个域上使用多个区域(我们称它们为“岛”),每个岛永远都不会想到“ basePathing”,因为这会使岛之间的互操作性复杂化。 让我详细说明一下:

因此,我们有两个岛屿AB ,其主要思想是作为一个网站体验的一部分,用户在一个岛到另一个岛之间导航时的透明度。 因此,各岛之间应该有联系。 然后是部署问题与应用程序问题。

  1. 部署问题与应用程序问题–应用程序不知道可以将其部署在哪里,它只知道如何处理传入的http请求–已经确定了可以响应的路由。
    当它部署在某个地方时-可能是不同的域,不同的端口,并且从理论上讲,它可能是不同的basePath,这将通过代理或其他方式对应用程序透明。

  2. 孤岛之间的交叉链接–为了保持孤岛的精神作为独立的可部署实体,在不同孤岛之间不应存在任何内部实施知识泄漏。
    因此,孤岛互相引用页面的最佳方法是让它们导出可供其他孤岛使用的可用路由(_在nextjs世界中,自定义<IslandALink>种组件将是首选道路_)。
    到目前为止,一切都是直截了当的-所有孤岛都假定共享同一域并具有其绝对路径集( /path1path2等)。 这样,第二岛会导入该路径列表并依靠它来保持稳定。 同时,每个岛屿保持其路径向后兼容的要求非常低(无论如何,这在网络上是一件好事):)

当添加特定于部署的basePath时,我们会自动增加整个系统的复杂性–每个孤岛是否应该知道(也许决定)它自己的部署basePath? 那和目前的工作方式有何不同? 还是应该忽略A岛的部署路径? 那么,由于岛B只知道岛A自己知道什么,岛B将如何找到已部署的岛A? 还是必须为所有已部署的孤岛和所有其他孤岛提供basePath? 借助现代的部署方式,这意味着当您需要添加新的孤岛时,可以重新部署所有孤岛。

还是您如何设想故事的那一部分?

谢谢。

^它是在早上喝咖啡之前写的,所以如果您需要对其中任何部分进行更连贯的解释,请告诉我。 :)

首先,谢谢您花时间来审查我的问题。

@timneutkensassetPrefix优先级高于basePath ,这正是我们在开始时所讨论的。 在看到必须更改的文件数量之后,我认为第二种方法更干净。 但是,我将回滚到第一个解决方案。 让我们将其完全分开,完全没有问题。 我只是在大声思考。

@alexindigo Thx为您提供详细答案。 让我试着回答你的问题😏

不确定当前的AssetPrefix到底对您不起作用

我在这里有两个问题:

  1. 我无法在当前项目中使用多个域或子域。 (域限制,没有通配符SSL证书)
  2. 当前assetPrefix在单个域上的实现需要对代理路由,静态文件等进行更多调整。我们可以通过引入basePath来减少这种调整。 它不会刹车,也不会增加复杂性,因为您不必像@timneutkens那样提供basePath

应用程序不知道可以在哪里部署

我们当然有相同的目标! 我们在现有的解决方案中动态定义assetPrefixes。 它是通过代理通过请求标头提供的。

那和目前的工作方式有何不同?

路由器将意识到contextPath,并将减少自定义代码的数量。

每个孤岛是否应该知道(也许决定)它自己的部署basePath? 还是应该忽略A岛的部署路径?

不一定是。 开发人员在这里应该有自由。 应该有可能以与assetPrefix相同的方式动态地提供basePath。

那么,由于岛B只知道岛A自己知道什么,岛B将如何找到已部署的岛A? 还是必须为所有已部署的孤岛和所有其他孤岛提供basePath? 借助现代的部署方式,这意味着当您需要添加新的孤岛时,可以重新部署所有孤岛。

也许您也可以将basePath添加到路由导出中。 我不知道。 我并不是说basePath变量对于每个用例都很重要。 看来这不是最适合您的解决方案。 但这完全没问题。 事实是,您仍然只能使用assetPrefix ,而您的岛屿将保持不变。 看来您仍然拥有自己的路由。 区域之间的交叉链接对于我们的项目甚至都不重要,因为我们的区域实际上是独立的并且彼此隔离。

借助现代的部署方式,这意味着当您需要添加新的孤岛时,可以重新部署所有孤岛。

我看不出原因。 我什至可以想象有些区域具有basePaths,而有些则没有。 甚至某些应用程序即使没有多区域设置也将使用basePath配置。

@alexindigo您能为我们提供两个真实的岛URL,这些URL由next.js呈现,以便我可以看到它在起作用吗? 我试图找到一个,但在您的域中找不到带有_next请求的页面😄
您所有的岛屿都具有相同的配置吗?
"assetPrefix":"https://static.trulia-cdn.com/javascript"

@tomaswitek

我无法在当前项目中使用多个域或子域。 (域限制,没有通配符SSL证书)

哦,所以您不是传统意义上的CDN,而是直接从每个应用程序中获取资产吗? 我懂了。

当前在单个域上实现assetPrefix的情况需要对代理路由,静态文件等进行更多调整。我们可以通过引入basePath来减少这种调整。 它不会刹车,也不会增加复杂性,因为您不必像@timneutkens一样提供basePath。

顺便说一句,这不是“不,不要添加该功能” :)它更像是–“也许我们可以更全面地考虑这种方法” :)

不一定是。 开发人员在这里应该有自由。 应该有可能以与assetPrefix相同的方式动态地提供basePath。

是。 仅当岛之间没有链接时,它才起作用。 听起来这是您的用例。 同时,我很难理解是什么使它们成为孤岛,而不是仅仅是一堆独立的应用程序,如果它们是100%独立的呢? :)

也许您也可以将basePath添加到路由导出中。

由于路由导出是在构建时发生的,而basePath是在部署时定义的,并且同一代码工件(阶段,preprod,prod,测试环境等)。


您所有的岛屿都具有相同的配置吗?
“ assetPrefix”:“ https://static.trulia-cdn.com/javascript

是的,所有孤岛都共享其资产,因为接下来进行内容哈希处理,这不仅不是问题,而且实际上是非常有益的。 (我们从每个工件中提取构建的资产,并在部署时发布在CDN上)。

这样,我们只有对应用服务器的“常规html”请求,这就是为什么我在trulia.com上看不到任何“ _next”路径的原因

至于岛屿的例子:

我们全新的全新岛屿–邻居页面– https://www.trulia.com/n/ca/san-francisco/pacific-heights/81571 (您可以在此处找到更多信息:http://www.trulia。 com / neighbourhoods)
该岛负责所有/n/*路径。

另一个孤岛是我们的登录页面– https://login.trulia.com/login –它看起来像不同的域,但实际上并非如此,出于各种原因它看起来像是这样,但是从技术上讲,它是相同的部署。 :)
这个岛可以处理/login/signup类的网址。

如果您还有其他问题,请告诉我。

@alexindigo非常感谢您的示例。
对示例进行分析后,我有几个问题😄

您仍然为每个孤岛执行服务器渲染,但是您尝试将尽可能多的资产提取到一个普通的CDN中,对吗?

您能否描述一下调用https://www.trulia.com/n/ca/san-francisco/pacific-heights/81571时发生的情况? 您的代理人是否知道/n代表社区概览并将其转发到正确的岛屿? 它会在到达岛之前以某种方式影响请求吗?

您是从岛屿内部的下一个位置使用内置路由,还是有自定义解决方案?
我想检查您岛内的路线。 不幸的是, Neighborhood overview或多或少只是模态导航而没有更改url。 在登录中似乎有一个完全自定义的解决方案。

我希望我会在此评论中回答您所有的问题😏

顺便说一句,这不是“不,不要添加该功能” :)它更像是–“也许我们可以更全面地考虑这种方法” :)

当然,找到不必触摸next.js的解决方案将是很棒的😏

是。 仅当岛之间没有链接时,它才起作用。 听起来这是您的用例。 同时,我很难理解是什么使它们成为孤岛,而不是仅仅是一堆独立的应用程序,如果它们是100%独立的呢? :)

我从未写过,也没有说过我在寻找“孤岛”解决方案。 我刚刚与@timneutkens聊天,描述了我的问题,Tim的回答基本上是next.js不支持基本路径。 经过一番谷歌搜索之后,我意识到我并不是唯一一个正在寻找它的人。 所以我认为我可以有所作为。 之后,Tim ping您给我一个反馈,我非常感谢您的反馈。

由于路由导出是在构建时发生的,而basePath是在部署时定义的,并且同一代码工件(阶段,preprod,prod,测试环境等)。

好吧,如果您想在构建时导出路由并使它们可用于其他孤岛,则唯一直接的方法可能是在配置中对basePath进行硬编码。 我明白你的意思。 另一方面,这真的是一个问题吗? 您仍然可以将应用程序部署到不同的域和端口,并且可以对每个环境使用相同的basePath。

早上好@tomaswitek :)

我在使用“ basePath”功能时的经验非常复杂,这很容易让人误解,通常最好实施此类事情而不必急于解决一个特定的问题,
但是从多个角度来看它。 与您要进行深度合并的方式类似–概述多个用例,并查看它们如何(以及是否)全部归于一类。 由于该框架(甚至主要版本)之间具有不兼容的功能,这非常令人讨厌:)

您仍然可以将应用程序部署到不同的域和端口,并且可以对每个环境使用相同的basePath。

听起来您可以接受解决方案,其中“ basePath”是路由代码的一部分,您在一开始就提到了这一点–例如pages目录中的子文件夹(顺便说一句,这种方法将向开发人员发出信号basePath相当不错)。 但是,唯一使您停滞的是资产_next内部nextjs路径不可配置。

这听起来像是更狭窄的问题,我们可以用较少的长期副作用来解决。

而且它可以使我们走得更远,例如是否可以为每个资产配置assetPath(例如,使用某种next.config映射)–它将使我们能够在应用程序之间拥有共享资产,从而提高性能等。

并且该功能具有开放式PR。 ;)/ cc @timneutkens听起来是时候该回到那只小狗了。 :)

如果您不打算在不久的将来添加此代码,我们是否可以在自述文件中添加一个基于express的示例server.js来实现此功能并起作用? 我已经尝试过一些在这些问题上四处徘徊的方法,但无法使它们起作用。 谢谢。

@ccarse我有一个工作叉,我们已经在生产中使用它了: https :
我也准备花费时间为该功能打开PR。
@timneutkens @alexindigo还有另一种方法可以解决这个问题吗?
如果我们不需要basePath配置,您可以使用assetPath给我们一个简单的例子吗?

我的公司也对此表示反对。

我们正在逐步地逐步接管旧版应用程序,并将其替换为Next.js。

作为简化示例:

| 网址| 应用程式|
| --- | --- |
| example.com | 遗产|
| example.com/shop | 下一个|
| example.com/search | 遗产|
| example.com/members | 下一个|

这意味着我们希望所有内容都在每个Next.js应用程序中作为前缀...页面,路线,资产等。

还值得注意的是,我们没有使用Now,因此我们无法利用now.json路由。 我们有自己的负载平衡器位于整个域的前面,然后根据子路径路由流量。

我们还使用了自定义服务器(hapi),因此,如果我们也可以利用自定义服务器中在此处创建的内容,那就太好了。

也许有now.config.json设置的某种组合,或者可以使用微代理来完成同一件事,但是我们还没有找到正确的组合。

我认为,在Now v2上托管的多个静态导出的Next.js应用程序遇到了相同的问题。

| 网址| 应用程式|
| -| -|
| example.com | 下一个|
| example.com/dashboard | 下一个|

如预期的那样,根应用程序可以正常工作。 不过,第二个问题出了问题。 我们目前正在包装next/link ,结合assetPrefix可以解决大多数问题:

export default ({ children, href, ...rest }) => (
      <Link href={process.env.NODE_ENV === "production" ? `/dashboard${href}` : href} {...rest}>
        {children}
      </Link>
);

但是,这会破坏prefetch因为它随后尝试在错误的URL处查找.js文件:

  • 实际文件URL: https :
  • 预提取的文件网址: https :

我们当前的解决方法是禁用prefetch ,这并不理想。

这是什么状态?

还请寻找对此的更新。

@timneutkens如果社区有兴趣,我准备花时间为它建立PR。 我们已经在生产中使用了解决方案(https://github.com/panter/next.js/pull/1),对此我们感到非常满意。

我们还需要一个解决方案

我们将很快引入新的API,这将使该提案过时。

也受此影响。 需要在子目录路径下运行下一个项目。 期待正式的功能。 是否有预计到达时间?

API

怎么样了? :D

请不要对该主题发送垃圾邮件,并在问题本身上使用GitHub的👍功能。

@timneutkens您能提供更多信息吗? 什么API将使它过时? 您认为“很快”是什么? 谢谢。

这可能与多区域不完全相关,但可能会有所帮助...

我通过创建自定义服务器并使用代理中间件解决了与此类似的问题

例如:@Zertz
请注意:您仍然需要解决链接问题-再次,我通过创建一个链接组件并通过config将前缀向下传递给应用程序来解决此问题,如果存在前缀,则对静态图像使用该前缀或不使用该前缀。

const proxy = require('http-proxy-middleware');

app.setAssetPrefix('/dashboard');

  // Express custom server
  // Proxy so it works with prefix and without...
  // So if asset prefix is set then it still works
  const server = express();
  server.use(
    proxy('/dashboard', {
      target: 'http://localhost:3000', 
      changeOrigin: true,
      pathRewrite: {
        [`^/dashboard`]: '',
      },
    }),
  );

我提到的建议是#7329

我提到的建议是#7329

@timneutkens
您能否提供有关拟议的钩子如何解决我们的基本路径问题的更多详细信息?
那么像Router.push('/about')这样的路由器重定向又会被钩替换吗?

谢谢您的时间😏

路由器api也将更改,因为它需要一个链接到的组件。 那时,您可以为URL本身使用相对路径。

关于何时可以获得解决方案或至少可以解决此问题的任何更新?

在初始问题上使用instead,而不要发布任何更新。

@ MMT-LD您的解决方案适合我,但是现在在每次“链接”单击或“路由器”推送事件中,页面都会重新加载☹️

我尝试了@Zertz的解决方案,它运行完美!
我也可以通过将输出文件复制到预取的路径来解决prefetch问题。
https://github.com/fand/MDMT/blob/master/scripts/copy-preload.js

...这是一个肮脏的把戏,但无论如何都在起作用🤪

@nicholasbraun

现在在每次链接单击或路由器推送事件上页面都会重新加载☹️

我遇到了这个问题,但是使用链接上的“ as”参数进行了修复,因此链接指向内部文件,但是“ as”相对于路径
例如:
<Link href={"/${item.link}"} as={"./${item.link}"}>

@nicholasbraun

您的解决方案适合我,但现在在每次“链接”点击或“路由器”推送事件中,页面都会重新加载☹️

这就是我的意思。 这是从内存中来的。。。。但是我不确定您不能从下面获得所需的信息。

// WithConfig component
import getConfig from 'next/config';

const { publicRuntimeConfig } = getConfig();

const WithConfig = ({ children }) =>
  children && children({ config: publicRuntimeConfig });

export default WithConfig;
// Extended Link component

 import React from 'react';
import PropTypes from 'prop-types';
import Link from 'next/link';
import { WithConfig } from '../WithConfig';
/* 
    <Link> component has two main props:
    href: the path inside pages directory + query string. e.g. /page/querystring?id=1
    as: the path that will be rendered in the browser URL bar. e.g. /page/querystring/1

*/

const NextLink = ({
  browserHref,
  pagesHref,
  whatever,
}) => {
  return (
    <WithConfig>
      {({ config: { pathPrefix } = {} }) => (
        <Link
          as={pathPrefix ? `${pathPrefix}${browserHref}` : browserHref}
          href={pagesHref}
          passHref
        >
          <a>{whatever}</a> // this bit is up to you - children or whatever
        </Link>
      )}
    </WithConfig>
  );
};

NextLink.propTypes = {
  browserHref: PropTypes.string.isRequired,
  pagesHref: PropTypes.string,
};

NextLink.defaultProps = {
  pagesHref: undefined,
};

export default NextLink;

用法:

import NextLink from '../NextLink'

<NextLink browserHref={`/page/1`} pagesHref={`/page?querystring=1`} whatever='I'm the link' />

祝你好运:笑脸:

由于useLink RFC现在已被拒绝(#7329),并且具有basePath支持将极大地帮助我们,Next.js项目是否乐于接受实施它的PR? 我愿意做。

通过@tomaswitek查看此实现,它似乎朝着正确的方向发展,最重要的是使路由器意识到basePath 。 还有其他非显而易见的事情会使basePath支持变得困难吗?

总的来说,我认为设计很清晰,只是一个配置变量:

module.exports = {
  basePath: '/demo'
}

assetPrefix交互在此处定义良好: https


更新:我也在考虑是否可以通过创建自定义路由器并以某种方式交换默认路由器来实现这一点,但似乎不可能,Next.js对其路由器进行硬编码,请参见此处。 我也怀疑“仅”更换路由器就足够了。 该功能可能需要整体由Next.js支持。

自2017年以来就存在此问题,是否有任何解决方法? 还是对我们的basePath请求的正式回复?

因此,在尝试使用assetPrefix和自定义<Link>组件的组合使其工作之后,例如在https://github.com/zeit/next.js/issues/4998#issuecomment中建议-464345554或https://github.com/zeit/next.js/issues/4998#issuecomment -521189412,很遗憾,我不认为可以做到。

定义assetPrefix相对简单,在next.config.js类似这样:

const assetPrefix = process.env.DEPLOYMENT_BUILD ? '/subdir' : '';

module.exports = {
  assetPrefix,
  env: {
    ASSET_PREFIX: assetPrefix,
  },
}

下一步是自定义Link组件。 例如,在https://github.com/zeit/next.js/issues/4998#issuecomment -464345554中给出的第一个想法是像这样(简化)添加href前缀:

export default ({ children, href, ...rest }) => (
  <Link href={`${process.env.ASSET_PREFIX}${href}`} {...rest}>
    {children}
  </Link>
);

正如该线程中的其他人所报告的那样,这会中断预取,因为请求突然到达/ subdir /_next/static/.../pages/ subdir /example.js –另一个“ subdir”不应存在。 但是,使用我们自定义的Link组件,我们将href设置为/subdir/example ,所以难怪Next.js正在请求捆绑pages/subdir/example.js页面。

好的,有问题的预取听起来并不像世界末日(尽管UX相当丑陋),但是在我们的应用程序中,由于我们使用Next.js 9的动态路由,情况变得更糟。 为此,我们需要正确设置as ,以便自定义Link组件的演变如下所示:

export default ({ children, href, as, ...rest }) => (
  <Link 
    href={`${process.env.ASSET_PREFIX}${href}`}
    as={`${process.env.ASSET_PREFIX}${as}`}
    {...rest}
  >
    {children}
  </Link>
);

用法是:

<CustomLink href='/post/[id]' as='/post/1'>...</CustomLink>

转换为:

<Link href='/subdir/post/[id]' as='/subdir/post/1'>...</Link>

并且在“立即”上部署时,这对我不起作用–尝试导航到https://deployment-id.now.sh/subdir/post/1导致404。我不确定为什么,也许这也是@now/next器的问题更新:这是因为https://github.com/zeit/next.js/pull/8426#issuecomment-522801831),但最终,当我们要求/subdir/post/[id]时,我们混淆了Next.js的路由器如果磁盘上不存在这样的文件,则使用

此线程中还有另一个示例, https: //github.com/zeit/next.js/issues/4998#issuecomment -521189412,仅以不是href

export default ({ children, href, as, ...rest }) => (
  <Link href={href} as={`${process.env.ASSET_PREFIX}${as}`} {...rest}>
    {children}
  </Link>
);

但这将在浏览器中引发此错误:

您的<Link>as值与href值不兼容。 这是无效的。

这是https://github.com/zeit/next.js/issues/7488中报告的问题

毕竟,在支持basePath类的东西之前,我不认为有解决方案,我很乐意提供帮助。

@borekb我也准备帮助过,就像我之前提到过几次。 到目前为止,我所看到的所有变通办法只能解决部分问题。 现在,我们在生产中使用next.js的一个分支,该分支实现了basePath。

我们将很快引入新的API,这将使该提案过时。

@tim还是这样吗?有关API的新提案是否已关闭? https://github.com/zeit/next.js/issues/7329

顺便说一句。 明天恰好是我打开这个问题一年

一个相对荒谬的想法是将页面放置在src/pages之类的位置,然后将它们符号链接到正确的位置。 例如:

  • 部署到myapp.example.com ,我将src/pagespages
  • 要部署到example.com/myapp ,我会将src/pagespages/myapp

与自定义<Link>组件和assetPrefix ,它可以工作,但我不敢尝试😄。

有什么更新吗?

basePath支持有任何进展吗? :)

@nicholasbraun

现在,在每次“链接”单击或“路由器”推送事件上,页面都会重新加载frowning_face

我遇到了这个问题,但是使用链接上的“ as”参数进行了修复,因此链接指向内部文件,但是“ as”相对于路径
例如:
<Link href={"/${item.link}"} as={"./${item.link}"}>

你救了我的一天! :)))

我对Router.push(`/route`, `${process.env.BASE_PATH}route`);做同样的事情

@nicholasbraun

现在在每次链接单击或路由器推送事件上页面都会重新加载☹️

我遇到了这个问题,但是使用链接上的“ as”参数进行了修复,因此链接指向内部文件,但是“ as”相对于路径
例如:
<Link href={"/${item.link}"} as={"./${item.link}"}>

此解决方案不适用于接下来的9个基于文件的路由。 /route/[id]${process.env.BASE_PATH}/route${id}引发此错误

评论很好地说明了问题。

尽管我已经看到一些人讨论这里的解决方案如何破坏预取。 对我们来说,还有另一个更重要的问题。

使用next9,在href使用assetPrefix会使next _always_执行服务器路由。 我已在本期中创建了一个复制回购,并对其进行了演示。

这实际上会破坏我们的Apollo客户端缓存,因为它会在每条路由上重新创建。

我认为该实现方式将带assetPrefix的基础页面href与下一条路由href (其中包括assetPrefix)进行比较-得出的路由较深。

例如,如果您使用的是href /prefix/page (基础页面仅为/page ),而您的下一条href路由为/prefix/page/[id] (因为没有前缀,它将显示404)这是一条完全不同的路线,不可能有一条浅浅的路线。

使用快速路线在分钟内研究解决方法

使用时具有href道具的basePath组件,预取无法正常工作。
PLZ支持basePath和prefetch,它会很棒

我真的可以用这个。 我正在从单个服务器源运行多个应用程序,并且每个应用程序都分成自己的web/appX/{next project files} 。 更好地控制basePath真是太好了。 我现在已经找到一种解决方法,但是它不是很漂亮。

静态导出也需要basePath 😊

似乎工作成功👏

{
  experimental:{
    basePath: '/some/dir',
  }
}

不幸的是,这对我们来说是非常糟糕的限制:(

我们所有应用程序都位于反向代理后面,因此需要在路径前面加上前缀(在下面的示例中,这是/auction-results前缀)

我们已经使用assetPrefix前缀-这使应用程序可以在服务器端请求中正常运行。
例如: mydomain.com/auction-results/通过使用如下所示的快速路由可以正常工作:

router.get(`/${appPrefix}/`, (req, res) => {
  nextApp.render(req, res, '/national', req.params);
});

但是,当我们尝试通过next/link进行客户端导航时,例如:

其中/auction-results是应用程序前缀,而/national~pages/national

<Link href="/national" as="/auction-results/">
  <a>Goto National Page</a>
</Link>

这什么也没做(鬼点击)

具有完整的页面刷新链接并不理想。

如果有什么办法我可以帮忙,我很乐意

关于此事的任何更新...去年大约这个时候,我遇到了这个问题。 一年后的今天,我正在开发一个新的应用程序,并且必须执行与去年相同的解决方法...有点“生产就绪”的预警。 基本路径应该是一种基本功能。

关于此事的任何更新...去年大约这个时候,我遇到了这个问题。 一年后的今天,我正在开发一个新的应用程序,并且必须执行与去年相同的解决方法...有点“生产就绪”的预警。 基本路径应该是一种基本功能。

发布此内容后,我不确定您的期望。

我的团队(5人)正在全职工作Next.js,我们同时正在开发许多功能。 在过去的一年中,我们致力于以下方面:

有效地使Next.js应用程序(新的和现有的)显着缩小,更快并且更具可伸缩性。

如果您想为某个功能表达自己的“赞”,可以。 在初始线程上使用👍功能。

我绝对同意basePath应该是内置功能。 它已经在路线图上了,我什至写了一个初始PR,您可以通过回读线程来查看。

这是PR: https :

如果您想在财务上为实现此功能做出贡献,请随时与[email protected]联系

这是什么状态? 我们真的取决于这个:/

@Sletheren basePath支持目前处于试验阶段,使用时需承担

cf. https://github.com/zeit/next.js/pull/9872

@Sletheren basePath支持目前处于试验阶段,使用风险自负。

cf. #9872

@martpie我已经看到了,但是。 我的情况basePath不只是一个,它可以是多个basePath,因为我们通过不同的“ URL”为我们的应用提供服务,并且在构建期间设置basePath是不可行的(即使它具有以支持路径数组而不是单个字符串)

@timneutkens感谢您的更新。 您是否愿意再提供一次更新。 对我们来说这是一个关键功能,我们需要知道...

  1. 这是否仅适用于企业(您与企业销售人员联系的参考引起了某些不适)?

  2. 根据PR的说法,它似乎已在路线图上,不会再被删除。 您能否给出一些指示,现在是否可以安全地使用此功能,而在接下来的几个月中没有任何意外,例如残缺的开源版本,以及在我们与一些随机销售人员就任意价格进行了几周的谈判之后,又获得了完全的支持?

我了解你们在许多功能上工作,每个人都有自己的优先事项,但更小的设置也需要代理Next,运行多个实例并basePath每个服务指定专用的

多谢您的谅解,并期待收到您的意见。

FWIW,我现在可以使用它,并且可以通过以下方式为其他人驾驶:

将其放入您的next.config.js

module.exports = {
  experimental: {
    basePath: '/custom',
  },
}

然后,我需要重新启动服务器并正确设置我的Web服务器中间件:

我通过自定义路径捕获所有请求,例如。 app.use('/custom', (req, res...) => { ... ,然后(这很重要),我需要代理到正在运行Next的系统的URL(因此,如果您使用http-proxy那么容器业务流程的内部地址以及相应的路径也应包含在内) http-proxy =>例如... target: 'http://next:3000/custom ),因此不仅是没有自定义路径的主机。 如果您使用http-proxy-middleware ,则不需要此功能。

感觉还不错,我希望该功能不需要任何EE许可证。 如果您的团队需要帮助以使此功能成熟,请告诉我们,也许我们可以提供帮助!

编辑:刚刚在Next的生产模式下也尝试过此方法,它似乎也可以正常工作。

@timneutkens感谢您的更新。 您是否愿意再提供一次更新。 对我们来说这是一个关键功能,我们需要知道...

  1. 这是否仅适用于企业(您与企业销售人员联系的参考引起了某些不适)?
  2. 根据PR的说法,它似乎已在路线图上,不会再被删除。 您能否给出一些指示,现在是否可以安全地使用此功能,而在接下来的几个月中没有任何意外,例如残缺的开源版本,以及在我们与一些随机销售人员就任意价格进行了几周的谈判之后,又获得了完全的支持?

我了解你们在许多功能上工作,每个人都有自己的优先事项,但更小的设置也需要代理Next,运行多个实例并basePath每个服务指定专用的

多谢您的谅解,并期待收到您的意见。

@ pe-s我认为您误会了我的帖子。

到目前为止,还没有“企业Next.js版本”。 我指的是无数次外部公司伸出手来支付咨询费用,以在较短的时间内建立类似功能的情况。 Eg区域支持是与Trulia合作建立的。

此功能仍在开发中,并且仍在规划中。 所有正在使用的功能都是开源的,就像我说的那样,没有Next.js的企业版。 尽管在路线图上具有高影响力的工作有很多优先事项,但是为什么我提到如果您需要尽快使用此功能,请联系[email protected] ,以讨论企业对Next.js的支持。

@timneutkens tx,您的快速回复真是太好了! 然后,我们可以全力以赴:)
继续努力!

目前对next@canary Basepath支持已经停止,这不再是实验性的。 它将很快在稳定的频道上。

我对此很迟,但是您是否考虑使用实际的HTML <base>而不是手动处理呢?

目前对next@canary Basepath支持已经停止,这不再是实验性的。 它将很快在稳定的频道上。

@timneutkens ,谢谢您的补充。 您是否知道非实验性basePath支持何时正式发布?

另外,当我设置basePath时,资产(位于公共文件夹中)将按预期方式提供给相应的url。 但是,当我在代码中引用它们时,我必须手动将基本路径添加到src,因为否则它们仍将从正常路径中引用。 这是basePath的预期用途吗? 我也尝试过使用assetPrefix,但对我的代码没有任何影响。

范例

  1. 使用next v9.4.5-canary.24
  2. 在next.config.js中将basePath设置为/alerts
const basePath = '/alerts';
module.exports = {
  basePath: basePath,
  env: {
    BASE_PATH: basePath,
  },
};
  1. 位于public/images/example.png资产
  2. 在React组件中使用资产的示例:
const ExampleImage = () => (
  <img src={`${process.env.BASE_PATH}/images/example.png`} />
);

在我的测试中,它不是在更新资产网址。

我安装了最新的金丝雀:
npm install [email protected]

next.config.js

const isProd = process.env.NODE_ENV === 'production';

module.exports = {
  basePath: isProd ? '/example' : ''
}

所有页面和链接均正确加载:
http:// localhost :3000 / example / posts / pre-rendering
http://本地主机:3000 / example / posts / ssg-ssr
http:// localhost :3000 / example / posts / pre-rendering

但是图像,图标等未映射:
http://本地主机:3000 / favicon.ico 404
http:// localhost :3000 / images / profile.jpg 404

有人测试过吗? 我也尝试过使用assetPrefix,但这也不起作用。

另外我很困惑,为什么不为此使用内置的浏览器功能呢?
https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/base

谢谢您也为此关注@kmturley 。 很高兴知道这不只是我。
@timneutkens ,我们应该重新打开此问题/为此错误创建一个新的问题吗?

您必须手动为图像添加前缀。 您可以使用以下方法获取basePath

const {basePath} = useRouter()

https://nextjs.org/docs/api-reference/next.config.js/cdn-support-with-asset-prefix

Next.js将在加载的脚本中自动使用您的前缀,但这对公用文件夹没有任何影响。

现在,我意识到有多种方法可以链接到/ public中的文件。 例如<img/> <link/> ...
这就是为什么我们必须手动为每个路径指定basePath吗?

如果有如下所示的组件可用,我认为这可以节省时间并减少很多人的困惑?

<WithinBasePath>
  {/* automatically fixes the path with basePath */}
  <img src="/logo.png" />
</WithinBasePath>

我真的认为这不合适,但这就是我的意思。

// src/components/WithinBasePath/index.tsx

import React from "react"
import path from "path"
import { useRouter } from "next/router"
interface Props {}

const WithinBasePath: React.FC<Props> = (props) => {
  const { basePath } = useRouter()
  const children = [props.children].flatMap((c) => c) as React.ReactElement[]
  return (
    <>
      {children.map((child, key) => {
        let newChild = null

        switch (child.type) {
          case "img":
            newChild = React.createElement(child.type, {
              ...child.props,
              src: path.join(basePath, child.props.src),
              key,
            })
            break
          case "link":
            newChild = React.createElement(child.type, {
              ...child.props,
              href: path.join(basePath, child.props.href),
              key,
            })
            break
          default:
            newChild = React.createElement(child.type, {
              ...child.props,
              key,
            })
        }
        return newChild
      })}
    </>
  )
}
export default WithinBasePath

// pages/test.tsx

import React from "react"
import WithinBasePath from "@src/components/WithinBasePath"
interface Props {}

const test: React.FC<Props> = (props) => {
  return (
    <WithinBasePath>
      <img src="/123.jpg" />
      <link href="/abc.jpg" />
      <div>other element</div>
    </WithinBasePath>
  )
}
export default test

对于尝试使用const {basePath} = useRouter()这是一个挂钩的人,可以使用类和组件并得到此错误:

无效的挂机呼叫警告

https://reactjs.org/warnings/invalid-hook-call-warning.html

您可以使用以下方法使其正常工作:

import { withRouter, Router } from 'next/router'

class Example extends Component<{router: Router}, {router: Router}> {
  constructor(props) {
    super(props)
    this.state = {
      router: props.router
    }
  }
  render() {
    return (
      <Layout home>
        <Head><title>Example title</title></Head>
        <img src={`${this.state.router.basePath}/images/creators.jpg`} />
      </Layout>
    )
  }
}
export default withRouter(Example)

如果要使用带有markdown的basePath,则看起来需要查找并替换字符串:

const content = this.state.doc.content.replace('/docs', `${this.state.router.basePath}/docs`);
return (
<Layout>
  <Container docs={this.state.allDocs}>
    <h1>{this.state.doc.title}</h1>
    <div
      className={markdownStyles['markdown']}
      dangerouslySetInnerHTML={{ __html: content }}
    />
  </Container>
</Layout>
)

您必须手动为图像添加前缀。 您可以使用以下方法获取basePath

const {basePath} = useRouter()

但是,此解决方案不考虑在css或scss文件中导入的图像。 对于从css或scss文件中导入资产时,如何设置基本路径有解决方案吗?
使用此解决方案,我们将必须确保通过img标签,内联样式或在style标签中导入所有图像。 这是不理想的,因为它将拆分您的样式以在多个地方实现。

@peetjvv这是在CSS中使用带有前缀basePaths的资产的次_app.tsx创建,导入和添加<CSSVariables>组件,这将注入一个包含CSS变量的全局内联<style>元素,然后您可以在整个样式表中使用所有元素。

例如,在<body>的开头创建并注入变量:

<style>
:root {
      --asset-url: url("${basePath}/img/asset.png");
}
</style>

为了获得该basePath,我使用withRouter km withRouter@kmturley方法。
该组件的外观如下所示:

import { withRouter, Router } from "next/router";
import { Component } from "react";

export interface IProps {
  router: Router;
}

class CSSVariables extends Component<IProps> {
  render() {
    const basePath = this.props.router.basePath;
    const prefixedPath = (path) => `${basePath}${path}`;
    const cssString = (value) => `\"${value}\"`;
    const cssURL = (value) => `url(${value})`;
    const cssVariable = (key, value) => `--${key}: ${value};`;
    const cssVariables = (variables) => Object.entries(variables)
      .map((entry) => cssVariable(entry[0], entry[1]))
      .join("\n");
    const cssRootVariables = (variables) => `:root {
      ${cssVariables(variables)}
    }`;

    const variables = {
      "asset-url": cssURL(
        cssString(prefixedPath("/img/asset.png"))
      ),
    };

    return (
      <style
        dangerouslySetInnerHTML={{
          __html: cssRootVariables(variables),
        }}
      />
    );
  }
}

export default withRouter(CSSVariables);
此页面是否有帮助?
0 / 5 - 0 等级

相关问题

jesselee34 picture jesselee34  ·  3评论

lixiaoyan picture lixiaoyan  ·  3评论

pie6k picture pie6k  ·  3评论

timneutkens picture timneutkens  ·  3评论

knipferrc picture knipferrc  ·  3评论