Skip to content

Commit

Permalink
Update client-only-routes-and-user-authentication.md (#30602)
Browse files Browse the repository at this point in the history
  • Loading branch information
KyleAMathews authored Apr 1, 2021
1 parent d97b009 commit 8f644eb
Showing 1 changed file with 13 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Often you want to create a site with client-only portions, which allows you to g

A classic example would be a site that has a landing page, various marketing pages, a login page, and then an app section for logged-in users. The logged-in section doesn't need to be server rendered as all data will be loaded live from your API after the user logs in. So it makes sense to make this portion of your site client-only.

Client-only routes will exist on the client only and will not correspond to `index.html` files in an app's built assets. If you'd like site users to be able to visit client routes directly, you need to [set up your site to handle those routes](#handling-client-only-routes-with-gatsby) appropriately. Or, if you have control over the configuration of the file server yourself (instead of using another static file host like Netlify), you can [set up the server](#configuring-and-handling-client-only-routes-on-a-server) to handle these routes.
Client-only routes will exist on the client only and will not correspond to `index.html` files in an app's built assets in the `/public` directory. If you'd like site users to be able to visit client routes directly, you need to [set up your site to handle those routes](#handling-client-only-routes-with-gatsby) appropriately. Or, if you have control over the configuration of the file server yourself, you can [set up the server](#configuring-and-handling-client-only-routes-on-a-server) to handle these routes.

A sample site might be set up like this:

Expand All @@ -18,11 +18,11 @@ Gatsby converts components in the `pages` folder into static HTML files for the

## Handling client-only routes with Gatsby

Gatsby uses [@reach/router](https://reach.tech/router/) under the hood. This means you don't need to install it separately and it is the recommended approach to create client-only routes.
Gatsby uses [@reach/router](https://reach.tech/router/) under the hood so we'll use it to setup client-only routes within our app.

You first need to set up routes on a page that is built by Gatsby. You can see the routes added to `src/pages/app.js` in the code example below:
You first need to set up routes on a page that is built by Gatsby. You can see the routes added to `src/pages/[app].js` in the code example below:

```jsx:title=src/pages/app.js
```jsx:title=src/pages/[app].js
import React from "react"
import { Router } from "@reach/router" // highlight-line
import Layout from "../components/Layout"
Expand Down Expand Up @@ -55,7 +55,7 @@ Briefly, when a page loads, Reach Router looks at the `path` prop of each compon

With [authentication set up](/docs/how-to/adding-common-features/building-a-site-with-authentication) on your site, you can create a component like a `<PrivateRoute/>` to extend the example above and gate content:

```jsx:title=src/pages/app.js
```jsx:title=src/pages/[app].js
import React from "react"
import { Router } from "@reach/router"
import Layout from "../components/Layout"
Expand Down Expand Up @@ -86,7 +86,6 @@ export default App
The `<PrivateRoute />` component would look something like this one (taken from the [Authentication Tutorial](/tutorial/authentication-tutorial/#controlling-private-routes), which implements this behavior):

```jsx:title=src/components/PrivateRoute.js
// import ...
import React from "react"
import { navigate } from "gatsby"
import { isLoggedIn } from "../services/auth"
Expand All @@ -103,56 +102,21 @@ const PrivateRoute = ({ component: Component, location, ...rest }) => {
export default PrivateRoute
```

### Configuring pages with `matchPath`

To ensure that users can navigate to client-only routes directly, pages in your site need to have the [`matchPath` parameter](/docs/gatsby-internals-terminology/#matchpath) set. Add the following code to your site’s `gatsby-node.js` file:

```javascript:title=gatsby-node.js
// Implement the Gatsby API “onCreatePage”. This is
// called after every page is created.
exports.onCreatePage = async ({ page, actions }) => {
const { createPage } = actions

// Only update the `/app` page.
if (page.path.match(/^\/app/)) {
// page.matchPath is a special key that's used for matching pages
// with corresponding routes only on the client.
page.matchPath = "/app/*"

// Update the page.
createPage(page)
}
}
```

> 💡 Note: There's also a plugin to simplify the creation of client-only routes in your site:
> [gatsby-plugin-create-client-paths](/plugins/gatsby-plugin-create-client-paths/).
The above code (as well as the `gatsby-plugin-create-client-paths` plugin) updates the `/app` page at build time to add the `matchPath` parameter in the page object to make it so that the configured pages (in this case, everything after `/app`, like `/app/dashboard` or `/app/user`) can be navigated to by Reach Router.

_Without_ this configuration set up, a user that clicks on a link to `<yoursite.com>/app/user` will instead be routed to the static `/app` page instead of the component or page you have set up at `/app/user`.

> Tip: For applications with complex routing, you may want to override Gatsby's default scroll behavior with the [shouldUpdateScroll](/docs/reference/config-files/gatsby-browser/#shouldUpdateScroll) Browser API.
## Configuring and handling client-only routes on a server
## How to configure your hosting service to handle client-only routes

If you are hosting on your own server, you can opt to configure the server to handle client-only routes instead of using the `matchPath` method explained above.

Consider the following router and route to serve as an example:

```jsx:title=src/pages/app.js
<Router basepath="/app">
<Route path="/why-gatsby-is-awesome" />
</Router>
```
Site hosting services and software needs some help in order to server client-only routes correctly. Most Gatsby pages have a corresponding html file that the server responds with when a user visits the page e.g. visiting `/blog/my-blog-post/` makes the server respond with `/blog/my-blog-post/index.html`. But client-only routes like `/app/why-gatsby-is-awesome/` don't have a corresponding html file. The server needs to be configured to know to serve instead `/app/index.html`.

In this example with a router and a single route for `/app/why-gatsby-is-awesome/`, the server would not be able to complete this request as `why-gatsby-is-awesome` is a client-side route. It does not have a corresponding HTML file on the server. The file found at `/app/index.html` on the server contains all the code to handle the page paths after `/app`.
Popular hosting services like Gatsby Cloud, Netlify, and Vercel have plugins that automatically configure hosting to handle client-only routes.

A pattern to follow, agnostic of server technology, is to watch for these specific routes and return the appropriate HTML file.
- [Gatsby Cloud](https://www.gatsbyjs.com/plugins/gatsby-plugin-gatsby-cloud/?=cloud)
- [Netlify](https://www.gatsbyjs.com/plugins/gatsby-plugin-netlify/?=netlif)
- Vercel automatically adds its Gatsby plugin.

In this example, when making a `GET` request to `/app/why-gatsby-is-awesome`, the server should respond with `/app/index.html` and let the client handle the rendering of the route with the matching path. It is important to note that the response code should be a **200** (an OK) and not a **301** (a redirect). This can be done with NGINX using [`try_files`](https://docs.nginx.com/nginx/admin-guide/web-server/serving-static-content/#trying-several-options), or an [equivalent directive](https://serverfault.com/questions/290784/what-is-apaches-equivalent-of-nginxs-try-files) if using Apache.
### Self-hosting with Ngninx and Apache

One result of this method is that the client is completely unaware of the logic on the server, decoupling it from Gatsby.
Your server configuration should handle `GET` requests to `/app/*` e.g. `/app/why-gatsby-is-awesome` with `/app/index.html` and let the client handle the rendering of the route with the matching path. It is important to note that the response code should be a **200** (an OK) and not a **301** (a redirect). This can be done with NGINX using [`try_files`](https://docs.nginx.com/nginx/admin-guide/web-server/serving-static-content/#trying-several-options), or an [equivalent directive](https://serverfault.com/questions/290784/what-is-apaches-equivalent-of-nginxs-try-files) if using Apache.

## Additional resources

Expand Down

0 comments on commit 8f644eb

Please sign in to comment.