faustjs icon indicating copy to clipboard operation
faustjs copied to clipboard

handleSitemapRequests will not work with next.js ^12.2.0

Open priard opened this issue 2 years ago • 5 comments

The recently released Next version 12.2.0 introduces several changes, including stable middleware. Among other things, the middleware limited possibility of returning a response body, which we need for processed sitemap.

First error:

error - Nested Middleware is not allowed, found: pages/_middleware Please move your code to a single file at /src/middleware instead.

Second error:

Your middleware function returns a response body, which is not supported.

More info about error: Returning response body in middleware Middleware (Stable)

We need to find a solution for this, in the meantime I suggest to update package.json in the examples to limit the maximum version to 12.1.6.

"next": "<=12.1.6",

priard avatar Jun 29 '22 11:06 priard

Hey @priard,

Thanks for reporting the issue!

Yes, with Next.js middleware now out of beta, they made some unexpected (imo) changes that effect how middleware work.

The first issue with nested middleware is easy to solve from the sitemap perspective. But the lack of support for returning a response body will require some additional thought from how we want to support sitemaps going forward.

We've created a ticket in our internal backlog (MERL-357) to address this.

In the meantime, I agree we should limit the version in the example project's package.json file. I'll create a PR for this.

blakewilson avatar Jun 29 '22 17:06 blakewilson

Hey, is there anything new on the subject?

roeean avatar Jul 13 '22 16:07 roeean

Hi @roeean, we are activately working on a solution for this in our current development sprint.

blakewilson avatar Jul 28 '22 14:07 blakewilson

is there any update ? i am actively looking into this thread

rizwan92 avatar Aug 27 '22 17:08 rizwan92

@rizwan92

is there any update ? i am actively looking into this thread

Doing something like this as a quick hacky fix: sitemap.xml.ts in the pages directory with the following:

const Sitemap = () => {};

export const getServerSideProps = async ({ res }) => {
  const baseUrl = {
    development: "http://localhost:3000",
    production: "https://yourwebsite.org",
  }[process.env.NODE_ENV];

  const pages = await fetch(
    `${process.env.NEXT_PUBLIC_WORDPRESS_URL}/graphql`,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Accept: "application/json",
      },
      body: JSON.stringify({
        query: `
            query {
                posts {
                    edges {
                        node {
                            slug
                            date
                        }
                    }
                }
                pages {
                    edges {
                        node {
                            slug
                            date
                        }
                    }
                }
                events {
                    edges {
                        node {
                            slug
                            date
                        }
                    }
                }
                resources {
                    edges {
                        node {
                            slug
                            date
                        }
                    }
                }
            }
        `,
      }),
    }
  )
    .then((res) => res.json())
    .then((res) => {
      const posts = res.data.posts.edges.map((post) => {
        return {
          url: `${baseUrl}/news/${post.node.slug}/`,
          lastmod: post.node.date,
        };
      });
      const pages = res.data.pages.edges.map((page) => {
        return {
          url: `${baseUrl}/${page.node.slug}/`,
          lastmod: page.node.date,
        };
      });
      const events = res.data.events.edges.map((event) => {
        return {
          url: `${baseUrl}/events/${event.node.slug}/`,
          lastmod: event.node.date,
        };
      });
      const resources = res.data.resources.edges.map((resource) => {
        return {
          url: `${baseUrl}/resources/${resource.node.slug}/`,
          lastmod: resource.node.date,
        };
      });
      return { posts, pages, events, resources };
    })
    .catch((err) => {
      console.log(err);
      return [];
    });

  const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
    <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
        ${pages["pages"]
          .map(({ url, lastmod: date }) => {
            if (url === `${baseUrl}/testing/`) {
              return null;
            }
            return `
            <url>
                <loc>${url}</loc>
                <lastmod>${date}</lastmod>
                <changefreq>daily</changefreq>
                <priority>1.0</priority>
            </url>
            `;
          })
          .join("")}
        ${pages["posts"]
          .map(({ url, lastmod: date }) => {
            return `
                <url>
                <loc>${url}</loc>
                <lastmod>${date}</lastmod>
                <changefreq>daily</changefreq>
                <priority>1.0</priority>
                </url>
            `;
          })
          .join("")}
        ${pages["events"]
          .map(({ url, lastmod: date }) => {
            return `
                <url>
                <loc>${url}</loc>
                <lastmod>${date}</lastmod>
                <changefreq>daily</changefreq>
                <priority>1.0</priority>
                </url>
            `;
          })
          .join("")}
        ${pages["resources"]
          .map(({ url, lastmod: date }) => {
            return `
                <url>
                <loc>${url}</loc>
                <lastmod>${date}</lastmod>
                <changefreq>daily</changefreq>
                <priority>1.0</priority>
                </url>
            `;
          })
          .join("")}
    </urlset>
  `;

  res.setHeader("Content-Type", "text/xml");
  res.write(sitemap);
  res.end();

  return {
    props: {},
  };
};

export default Sitemap;

CesarBenavides777 avatar Aug 27 '22 18:08 CesarBenavides777

Hello @priard. We've recently added a helper that overcomes this issue with next.js. Unfortunately we haven't documented this yet but its easy to use it.

Here is how to enable this:

  1. Create a sitemap.xml.ts in the pages directory:

  2. Create a page that handles the sitemap request:

import {getSitemapProps} from '@faustjs/next/server';
export default function Page() {
  return null;
}

export const getServerSideProps = async (ctx) => {
  return getSitemapProps(ctx, {
    frontendUrl: 'http://localhost:3000', // or your public frontend URL
    wpUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL,
    sitemapIndexPath: '/wp-sitemap.xml' // path in WordPress that handles sitemaps
  });
}

Visit your page at frontendUrl/sitemap.xml and you should be able to see the sitemaps.

I hope this helps.

theodesp avatar Oct 21 '22 10:10 theodesp