How to Set Up Redirects in Gatsby

 https://www.codeconcisely.com/posts/how-to-set-up-redirects-in-gatsby/

To create a redirect, you need to use createRedirect function in gatsby-node.js.

You can access it from the actions collection inside createPages Gatsby Node API function.

Start by creating a redirects.json file where you will keep your routes.

[
  {
    "from": "/posts/this-is-the-old-url/",
    "to": "/posts/the-new-destination-url/"
  }
]

Use from to specify the route from which you want to direct your users away. Specify the destination route inside the to property.

Now go ahead and import the redirects and use them inside the createPages API.

// gatsby-node.js

const redirects = require('./redirects.json');

exports.createPages = async ({ graphql, actions }) => {
  const { createRedirect } = actions;

  redirects.forEach(redirect => {
    createRedirect({
      fromPath: redirect.from,
      toPath: redirect.to,
    });
  });
};

This code creates a redirect for every entry inside the redirects array that you import from redirects.json.

Since redirects are server side, your hosting platform must handle them for you. For this reason, you can’t test redirects locally while developing.

The most popular hosting options — Gatsby Cloud and Netlify — handle redirects differently. Depending on your platform of choice, you need to install the needed plugin.

Redirects on Netlify

If you are using Netlify for hosting, you will need to install a plugin that handles the redirects for you.

npm i gatsby-plugin-netlify

Don’t forget to add it to your gatsby-config.js as well.

// gatsby-config.js

module.exports = {
  plugins: ['gatsby-plugin-netlify'],
};

Your redirects should now work after deploying your site on Netlify.

If you would like to redirect an entire subdirectory to a new location, you can use splats for that.

Let’s say you moved your blog posts from /blog/post-name to /posts/post-name. You can redirect all your old /blog/* URLs to /posts.

// redirects.json

[
  {
    "from": "/blog/*",
    "to": "/posts/:splat"
  }
]

You can turn to Netlify’s documentation article Redirect options for more information.

Redirects on Gatsby Cloud

To have your redirects work on Gatsby Cloud, you need to install the gatsby-plugin-gatsby-cloud plugin.

npm i gatsby-plugin-gatsby-cloud

And add it to your gatsby-config.js.

// gatsby-config.js

module.exports = {
  plugins: ['gatsby-plugin-netlify'],
};

The syntax for splat redirects on Gatsby Cloud differs from Netlify. To redirect all requests from /blog/ subdirectory to /posts/ subdirectory, use an asterisk (*).

// redirects.json

[
  {
    "from": "/blog/*",
    "to": "/posts/*"
  }
]

Check out the Working with Redirects and Rewrites article to learn about other options on Gatsby Cloud redirects.

Using multiple queries or entries on gatsbyjs createPages Node API

 https://swas.io/blog/using-multiple-queries-on-gatsbyjs-createpages-node-api/

Gatsbyjs Node API provides great many ways to create static pages for your application. The thing I like most about it is, the complete control it gives. Essentially to create a page, we need to

  1. Supply path or slug of the page.
  2. A react component template.
  3. Data.

NOTE: The article is written for gatsbyjs v2, and it may still work for v1.

Gatsby doesn't care how and where the data came from, it can be from a graphql query or maybe something else too. It just creates a page at the provided path, passes the data to your react component and again you are in control of how to present the data.

So I was in a situation where I needed to iterate over a multiple thing, which was based on promise interface and I needed createPages to wait for all the promise to resolve. Basically I was:

  1. Fetching some markdown files using graphql query.
  2. Fetching some directory from the file-system using Nodejs fs API.

This is the solution I came up with.

USE Promise.all INTERFACE

Under gatsby-node.js file, we usually define createPages like this:

// Create pages for docs
exports.createPages = ({ actions, graphql }) => {
	const { createPage } = actions;
	const docTemplate = path.resolve('src/templates/docTemplate.js');

	// Individual doc pages
	return graphql(`
		{
			allMarkdownRemark(
				filter: { fileAbsolutePath: { glob: "**/docs/**/*.md" } }
				sort: { order: DESC, fields: frontmatter___order }
			) {
				edges {
					node {
						fields {
							slug
						}
					}
				}
			}
		}
	`).then(result => {
		if (result.errors) {
			Promise.reject(result.errors);
		}

		result.data.allMarkdownRemark.edges.forEach(({ node }) => {
			createPage({
				path: node.fields.slug,
				component: docTemplate,
			});
		});
	});
};

As we can see, here we are just returning one single Promise, we get with graphql function and gatsby is taking care of waiting till it is resolved. This is just how Promise work, they don't resolve until we call resolve() or all chainables are passed.

So naturally the right way to wait for multiple queries would be to have multiple Promise and return a Promise.all([promiseOne, promiseTwo]). Let's see an example

// Create pages for docs and docRoots
exports.createPages = ({ actions, graphql }) => {
	const { createPage } = actions;
	const docTemplate = path.resolve('src/templates/docTemplate.js');
	const docRootTemplate = path.resolve('src/templates/docRootTemplate.js');

	// Individual doc pages
	// graphql already returns a promise
	// so we can use that instead of creating our own Promise instance
	const docs = graphql(`
		{
			allMarkdownRemark(
				filter: { fileAbsolutePath: { glob: "**/docs/**/*.md" } }
				sort: { order: DESC, fields: frontmatter___order }
			) {
				edges {
					node {
						fields {
							slug
						}
					}
				}
			}
		}
	`).then(result => {
		if (result.errors) {
			Promise.reject(result.errors);
		}

		result.data.allMarkdownRemark.edges.forEach(({ node }) => {
			createPage({
				path: node.fields.slug,
				component: docTemplate,
			});
		});
	});

	// Doc root pages
	// This is a `sync` operation, but we are wrapping
	// inside a Promise, because that's what gatsby Node API
	// expects.
	const docRoots = new Promise((resolve, reject) => {
		// First get all directories inside docs
		const docTypes = dirs(path.resolve(__dirname, './docs'));
		if (docTypes && docTypes.length) {
			docTypes.forEach(docType => {
				createPage({
					path: `/${docType}/`,
					component: docRootTemplate,
					context: {
						docType,
					},
				});
			});
			resolve();
		} else {
			reject(new Error(`No directories found for document roots.`));
		}
	});

	return Promise.all([docs, docRoots]);
};

Here we are

  1. Querying through graphql our markdown files.
  2. At the same time, we are querying directories to get child directory and creating pages for them too. Here the operation is synchronous but we are still using promise interface to demonstrate the working of asynchronous operations.
  3. Finally we are returning Promise.all([...]), which would return a promise interface, which in turn, would wait for all the individual Promises we have passed to it.

And that's how it works.

WHAT IF I NEED MULTIPLE graphql QUERIES?

In most of the cases you don't. Just use a single graphql query and extract data from it.

For example, if we were to extract files from src/pages/guide/**/*.md, and src/blog/**/*.md, then instead of writing two queries, we can very much do

// Create pages for docs
exports.createPages = ({ actions, graphql }) => {
	const { createPage } = actions;
	const docTemplate = path.resolve('src/templates/docTemplate.js');
	const blogTemplate = path.resolve('src/templates/blogTemplate.js');

	// Individual doc and blog pages
	// All in one go
	return graphql(`
		{
			blogs: allMarkdownRemark(
				filter: { fileAbsolutePath: { glob: "**/src/pages/blog/*.md" } }
				sort: { order: DESC, fields: frontmatter___date }
			) {
				edges {
					node {
						fields {
							slug
						}
					}
				}
			}
			docs: allMarkdownRemark(
				filter: {
					fileAbsolutePath: { glob: "**/src/pages/project/*.md" }
				}
				sort: { order: DESC, fields: frontmatter___order }
			) {
				edges {
					node {
						fields {
							slug
						}
					}
				}
			}
		}
	`).then(result => {
		if (result.errors) {
			Promise.reject(result.errors);
		}

		// Create doc pages
		result.data.docs.edges.forEach(({ node }) => {
			createPage({
				path: node.fields.slug,
				component: docTemplate,
			});
		});
		// Create blog pages
		result.data.blogs.edges.forEach(({ node }) => {
			createPage({
				path: node.fields.slug,
				component: docTemplate,
			});
		});
	});
};

Notice we are querying docs and blogs under the same graphql

{
	blogs: allMarkdownRemark(
		filter: { fileAbsolutePath: { glob: "**/src/pages/blog/*.md" } }
		sort: { order: DESC, fields: frontmatter___date }
	) {
		edges {
			node {
				fields {
					slug
				}
			}
		}
	}
	docs: allMarkdownRemark(
		filter: { fileAbsolutePath: { glob: "**/src/pages/project/*.md" } }
		sort: { order: DESC, fields: frontmatter___order }
	) {
		edges {
			node {
				fields {
					slug
				}
			}
		}
	}
}

and extracting the results using result.data.blogs and result.data.docs.

IMHO, this is the perfectly fine way to have multiple query dependent createPage stuff.

But if, for some reason, you absolutely MUST have parallel running multiple queries, then again you can use the promise interface. Let's convert the same example into multiple queries.

// Create pages for docs and blogs separately using two separate
// queries. We use the `graphql` function which returns a Promise
// and ultimately resolve all of them using Promise.all(Promise[])
exports.createPages = ({ actions, graphql }) => {
	const { createPage } = actions;
	const docTemplate = path.resolve('src/templates/docTemplate.js');
	const blogTemplate = path.resolve('src/templates/blogTemplate.js');

	// Individual blogs pages
	const blogs = graphql(`
		{
			blogs: allMarkdownRemark(
				filter: { fileAbsolutePath: { glob: "**/src/pages/blog/*.md" } }
				sort: { order: DESC, fields: frontmatter___date }
			) {
				edges {
					node {
						fields {
							slug
						}
					}
				}
			}
		}
	`).then(result => {
		if (result.errors) {
			Promise.reject(result.errors);
		}

		// Create blog pages
		result.data.blogs.edges.forEach(({ node }) => {
			createPage({
				path: node.fields.slug,
				component: blogTemplate,
			});
		});
	});

	// Individual docs pages
	const docs = graphql(`
		{
			docs: allMarkdownRemark(
				filter: {
					fileAbsolutePath: { glob: "**/src/pages/project/*.md" }
				}
				sort: { order: DESC, fields: frontmatter___order }
			) {
				edges {
					node {
						fields {
							slug
						}
					}
				}
			}
		}
	`).then(result => {
		if (result.errors) {
			Promise.reject(result.errors);
		}

		// Create doc pages
		result.data.docs.edges.forEach(({ node }) => {
			createPage({
				path: node.fields.slug,
				component: docTemplate,
			});
		});
	});

	// Return a Promise which would wait for both the queries to resolve
	return Promise.all([blogs, docs]);
};

Here we are creating multiple Promisees blogs and docs. Notice we are again just using graphql directly, which actually returns a Promise. We are calling .then() to chain a callback function, under which we are creating the pages through createPage API.

Returning Promise.all([blogs, docs]) ensures that our operation is successfully completed, before gatsby moves to create page files.

StaticImage

  import React , { useEffect , useRef } from "react" import { StaticImage } from "gatsby-plugin-image" impor...