remix-sitemap icon indicating copy to clipboard operation
remix-sitemap copied to clipboard

'No route matches URL' console errors

Open lewsmith opened this issue 2 years ago • 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/@[email protected]/node_modules/@remix-run/router/router.ts:4144:5)
    at Object.query (./node_modules/.pnpm/@[email protected]/node_modules/@remix-run/router/router.ts:2628:19)
    at handleDocumentRequestRR (./node_modules/.pnpm/@[email protected][email protected]/node_modules/@remix-run/server-runtime/dist/server.js:138:35)
    at requestHandler (./node_modules/.pnpm/@[email protected][email protected]/node_modules/@remix-run/server-runtime/dist/server.js:63:24)
    at ./node_modules/.pnpm/@[email protected][email protected][email protected]/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

lewsmith avatar Sep 19 '23 11:09 lewsmith

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;
}

lewsmith avatar Sep 19 '23 12:09 lewsmith

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/@[email protected]/node_modules/@remix-run/router/router.ts:4144:5)
    at Object.query (/Users/justinhandley/IdeaProjects/muzebook/node_modules/.pnpm/@[email protected]/node_modules/@remix-run/router/router.ts:2628:19)
    at handleDocumentRequestRR (/Users/justinhandley/IdeaProjects/muzebook/node_modules/.pnpm/@[email protected][email protected]/node_modules/@remix-run/server-runtime/dist/server.js:138:35)
    at requestHandler (/Users/justinhandley/IdeaProjects/muzebook/node_modules/.pnpm/@[email protected][email protected]/node_modules/@remix-run/server-runtime/dist/server.js:63:24)
    at /Users/justinhandley/IdeaProjects/muzebook/node_modules/.pnpm/@[email protected][email protected][email protected]/node_modules/@remix-run/express/dist/server.js:41:28

GET /sitemap.xml 200 767 - 53.260 ms

justinhandley avatar Oct 15 '23 21:10 justinhandley

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 avatar Oct 16 '23 00:10 fedeya

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

fedeya avatar Oct 29 '23 21:10 fedeya