Gatsby: 禁用客户端路由?

创建于 2018-03-02  ·  69评论  ·  资料来源: gatsbyjs/gatsby

描述

我有一个用例,其中服务器正在定义一些自定义路由。 当浏览器加载这些路由时,会短暂显示预期的内容,直到客户端路由接管并用404替换页面,因为无法识别浏览器中的url。

我的第一个想法是也许可以在这里使用matchPath ,但是我不一定知道会呈现这些页面的url模式,并且url是什么,以及哪个页面是重叠的回。

我猜可能有可能与查找页面挂钩,但是我不确定那会是什么样子。

环境

盖茨比版本:1.9.221
Node.js版本:8.9.1
作业系统:macOS

实际结果

加载浏览器后,将短暂显示预期的页面,直到javascript加载完毕,确定网址未知,然后呈现404页面。

预期行为

服务器呈现的页面应该在自定义URL上可用,并且在客户端加载时不能被404页面替换。

重现步骤

1. git clone https://github.com/TuckerWhitehouse/gatsby-client-routing-issue

2. npm install

3. npm run build

4. npm start

5. open http://localhost:3000

awaiting author response question or discussion

最有用的评论

根据此线程继续保持活跃的程度,似乎有不小的用户希望这种行为。

快速重申一下我的用例:我想(确实! )将Gatsby用作静态_page_生成器-而不是静态_site_生成器-并且因为Gatsby“页面”被注入到URL不在其中的包含页面中我的控制权可能会发生变化,因此我不希望Gatsby应用程序_ever_与URL混为一谈。 开箱即用,Gatsby _mostly_支持该用例,非常高兴使用,但是它确实做出了一些假设-再次由于其标准的静态_site_用例-导致需要提到的黑客以上。

因此,是否有能力将客户端路由禁用成为顶级配置选项? 我很乐意提交PR,但是如果没有机会接受PR,我不想浪费时间。

所有69条评论

您为什么不知道服务器正在渲染的路径?

更少的是我不知道路径(我可以编写匹配它们的正则表达式),但是更多的是重叠。 实际设置位于apache服务器后面,该服务器将代理反向转换为一堆不同的应用程序,包括gatsby网站。 如果其中任何一个应用程序不可用,或者返回内部服务器错误,我们将返回一个自定义错误页面,该页面是gatsby网站的一部分。

因此,在任何时间点,如果app1不可用或行为异常,对/ app1的任何请求都将返回/error/unavailable.html或/error/internal.html的内容,而对于app2则同样如此,依此类推。

在两个不可用的内部错误页面上都使用像/^(app1|app2)/.*/ matchPath这样的findPage不知道(基于url)我实际上打算使用哪一页向用户展示。

我能够使用全局变量并在onClientEntry “修补” ___history___loader来使工作正常。 它非常脆弱,因为它依赖于gatsby来暴露那些全局变量-不确定是否有某种方法可以将其通用化并将其添加到gatsby中。

// gatsby-browser.js
exports.onClientEntry = () => {
  // Check for a custom pathname
  const pathname = global.___pathname
  if (!pathname) return

  // Override the history location
  const history = global.___history
  history.location.pathname = pathname

  // Patch the resource loader
  const loader = global.___loader
  const { getResourcesForPathname } = loader

  loader.getResourcesForPathname = (path, ...args) => {
    return getResourcesForPathname(path === location.pathname ? pathname : path, ...args)
  }
}
// src/pages/page1.js
import React from "react"
import Helmet from 'react-helmet'

export default () => (
  <div>
    <Helmet>
      <script>{`window.___pathname = '/page1'`}</script>
    </Helmet>
    <div>Page 1!</div>
  </div>
)

我也同意应该有一个构建选项来禁用此功能。 我们还有一个非常规的设置,希望在我们完成向完整Gatsby站点的迁移时暂时禁用此功能。

在构建时一个简单的标志将是完美的。

这个怎么样? 有什么解决办法吗?

我们最终修改了pages.json以匹配所需的路径。 我们使用已更正的路径名来基本调用addPagesArray。

我仍然不明白为什么这会引发错误? 该页面可以正常工作。 当它与路径不匹配时,这最多应该是一个警告。

话虽这么说,我不知道是否有通过配置和运行时代码修改pages.json的更优雅的方法。

我想解决这个问题。

我正在从事的项目遇到类似的问题。 我们正在构建一个着陆页生成器,它将生成单页Gatsby应用程序。 当我们尝试在其域之外提供目标网页时,就会出现此问题。

因此,例如,我们有主要的盖茨比应用程序www.example.com 。 我们提供的服务将获取盖茨比登陆页面,并以www.example.com/trial 。 因此,着陆页的URL看起来像www.example.com/trail/ad-123该页面最初加载正常,直到所有JS加载并且路由器接管为止。 着陆页查看路径,但不知道路径在哪里,因此它尝试更改路径以将页面放置在根目录下,就像这样的www.example.com/ad-123 ,这将导致404重定向。

是否有计划添加可配置选项来解决此问题? 盖茨比团队会接受公关吗?

@ alex-greco-harrys在我看来,路径前缀就是您要在这种情况下使用的

我还需要禁用客户端路由,才能在我的网站上正确运行Google Adsense。

Google Adsense自动广告不会检测到客户端路由,并且在更新路由时广告也不会刷新。

无论如何,我可以禁用客户端路由吗?

在这种情况下,您可以使用a标签代替gatsby-link

我能够使用全局变量并在onClientEntry “修补” ___history___loader来使工作正常。 它非常脆弱,因为它依赖于gatsby来暴露那些全局变量-不确定是否有某种方法可以将其通用化并将其添加到gatsby中。

// gatsby-browser.js
exports.onClientEntry = () => {
  // Check for a custom pathname
  const pathname = global.___pathname
  if (!pathname) return

  // Override the history location
  const history = global.___history
  history.location.pathname = pathname

  // Patch the resource loader
  const loader = global.___loader
  const { getResourcesForPathname } = loader

  loader.getResourcesForPathname = (path, ...args) => {
    return getResourcesForPathname(path === location.pathname ? pathname : path, ...args)
  }
}
// src/pages/page1.js
import React from "react"
import Helmet from 'react-helmet'

export default () => (
  <div>
    <Helmet>
      <script>{`window.___pathname = '/page1'`}</script>
    </Helmet>
    <div>Page 1!</div>
  </div>
)

@TuckerWhitehouse您从哪里获得___history___loader ? 当我尝试复制您的示例时,global的这两个属性是undfined

@ alex-greco-harrys在我看来,路径前缀就是您要在这种情况下使用的

@ jgierer12这有助于解决我的第一部分问题。 第二部分是直到呈现页面之前,最终路径都是未知的。 我们有一个学习服务,它可以收集静态页面,并根据转换率为其提供服务。 因此,在路径example.com/go/我们可以提供一组页面中的一个。 因此,我们不会在example.com/go/first-pageexample.com/go/second-page类的路径上提供页面。 两者都将以example.com/go/page路径投放。

本质上,我想完成的工作是在我想要的任何路径下提供gatsby页面。

@ alex-greco-harrys这些全局变量被gatsby v1暴露。 随着v2的升级,我知道底层路由器已从react-router切换到reach-router,所以我想那些全局变量会受到影响。

我也希望使用Gatsby构建一个单页应用程序,并希望完全禁用路由。 有谁知道与V2兼容的解决方法(例如@TuckerWhitehouse )?

更新:
虽然我找不到能禁用客户端路由的解决方案,但通过设置以下内容,我可以防止@ alex-greco-harrys和其他人引用的重定向:

window.page = window.page || {};
window.page.path = window.location.pathname;

在gatsby-browser.js中,可以使production-app.js中的条件检查短路。 有条件的重定向尝试“使规范路径与实际路径匹配”,并导致上述(IMO)意外行为。

我也需要这个

我目前在另一个项目上使用Gatsby生成的代码,并且在多个页面上使用它。 我正在使用Gatsby,因为它会生成静态代码。 因此,我使用pathPrefix来生成特定路径下的所有内容并提供服务。 这样,所有内容都在那里被请求,然后呈现为页面的一部分。 但是,由于脚本中存在重定向,因此我一直都在不必要地重定向到pathPrefix 。 我必须手动删除@ethagnawl每次构建时

我也希望使用Gatsby构建一个单页应用程序,并希望完全禁用路由。 有谁知道与V2兼容的解决方法(例如@TuckerWhitehouse )?

更新:
虽然我找不到能禁用客户端路由的解决方案,但通过设置以下内容,我可以防止@ alex-greco-harrys和其他人引用的重定向:

window.page = window.page || {};
window.page.path = window.location.pathname;

在gatsby-browser.js中,可以使production-app.js中的条件检查短路。 有条件的重定向尝试“使规范路径与实际路径匹配”,并导致上述(IMO)意外行为。

@ethagnawl我有一种很

如果您查看以下Gatsby示例: https :

您可以在第15行上编辑该文件,使其看起来像<Page path="/*" {...props} />然后删除第16行。构建此应用程序时,任何路径都将导致提供您定义的Page 。 在这里,您可以随意设置Page 。 现在,如果您需要在任意路径上托管此页面,则不会看到任何重定向。

我无法弄清楚该解决方案如何在一个应用程序中处理多个页面。 我项目的目标是在我想​​要的任何URL上提供一个Gatsby页面(营销目标页面)。

不知道这是否对您的用例有所帮助,但是也许这可以激发将来的发现!

我能够按照文档中的html.js定制说明删除{this.props.postBodyComponents}

https://www.gatsbyjs.org/docs/custom-html/

根据此线程继续保持活跃的程度,似乎有不小的用户希望这种行为。

快速重申一下我的用例:我想(确实! )将Gatsby用作静态_page_生成器-而不是静态_site_生成器-并且因为Gatsby“页面”被注入到URL不在其中的包含页面中我的控制权可能会发生变化,因此我不希望Gatsby应用程序_ever_与URL混为一谈。 开箱即用,Gatsby _mostly_支持该用例,非常高兴使用,但是它确实做出了一些假设-再次由于其标准的静态_site_用例-导致需要提到的黑客以上。

因此,是否有能力将客户端路由禁用成为顶级配置选项? 我很乐意提交PR,但是如果没有机会接受PR,我不想浪费时间。

添加@ethagnawl似乎是一个合理的功能。 我认为它需要一个非常长且令人讨厌的名称,例如dangeouslySetInnerHTML,这样人们就完全意识到自己在做什么,因为这是一个非常特殊的情况。

我在PR上解决此问题的第一遍可以在这里找到。 非常感谢维护者和/或遇到此问题的其他用户的反馈。

感谢您创建aPR @ethagnawl

您能再次提醒我为什么以下工作吗?

// Implement the Gatsby API “onCreatePage”. This is
// called after every page is created.
exports.onCreatePage = ({ page, actions }) => {
  const { createPage } = actions;
  page.matchPath = `${page.path}*`;
  createPage(page);
};

@wardpeet我确定它会起作用,并且看起来与我上面提到的解决方案类似。 但是,这类解决方案难以记录,而且可能很脆弱(请参阅@TuckerWhitehouse提供的解决方案

IMO将这一概念整理起来是值得的,因为它再次使文档更加直接,并且该标志还可以通过绕过/循环/等来用于进行其他优化。 以这种方式使用盖茨比时无关紧要的功能。

此外,使用matchPath要求浏览器中的URL能够反映您要呈现的页面,但是当您将gatsby网站注入未知位置时,此功能会失效。 (我最初的问题是关于让gatsby在apache反向代理后面,并且不知道会导致某个页面呈现的路由)。

@ethagnawl您是否认为可以在页面级别禁用路由(类似page.__disable_client_side_routing__ = true )? 这可能会解决我原来遇到的问题。

您是否认为有可能在页面级别禁用路由

我不明白为什么不呢? 是我提议的解决方案的补充还是替代? 如果是后者,那么在页面级别上这样做有什么好处吗?

我已经设置了这个仓库:)
https://github.com/wardpeet/gatsby-plugin-static-site

不确定这是否适用于您的用例。
现在你需要做

git clone https://github.com/wardpeet/gatsby-plugin-static-site
npm install
npm run build
npm link

cd "into your project"
npm link gatsby-plugin-static-site

将gatsby-plugin-static-site添加到您的gatsby-config.js中

让我知道这是否适合您的用例,我无意实际支持它,所以我很乐意转移它:smile:

我更新了仓库,因为我的gitignore文件有问题(感谢@ m-allanson)。 我也以自己的名字将其发布到npm。

这样就可以完成安装

npm install --save @wardpeet/gatsby-plugin-static-site

并将@wardpeet/gatsby-plugin-static-site到gatsby-config.json

如果看起来不错,那么我可以添加一些测试和一些选项来禁用此行为以进行开发。

iya!

这个问题已经悄无声息。 幽灵般的安静。 👻

我们遇到了很多问题,因此我们目前在闲置30天后就关闭了问题。 从这里的最新更新已经至少有20天了。

如果我们错过了此问题,或者您想使其保持打开状态,请在此处回复。 您也可以添加标签“ not stale”以保持此问题的状态!

感谢您加入盖茨比社区! 💪💜

我希望它保持打开状态,因为它正在等待审核

我不确定它是否过时,我已解决此问题并希望获得反馈
https://github.com/gatsbyjs/gatsby/issues/4337#issuecomment -470075540

如果没有人回应,我认为最好将其关闭,因为它可能已解决。

@wardpeet可以通过该插件有条件地禁用客户端路由吗?

@wardpeet IIRC,您建议的修复程序是(可能最终)将此功能作为Gatsby配置选项添加的过程中的第一步。 因此,就此问题和盖茨比而言,_sort of_使其脱颖而出,但我可能会提出这样的论点,即该问题应保持公开状态以便继续进行对话。

@wardpeet最初的问题是有关为特定路由禁用客户端路由的, @ ethagnawl提出了为整个站点禁用路由的用例,我相信您的插件将解决这个问题。

在将旧CMS上的网站迁移到Gatsby时,我需要暂时禁用客户端路由。 在一次将开关完全切换到gatsby之前,我每次都要一页。

我尝试了@wardpeet插件,但似乎无法正常工作。

@brianbento您有复制品吗? 如果您可以在回购网站https://github.com/wardpeet/gatsby-plugin-static-site上创建问题,那么我可以看看缺少的内容

@wardpeet我会看看我能不能站起来。 主要问题是,当您使用pathPrefix时,您先前提到的“修复”(https://github.com/gatsbyjs/gatsby/issues/4337#issuecomment-465497418)不起作用。 它总是将地址“校正”到期望的值。

@brianbento您是否尝试过我上面提到的解决方案? 在两个不同的项目上,这对我来说效果很好。

@ethagnawl我仍然得到URL更正,然后将路径前缀加倍。

所以“ /“成为” //”在规范不匹配之后。

也许我执行错了。 您是否为页面使用路径前缀? 我应该激活静态站点插件吗?

您是否为页面使用路径前缀?

是。 我也在使用分支来允许远程资产。 因此,正是_possible_分支引入了使该修复程序对我有用而不对您有用的行为。

但是,最近的盖茨比发行版(我一直没有跟上)很可能破坏了我的“解决方案”,因为它一开始就是黑客。

@ethagnawl超级有帮助! 谢谢! 我知道@DSchau制作了一些插件来测试assetPrefix功能。 我会试一下!

当您还需要使用路径前缀时, @ wardpeet解决方案似乎__disable_client_side_routing__这样的解决方案禁用了规范检查,这将非常酷。 如果可以考虑合并,我很乐意进行处理并提交PR。 对这个想法有任何支持,还是您认为它不适合路线图?

@xavivars我肯定会发现它很有用。

@xavivars我在不久前通过了该功能,该功能@wardpeet的解决方案而关闭。 如果您打算重新考虑该方法,那么值得一看。

谢谢@ethagnawl ! 我看了看你的方法,那几乎就是我的想法。

我认为@wardpeet解决方案涵盖了一个不同的用例:该应用程序不具有SPA的功能,因为链接实际上正在更改浏览器location.href ,因此它会在“服务器端”导航。 但是我无法使它适用于我的用例,因为初始重定向仍在发生:我的初始假设是与prefixPath之间存在某种相互作用,使得此条件的值评估为true

https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/cache-dir/production-app.js#L65

您是否设法使其正常工作?

如果有人可以解释我的实际问题,我可能会在插件上做更多的工作,因为我有点忘记了需要解决的问题。 也许大多数情况可以通过新合并的assetPrefix选项解决?

对不起,不理解。

@xavivars

您是否设法使其正常工作?

对于我的用例,我的hack和提交的PR都在“正常工作”:没有重定向的单个静态页面生成。 我放弃PR是因为Gatsby团队似乎更喜欢插件而不是应用程序级别的配置选项。

我从来没有尝试过@wardpeet的插件,因为在发布之时我已经结束了我正在研究的Gatsby项目。 因此,我无法评论该操作是否正常。

@wardpeet :assetPrefix无法修复它。 我设法把它同时使用你的插件工作(到,基本上禁止客户端的“导航”点击时左右),并通过@ethagnawl几个月前提到的解决方法

https://github.com/gatsbyjs/gatsby/issues/4337#issuecomment -453244611

需要这种解决方法来禁用发生onClientEntry的“导航”事件。 我们修复了在那里添加一个钩子并应用该变通方法(将page.path强制为实际路径)的问题。 但是我不知道这是否有任何副作用,以及直到它停止工作需要多长时间(不超过hack)。

理想情况下,鉴于似乎有很多人使用gatsby作为“静态页面生成器”,因此我认为这应该是应用程序级的配置

@xavivars是否有您可以与您共享的链接?

并非如此,但这几乎就是:

在gastby-browser.js中添加前面提到的静态插件

exports.onClientEntry = () => {
    window.page = window.page || {};
    window.page.path = window.location.pathname;
}

尽管它依赖于gatsby内部结构,但以下内容也适用:

export function onInitialClientRender() {
  window.___navigate = (to, { replace }) => {
    if (replace) {
      window.location.replace(to);
    } else {
      window.location.assign(to);
    }
  };
}

使用https://github.com/wardpeet/gatsby-plugin-static-site&assetPrefix是否有效?

使该示例正常工作的链接问题,不确定这是否是您真正需要的。
https://github.com/wardpeet/gatsby-plugin-static-site/issues/1#issuecomment -494802726

对我来说,它可用于所有三件事:gatsby插件静态站点+ assetPrefix +禁用“导航”,如上所示

似乎我仍然很难理解这里需要什么。 我可以使用gatsby-plugin-static-site&assetPrefix解决此问题。

@wardpeet您是否有使用gatsby-plugin-static的演示的链接?

@ethagnawl很抱歉让您久等了。

我做了一个演示:
https://github.com/wardpeet/gatsby-demos/tree/static-asset-prefix

网站上线了:
https://zen-wright-33c2d8.netlify.com/

正如预期的那样(并由@TuckerWhitehouse和@ethagnawl预期),像https://github.com/gatsbyjs/gatsby/issues/4337#issuecomment -453244611中所提供的那样,这种脆弱的解决方案由于更改而不再起作用在盖茨比2.9.2中有以下几个原因:

第一个可解决的问题是,这条线
window.page.path = window.location.pathname;
需要替换为
window.pagePath = window.location.pathname;
为了避免在URL客户端进行更改。

但这有不希望的副作用:pagePath设置为_wrong_路径,而page-data.json不再加载(因为它依赖于页面的原始路径,而不是最终呈现的路径)

https://github.com/gatsbyjs/gatsby/commit/49fd769f695ccfa6e990e3eaae7c886f073db19b#diff -2d21ea42ec874a0988977e57b17251aa

看来现在使这项工作可行的唯一选择是真正引入__disable_client_side_routing__类的变量,或者至少引入__disable_client_side_canonical_redirect__来缩短这种情况: https :

@wardpeet :引入这样的配置变量是否有任何问题?

我们宁愿不想在核心中启用这些逃生舱口。 我对此问题的基本了解是:

我有一个gatsby网站和一个路径/ my-special-path,在我的服务器上,我有一个名为/ something-else的路由。 如果我将/ something other重写为/ gatsby / my-special-path,它将无法正常工作,因为它试图将页面更改为/ my-special-path?

如果是这样,我将查看是否可以在插件中对其进行修复。 您可能对此有现场演示吗?

是的,这就是问题所在。 我将尝试将另一个PR放在一起(不要将侵入性的内容作为https://github.com/gatsbyjs/gatsby/pull/15173的全局配置变量添加)。

我有一些可以接受的内容,我将在几分钟后成为另一位PR

@wardpeet这是我认为需要添加到Gatsby以便扩展插件的功能。 我在PR上添加了一些示例和文档

https://github.com/gatsbyjs/gatsby/pull/15180

与Discord中的@DSchau对话后,似乎核心贡献者一致认为#15173或#15180之类的解决方案不应存在于核心中,而应存在于插件中。 因此,我想探索其他解决方案。

目前,我发现的唯一方法是通过全局配置变量(#15173)来缩短规范重定向检查,或允许修改gatsby的感知呈现URL(#15180),因此规范重定向检查不直接依赖于window.location ,但位于可过滤的变量上。

恕我直言,挑战是使用插件来扩展/覆盖目前似乎不可扩展/可覆盖的东西(直接依赖window.location而没有从任何地方注入的值对我来说真的很难),但是可能有其他方法可以在不修改内核代码的情况下实现此行为。

@xavivars我将合并https://github.com/wardpeet/gatsby-plugin-static-site/pull/4并为此发布修复程序。

演示:(第5页具有规范的重定向)
https://static-asset-prefix--zen-wright-33c2d8.netlify.com/

我刚刚发布了@ wardpeet / gatsby-plugin-static-site版本0.1.0。 这应该可以解决此问题。 如果无法解决所有问题,请随时重新打开。

获得更好的静态站点支持的最佳方法是在插件本身上创建问题。 https://github.com/wardpeet/gatsby-plugin-static-site/issues/new

使用上述插件后,有人遇到过此问题吗?

任何适用于当前版本的GatsbyJS的解决方法?

我试过了:
https://github.com/wardpeet/gatsby-plugin-static-site

但这对我不起作用。 我在这里提出了一个问题:
https://github.com/wardpeet/gatsby-plugin-static-site/issues/13

我还创建了一个示例存储库来重现重定向问题:
https://github.com/isi-gach/gastby-static/tree/create-react-app

@ isi-gach您是否愿意提供对根本问题的看法(您期望什么,您看到什么,您想看到什么)? 我们这个线程中的一些人已经尝试过,但是可能会有所帮助。

@ethagnawl

我希望浏览器的URL不会改变,但是我看到URL发生了变化,在下面的视频中,URL从/demo/index.html变为/public/
https://www.youtube.com/watch?v=SxYbaDidnkY

该视频是使用我创建的示例存储库录制的:
https://github.com/isi-gach/gastby-static/tree/create-react-app

我正在尝试使用@wardpeet/gatsby-plugin-static-site阻止重定向,但似乎不起作用。

嗨@ isi -gach

@wardpeet插件中有几个拉取请求,它们可以解决您提到的问题。

当它们合并时,您可以改用我的叉子

嗨@xavivars
我从您的叉子尝试了npm ,现在URL不变了,但是我得到了一个白页:
https://www.youtube.com/watch?v=uNzk9UYVCxk

该视频是使用以下示例存储库录制的,由您的插件替换了wardpeet by plugin:
https://github.com/isi-gach/gastby-static/tree/create-react-app

我如何只为单个页面禁用客户端路由?

你可以用这个

exports.onPreBootstrap = ({ store }) => {
  const { program } = store.getState()
  const filePath = path.join(program.directory, '.cache', 'production-app.js')

  const code = fs.readFileSync(filePath, {
    encoding: `utf-8`,
  })

  const newCode = code.replace(
    `const { pagePath, location: browserLoc } = window`,
    `const { pagePath } = window
    let { location: browserLoc } = window

    if (window.parent.location !== browserLoc) {
      browserLoc = {
        pathname: pagePath
      }
    }
  `
  )

  fs.writeFileSync(filePath, newCode, `utf-8`)
}

我不确定它是否涵盖了插件涵盖的所有用例,但对于我的情况来说效果很好。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

rossPatton picture rossPatton  ·  3评论

KyleAMathews picture KyleAMathews  ·  3评论

dustinhorton picture dustinhorton  ·  3评论

ghost picture ghost  ·  3评论

andykais picture andykais  ·  3评论