0

Today I started writing a small Next.js app. I'm running a custom server using Fastify and the @fastify/nextjs plugin, but am running into issues loading dynamic routes.

Here's a snippet of my index.ts:

// ... Imports above

export const PORT = +(process.env.PORT ?? 3000);

run(async () => {
    // Initialize Fastify
    const app = fastify({ logger: true, pluginTimeout: 20e3 });

    // Initialize Apollo
    const apollo = new ApolloServer({
        typeDefs,
        resolvers,
        csrfPrevention: true,
        cache: 'bounded',
        plugins: [fastifyAppClosePlugin(app), ApolloServerPluginDrainHttpServer({ httpServer: app.server })],
    });

    console.log('Registering Fastify plugins.');
    // ... Register helmet, compression, cookie, and session plugins

    console.log('Registering Fastify Next.js plugin.');
    // Make Fastify work with Next.js
    await app.register(nextJSPlugin, { dev: true });
    // Make Fastify serve up all Next.js pages
    app.next('*');

    console.log('Starting Apollo server.');
    // Start the Apollo server
    await apollo.start();
    // Make Fastify handle GraphQL requests
    app.register(apollo.createHandler());

    console.log(`Waiting for connection to MongoDB at ${MONGODB_URI}`);
    await mongoConnection.asPromise();

    console.log('Starting the server...');
    // Start the Fastify server
    app.listen({ port: PORT }, () => {
        console.log(`Server running on port ${PORT}`);
        console.log(`GraphQL endpoint: ${apollo.graphqlPath}`);
    });
});

The pages for the Next.js app load perfectly fine except for the dynamic routes. I have pages on / and /test, which both work fine. But on this route [slug], the browser just hangs forever.

Here's what [slug].tsx looks like:

import { GetStaticPaths, GetStaticProps } from 'next';
import React from 'react';
// Configured Apollo client
import { client } from '../apollo/client';
import { PAGES } from '../apollo/queries';
import { PageType } from '../server/models/types';

type PageProps = {
    slug: string;
    content: string;
};

const Slug = ({ slug, content }: PageProps) => {
    return <div>thank god it loaded</div>;
};

export default Slug;

export const getStaticPaths: GetStaticPaths = async () => {
    const { data } = await client.query<{ pages: PageType[] }>({
        query: PAGES,
    });

    return {
        // The routes supported here are defined by the records in the "Pages" collection in my database
        paths: data.pages.filter(({ slug }) => slug !== '/').map(({ slug }) => ({ params: { slug } })),
        fallback: false,
    };
};

export const getStaticProps: GetStaticProps = async ({ params }) => {
    const { slug } = params as { slug: string };

    const { data } = await client.query<{ pages: [PageType] }>({
        query: PAGES,
        variables: {
            slug,
        },
    });

    return {
        props: data.pages[0],
        revalidate: 30,
    };
};
  1. I've ensured that my GraphQL server is running and healthy - the pages query works totally fine in Postman, Insomnia, and with cURL.
  2. I've triple checked and made sure that I initialized Apollo Client correctly. It is successfully connecting to the GraphQL server.

What could the issue be? Is it my file structure? Here's a rundown of what that looks like:

 - index.ts
 - /server
   - /config
   - /schemas
   - /models
   - /utils
 - /pages
  - _app.tsx
  - index.ts
  - [slug].tsx

I'm also using ts-node to ... yup, that was the issue.

mstephen19
  • 1,733
  • 1
  • 5
  • 20

1 Answers1

0

I was using the command nodemon --exec ts-node-esm index.ts to run the code, but I'm not using ESModules in my project anymore, so while typing this question I switched it to nodemon --exec ts-node index.ts and the page loads.

The reason (I believe) is because behind the scenes Next.js dynamically imports the getStaticProps and getStaticPaths functions from your component, and imports work differently between CommonJS and ESModules.

Spent an hour trying to solve this, wow.

mstephen19
  • 1,733
  • 1
  • 5
  • 20