Closed TuckerWhitehouse closed 5 years ago
Why don't you know what paths the server is rendering?
It's less that I won't know the paths (I can write a regex that will match them) but more the overlap. The actual setup is behind an apache server that reverse proxies to a bunch of different apps, including the gatsby site. If any of those apps become unavailable, or return an internal server error, we return a custom error page that is part of the gatsby site.
So at any point in time, if app1 is unavailable or misbehaving, any requests to /app1 would return the content of /error/unavailable.html or /error/internal.html, and the same would be true for app2, and so on.
Using a matchPath
like /^(app1|app2)/.*/
, on both the unavailable an internal error pages doesn't work because findPage
doesn't know (based on the url) which page I actually intend to show the user.
I was able to get something working using a global variable and "patching" ___history
and ___loader
in onClientEntry
. It's very fragile because of the dependency on gatsby exposing those globals - not sure if there is some way to generalize this and add it to gatsby.
Patching history catches calls using props.location.pathname
component-renderer.js#L18-L28
Patching loader catches direct use of 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>
)
I also agree that there should be a build option to disable this feature. We also have an unconventional setup and would like to disable this feature temporarily while we finish our migration to a full Gatsby site.
A simple flag at build time would be perfect.
how about this one? any solution for this?
We ended up modifying the pages.json to match the path that we needed. We basicallay called addPagesArray with the corrected path name.
I still dont understand why this throws an error? The page loads fine and works. This at most should be a warning when it cant match the path.
That being said I dont know if there is a more elegant way of modifying the pages.json thru a config vs runtime code.
I want to bump this issue.
A project I am working on is experiencing a similar issue. We are build a landing page generator that will build single-page Gatsby apps. This issue comes when we try to serve a landing page outside of it's domain.
So for example we have our main Gatsby app www.example.com
. We have a service that will take the Gatsby landing pages and serve them at www.example.com/trial
. So a landing page URL would look like www.example.com/trail/ad-123
The page initially loads fine until all the JS loads and the router takes over. The landing page looks at the path and doesn't know where it is, so it tries to change the path to place the page at the root, looking like this www.example.com/ad-123
, which results in a 404 redirect.
Are there any plans to add a configurable option to fix this? Would the Gatsby team be open to a PR?
@alex-greco-harrys It seems to me that a path prefix is what you'll want to use in that scenario.
I also needed to disable client side routing to run Google Adsense properly on my website.
Google Adsense auto ads don't detect client side routing and the ads don't refresh when routes are updated.
Is there anyway I can disable client side routing?
You can use a
tags instead of gatsby-link
in cases like that
I was able to get something working using a global variable and "patching"
___history
and___loader
inonClientEntry
. It's very fragile because of the dependency on gatsby exposing those globals - not sure if there is some way to generalize this and add it to gatsby.
- Patching history catches calls using
props.location.pathname
component-renderer.js#L18-L28- Patching loader catches direct use of
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 where are you getting ___history
, ___loader
from? When I try to replicate your example those two properties of global are undfined
.
@alex-greco-harrys It seems to me that a path prefix is what you'll want to use in that scenario.
@jgierer12 That helps solve the first piece of my issue. The second piece is that the final path is unknown until the page is rendered. We have a learning service that takes a collection of static pages and serves them based off conversion rates. So at a path example.com/go/
we could be serving 1 of a collection of pages. So we wouldn't be serving the page at a path like example.com/go/first-page
or example.com/go/second-page
. Those both would be served at example.com/go/page
path.
Essentially what I am trying to accomplish is to serve a gatsby page at whatever path I want.
@alex-greco-harrys those globals were exposed by gatsby v1. With the upgrade to v2, I know the underlying router was switched from react-router to reach-router, so my guess would be those globals were affected.
I'm also hoping to use Gatsby to build a single page application and would like to disable routing entirely. Does anyone know of a workaround (a la @TuckerWhitehouse's) that would be compatible with V2?
UPDATE: While I wasn't able to find a solution which would disable client side routing, I was able to prevent the redirect referenced by @alex-greco-harrys and others by setting:
window.page = window.page || {};
window.page.path = window.location.pathname;
in gatsby-browser.js which short circuits this conditional check in production-app.js. That conditional redirect attempts to "make the canonical path match the actual path" and results in the (IMO) unexpected behavior referenced above.
I also need this.
I am currently using code generated by Gatsby on another project and I use it on multiple pages. I am using Gatsby as it generates static code. Therefore, I used the pathPrefix
so I could generate everything under a specific path and serve it. That way, everything gets requested there and then rendered as a fragment of a page. However, I get unwanted redirects all the time to the pathPrefix
because it is in the scripts. I have to manually remove the condition that @ethagnawl mentioned everytime I build. I just tried his solution but it didn't work for me.
I'm also hoping to use Gatsby to build a single page application and would like to disable routing entirely. Does anyone know of a workaround (a la @TuckerWhitehouse's) that would be compatible with V2?
UPDATE: While I wasn't able to find a solution which would disable client side routing, I was able to prevent the redirect referenced by @alex-greco-harrys and others by setting:
window.page = window.page || {}; window.page.path = window.location.pathname;
in gatsby-browser.js which short circuits this conditional check in production-app.js. That conditional redirect attempts to "make the canonical path match the actual path" and results in the (IMO) unexpected behavior referenced above.
@ethagnawl I have a hacky sort of solution to produce a single page app that can be served at any URL. By single page, I actually mean one single page with no routing at all.
If you look at the following Gatsby example: https://github.com/gatsbyjs/gatsby/tree/master/examples/client-only-paths .
You can edit this file on line 15 to look like <Page path="/*" {...props} />
and delete line 16. When you build this application, any path will result in serving the Page
you have defined. From there you can make that Page
whatever you want. Now if you need to host this page at an arbitrary path you will see no redirection.
I was unable to figure out how this solution could work with multiple pages in an app. The goal for my project was to serve a single Gatsby page (marketing landing page) at any URL I want.
Not sure if this helps in your use case, but maybe this can fuel some future discovery!
I was able to accomplish this by following the Customizing html.js directions in the docs and removing {this.props.postBodyComponents}
Based on how active this thread continues to be, there seems to be a non-trivial number of users who desire this behavior.
To quickly reiterate my use case: I want to (did!) use Gatsby as a static page generator -- as opposed to a static site generator -- and because the Gatsby "page" is injected into a containing page whose URL is out of my control and subject to change, I don't want the Gatsby application ever mucking with the URL. Out of the box, Gatsby mostly supports this use case and is a great pleasure to use, but it does makes some assumptions -- again, because of its standard static site use case -- that result in the need for hacks like the ones mentioned above.
So, is there any hope for the ability to disable client side routing becoming a top-level config option? I would be happy to submit a PR, but don't want to sink time into it if there's no chance it'll be accepted.
This seems like a reasonable feature to add @ethagnawl. I think it'd need a very long and obnoxious name like dangeouslySetInnerHTML so people are fully conscious of what they're doing as this is a very special edge case.
My first pass at a PR addressing this issue can be found here. I'd greatly appreciate feedback from maintainers and/or other users who've bumped into this issue.
Thanks for creating aPR @ethagnawl
could you remind me again why won't the following work?
// 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 I'm sure that will work and looks similar to the solution I mentioned above. However, those sorts of solutions are hard to document and potentially fragile (see the solution offered by @TuckerWhitehouse which no longer works).
IMO, codifying this concept is worthwhile as, again, it makes documentation more straightforward and this flag could also be used to make additional optimizations by bypassing/noop-ing/etc. functionality that isn't relevant when Gatsby is being used in this way.
Additionally, using the matchPath
requires the url in the browser to reflect the page you want to render, but this breaks down when you are injecting a gatsby site into an unknown location. (My original issue was around having gatsby behind an apache reverse proxy and not knowing the routes that would cause a certain page to render).
@ethagnawl do you think it would be possible to disable routing at the page level (something like page.__disable_client_side_routing__ = true
)? This would probably resolve the original issue I was having as well.
do you think it would be possible to disable routing at the page level
I don't see why not? Would that be in addition to or in place of my proposed solution? If it's the latter, is there any advantage to doing that at the page level?
I've setup this repo :) https://github.com/wardpeet/gatsby-plugin-static-site
unsure if this works for your use cases. For now you need to do
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
add gatsby-plugin-static-site to your gatsby-config.js
Let me know if this is ok for your use case, I have no intention to actually support it so i'm happy to transfer it :smile:
I updated the repo as I had something wrong in my gitignore file (thanks @m-allanson). I also published it to npm under my own name.
so installation can be done
npm install --save @wardpeet/gatsby-plugin-static-site
and add @wardpeet/gatsby-plugin-static-site
to gatsby-config.json
If this is looking good then I can add some test and some options to disable this behaviour for develop.
Hiya!
This issue has gone quiet. Spooky quiet. 👻
We get a lot of issues, so we currently close issues after 30 days of inactivity. It’s been at least 20 days since the last update here.
If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not stale" to keep this issue open!
Thanks for being a part of the Gatsby community! 💪💜
I would like this to stay open as it looks like it’s waiting on review
I'm not sure it's not stale, I made a fix and hoping to get feedback for it https://github.com/gatsbyjs/gatsby/issues/4337#issuecomment-470075540
If no one responds I think it's a good idea to close this one as it is probably resolved.
@wardpeet is it possible with that plugin to conditionally disable client side routing?
@wardpeet IIRC, your proposed fix is the first step in the process of (maybe, eventually) getting this feature added as a Gatsby config option. So, that sort of makes it out of band as far as this issue and Gatsby are concerned, but I might make the argument that this issue should remain open in order to continue that conversation.
@wardpeet the original issue was about disabling client side routing for specific routes, @ethagnawl brought up the use case of disabling routing for an entire site which is what I believe your plugin addresses.
I need to disable client side routing temporarily while I migrate a site on an old CMS to Gatsby. I'm doing it one page at a time before flipping the switch completely over to just gatsby.
I've tried @wardpeet plugin but it seems to not be working.
@brianbento do you have a reproduction? if you can create an issue on the repo https://github.com/wardpeet/gatsby-plugin-static-site I can have a look what's missing
@wardpeet I'll see if I can get something up. The main issue is that your previously mentioned "fix"(https://github.com/gatsbyjs/gatsby/issues/4337#issuecomment-465497418) doesn't work when you use pathPrefix. It always "corrects" the address to what's expected.
@brianbento Have you tried the solution I mentioned above? That has worked well for me on two different projects.
@ethagnawl I still get the URL correction and then it doubles up the path prefix.
So "/
Maybe I'm implementing it wrong. Did you use path prefix for your pages? Am I supposed to have the static site plugin active?
Did you use path prefix for your pages?
Yes. I was also using this branch to allow for remote assets. So, it's possible that branch introduced behavior which made the fix work for me and not you.
However, it's more likely that recent Gatsby releases (I haven't kept up) have broken my "solution", as it was a hack to begin with.
@ethagnawl Super helpful! Thank you! I know @DSchau made some plugins to test out the assetPrefix feature. I'll give it a shot!
It seems @wardpeet solution doesn't work when you also need to use path prefix. Having a solution like the one proposed __disable_client_side_routing__
that disabled the canonical check would be super cool. I'd be happy to work on it and submit a PR if it'll be considered for merging. Any support for that idea, or do you think it doesn't fit into the roadmap?
@xavivars I would like that and find it useful, for sure.
@xavivars I took a pass at that feature a while back, which was closed in favor of what @wardpeet's solution. If you're going to consider revisiting that approach, it could be worth having a look at my attempt.
Thanks @ethagnawl ! I took a look at your approach, and that was pretty much what I was thinking.
I think @wardpeet solution covers a different use case: the app doesn't behave as an SPA because links are actually changing the browser location.href
, so then it navigates "server side". But I couldn't make it work for my use case because the initial redirect is still happening: my initial hypothesis is there's some sort of interaction with prefixPath
that makes this condition to evaluate to true
https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/cache-dir/production-app.js#L65
Did you manage to make it work properly?
I might be able to do more work on the plugin if anyone can explain me the actual issue as I kinda forgot what I need to fix. Maybe most of this can be resolved by the newly merged assetPrefix option?
Sorry for not understanding.
@xavivars
Did you manage to make it work properly?
Both my hack and the submitted PR were working properly for my use case: single, static page generation with no redirects. I gave up on my PR because the Gatsby team seemed to prefer a plugin instead of an app-level config option.
I never got around to trying @wardpeet's plugin, as I'd already wrapped up the Gatsby project I was working on by the time it was published. So, I can't comment on whether or not that was ever working properly.
@wardpeet: the assetPrefix doesn't fix it. I managed to have it working by using both your plugin (to, basically, disable client side "navigation" when clicking around) and the workaround mentioned by @ethagnawl few months ago
https://github.com/gatsbyjs/gatsby/issues/4337#issuecomment-453244611
That workaround is needed to disable the "navigate" event that happens onClientEntry
. We fixed adding a hook there and applying that workaround (forcing page.path to the actual path). But I have no idea if that has any side effects, and also how long will it take until it stops working (is not more than a hack).
Ideally, I think this should be an app-level config, given the amount of people that seems is using gatsby as a "static page generator"
@xavivars Do you have link you can share with you work around?
Not really, but this is pretty much it:
Add the static plugin mentioned before, and in gastby-browser.js
exports.onClientEntry = () => {
window.page = window.page || {};
window.page.path = window.location.pathname;
}
The following also works, although it relies on gatsby internals:
export function onInitialClientRender() {
window.___navigate = (to, { replace }) => {
if (replace) {
window.location.replace(to);
} else {
window.location.assign(to);
}
};
}
Does using https://github.com/wardpeet/gatsby-plugin-static-site & assetPrefix work?
Linked issue which made the example work, unsure if this is what you actually need. https://github.com/wardpeet/gatsby-plugin-static-site/issues/1#issuecomment-494802726
Description
I have a use case where the server is defining some custom routes. When the browser loads these routes, the expected content is shown for a brief moment until client side routing takes over and replaces the page with the 404 because the url in the browser is not recognized.
My first thought was that maybe the
matchPath
could be used here, but I won't necessarily know the url patterns that would render these pages, and there may be some overlap in what the url is, and what page is returned.I'm guessing it may be possible with some hook into find-page but I'm not sure what that would look like.
Environment
Gatsby version: 1.9.221 Node.js version: 8.9.1 Operating System: macOS
Actual result
After the browser loads, the expected page is shown briefly until the javascript loads, determines the url is unknown, and renders the 404 page.
Expected behavior
The server rendered page should be available at the custom url, and not be replaced by the 404 page when the client loads.
Steps to reproduce
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