我有一个用例,其中服务器正在定义一些自定义路由。 当浏览器加载这些路由时,会短暂显示预期的内容,直到客户端路由接管并用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
您为什么不知道服务器正在渲染的路径?
更少的是我不知道路径(我可以编写匹配它们的正则表达式),但是更多的是重叠。 实际设置位于apache服务器后面,该服务器将代理反向转换为一堆不同的应用程序,包括gatsby网站。 如果其中任何一个应用程序不可用,或者返回内部服务器错误,我们将返回一个自定义错误页面,该页面是gatsby网站的一部分。
因此,在任何时间点,如果app1不可用或行为异常,对/ app1的任何请求都将返回/error/unavailable.html或/error/internal.html的内容,而对于app2则同样如此,依此类推。
在两个不可用的内部错误页面上都使用像/^(app1|app2)/.*/
matchPath
这样的findPage
不知道(基于url)我实际上打算使用哪一页向用户展示。
我能够使用全局变量并在onClientEntry
“修补” ___history
和___loader
来使工作正常。 它非常脆弱,因为它依赖于gatsby来暴露那些全局变量-不确定是否有某种方法可以将其通用化并将其添加到gatsby中。
修补历史记录使用props.location.pathname
捕获呼叫
component-renderer.js#L18-L28
修补加载程序可直接使用window.location.pathname
production-app.js#L155
// 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中。
- 修补历史记录使用
props.location.pathname
捕获呼叫
component-renderer.js#L18-L28- 修补加载程序可直接使用
window.location.pathname
production-app.js#L155// 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-page
或example.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}
根据此线程继续保持活跃的程度,似乎有不小的用户希望这种行为。
快速重申一下我的用例:我想(确实! )将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
正如预期的那样(并由@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上添加了一些示例和文档
与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`)
}
我不确定它是否涵盖了插件涵盖的所有用例,但对于我的情况来说效果很好。
最有用的评论
根据此线程继续保持活跃的程度,似乎有不小的用户希望这种行为。
快速重申一下我的用例:我想(确实! )将Gatsby用作静态_page_生成器-而不是静态_site_生成器-并且因为Gatsby“页面”被注入到URL不在其中的包含页面中我的控制权可能会发生变化,因此我不希望Gatsby应用程序_ever_与URL混为一谈。 开箱即用,Gatsby _mostly_支持该用例,非常高兴使用,但是它确实做出了一些假设-再次由于其标准的静态_site_用例-导致需要提到的黑客以上。
因此,是否有能力将客户端路由禁用成为顶级配置选项? 我很乐意提交PR,但是如果没有机会接受PR,我不想浪费时间。