fedeya/remix-sitemap

'No route matches URL' console errors

lewsmith opened this issue · 4 comments

I've got my sitemaps setup and generating output okay - works like a charm.

However in the console I'm seeing errors about route matching. Example for a /sitemap.txt request, which displays the sitemap fine, but shows this error for every request.

GET /sitemap.xml 200 773 - 1.659 ms
Error: No route matches URL "/robots.txt"
    at getInternalRouterError (./node_modules/.pnpm/@remix-run+router@1.9.0/node_modules/@remix-run/router/router.ts:4144:5)
    at Object.query (./node_modules/.pnpm/@remix-run+router@1.9.0/node_modules/@remix-run/router/router.ts:2628:19)
    at handleDocumentRequestRR (./node_modules/.pnpm/@remix-run+server-runtime@2.0.0_typescript@5.2.2/node_modules/@remix-run/server-runtime/dist/server.js:138:35)
    at requestHandler (./node_modules/.pnpm/@remix-run+server-runtime@2.0.0_typescript@5.2.2/node_modules/@remix-run/server-runtime/dist/server.js:63:24)
    at ./node_modules/.pnpm/@remix-run+express@2.0.0_express@4.18.2_typescript@5.2.2/node_modules/@remix-run/express/dist/server.js:41:28

I think I've set it up exactly as required in my entry.server.tsx:

import { PassThrough } from 'node:stream';

import {
  EntryContext,
  createReadableStreamFromReadable,
} from '@remix-run/node';
import { RemixServer } from '@remix-run/react';
import isbot from 'isbot';
import { renderToPipeableStream } from 'react-dom/server';
import { createSitemapGenerator } from 'remix-sitemap';
import { configMeta } from './configs';

const ABORT_DELAY = 5_000;

const { isSitemapUrl, sitemap } = createSitemapGenerator({
  siteUrl: configMeta?.url,
  generateRobotsTxt: true,
});

export default async function handleRequest(
  request: Request,
  responseStatusCode: number,
  responseHeaders: Headers,
  remixContext: EntryContext,
) {
  if (isSitemapUrl(request)) {
    return await sitemap(request, remixContext);
  }

  return isbot(request.headers.get('user-agent'))
    ? handleBotRequest(
        request,
        responseStatusCode,
        responseHeaders,
        remixContext,
      )
    : handleBrowserRequest(
        request,
        responseStatusCode,
        responseHeaders,
        remixContext,
      );
}

function handleBotRequest(
  request: Request,
  responseStatusCode: number,
  responseHeaders: Headers,
  remixContext: EntryContext,
) {
  return new Promise((resolve, reject) => {
    let shellRendered = false;
    const { pipe, abort } = renderToPipeableStream(
      <RemixServer
        context={remixContext}
        url={request.url}
        abortDelay={ABORT_DELAY}
      />,
      {
        onAllReady() {
          shellRendered = true;
          const body = new PassThrough();

          responseHeaders.set('Content-Type', 'text/html');

          resolve(
            new Response(createReadableStreamFromReadable(body), {
              headers: responseHeaders,
              status: responseStatusCode,
            }),
          );

          pipe(body);
        },
        onShellError(error: unknown) {
          reject(error);
        },
        onError(error: unknown) {
          responseStatusCode = 500;
          if (shellRendered) {
            console.error(error);
          }
        },
      },
    );

    setTimeout(abort, ABORT_DELAY);
  });
}

function handleBrowserRequest(
  request: Request,
  responseStatusCode: number,
  responseHeaders: Headers,
  remixContext: EntryContext,
) {
  return new Promise((resolve, reject) => {
    let shellRendered = false;
    const { pipe, abort } = renderToPipeableStream(
      <RemixServer
        context={remixContext}
        url={request.url}
        abortDelay={ABORT_DELAY}
      />,
      {
        onShellReady() {
          shellRendered = true;
          const body = new PassThrough();

          responseHeaders.set('Content-Type', 'text/html');

          resolve(
            new Response(createReadableStreamFromReadable(body), {
              headers: responseHeaders,
              status: responseStatusCode,
            }),
          );

          pipe(body);
        },
        onShellError(error: unknown) {
          reject(error);
        },
        onError(error: unknown) {
          responseStatusCode = 500;
          if (shellRendered) {
            console.error(error);
          }
        },
      },
    );

    setTimeout(abort, ABORT_DELAY);
  });
}

One way I managed to stop the error is by creating the route routes/sitemap[.]xml.tsx and just return null, but that seems a bit hacky.

Have I done something wrong? Does anyone else see this?

Expected behavior
To show either the sitemap or robots file, without the console displaying the errors.

Environment (please complete the following information):

  • OS: Manjaro
  • Node version: 18
  • Remix version: 2.0.0
  • remix-sitemap version: 2.2.7

Another way to avoid these errors is to define some routes in the remix config, but I'm not sure if this is any better than creating the two null routes TBH.

E.g.

// remix.confg.js
export default {
   ...
   routes: async (defineRoutes) => { 
    return defineRoutes((route) => {
      route("/sitemap.xml", "routes/_null.tsx", {id: 'routes/sitemap.xml'}),
      route("/robots.txt", "routes/_null.tsx", {id: 'routes/robots.txt'})
    })
  }
};
// routes/_null.tsx
export default function NullRoute() {
  return null;
}

I'm seeing the same thing - the sitemap renders fine but I get this:

Error: No route matches URL "/sitemap.xml"
    at getInternalRouterError (/Users/justinhandley/IdeaProjects/muzebook/node_modules/.pnpm/@remix-run+router@1.9.0/node_modules/@remix-run/router/router.ts:4144:5)
    at Object.query (/Users/justinhandley/IdeaProjects/muzebook/node_modules/.pnpm/@remix-run+router@1.9.0/node_modules/@remix-run/router/router.ts:2628:19)
    at handleDocumentRequestRR (/Users/justinhandley/IdeaProjects/muzebook/node_modules/.pnpm/@remix-run+server-runtime@2.0.1_typescript@5.1.6/node_modules/@remix-run/server-runtime/dist/server.js:138:35)
    at requestHandler (/Users/justinhandley/IdeaProjects/muzebook/node_modules/.pnpm/@remix-run+server-runtime@2.0.1_typescript@5.1.6/node_modules/@remix-run/server-runtime/dist/server.js:63:24)
    at /Users/justinhandley/IdeaProjects/muzebook/node_modules/.pnpm/@remix-run+express@2.0.1_express@4.18.2_typescript@5.1.6/node_modules/@remix-run/express/dist/server.js:41:28

GET /sitemap.xml 200 767 - 53.260 ms
fedeya commented

It seems this is a remix v2 bug.
If this doesn't improve in future versions of the remix, it may be necessary to think about somewhere else to put the sitemap response.

fedeya commented

Hi @lewsmith @justinhandley to fix this i released a new version (3.1.0) with a new api to just generate the sitemap and robots in each route, i marked it as experimental because i didn't test it on all plataforms.

Here you can see a usage guide https://github.com/fedeya/remix-sitemap/releases/tag/v3.1.0