Next.js Discord

Discord Forum

Vercel deployment not showing fs files

Answered
Giant panda posted this in #help-forum
Open in Discord
Avatar
Giant pandaOP
Getting 404 error while fetching my files
Answered by Giant panda
okay i figured it out : so as in the screenshot the route /posts is not statically generated but fetched at runtime from server as a lambda , so it works fine , but the [id] pages are statically rendered and thus can't use session and stuff coz that's in cookies so basically can't use static generation when i am using sessions. Prolly that static generation thing is for very specific use-cases where we want to deliver static content to everyone.
Image
View full answer

70 Replies

Avatar
Giant pandaOP
so i have a /posts route which reads all .md files
working perfectly fine
but for dynamic route , when i access that individual route say /posts/oauth-blog
then it bugs out
import { getPostsById, getPostsIds } from "@/utils/posts";

export const generateStaticParams = async () => {
  const fileIds = await getPostsIds();
  return fileIds.map((id) => {
    id;
  });
};

const Home = async ({ params }: { params: { id: string } }) => {
  const { id } = params;
  const blogData: any = await getPostsById(id);
  return (
    <div className="prose dark:prose-invert m-auto">
      <div className="text-center p-10">
        <div>
          <h1>{blogData.title}</h1>
        </div>
        <div>Created on ({blogData.date})</div>
      </div>
      <article>
        <div dangerouslySetInnerHTML={{ __html: blogData.contentHtml }} />
      </article>
    </div>
  );
};

export default Home;
this is my /posts/[id]/pages.tsx code
Avatar
Clown
Where is the handler
Avatar
Giant pandaOP
import path from "path";
import { readdir, readFile } from "fs/promises";
import matter from "gray-matter";
import { remark } from "remark";
import html from "remark-html";

export interface PostsMetadata {
  id: string;
  date?: string;
  title?: string;
  about?: string;
}

export const getPostsIds = async () => {
  const postsDirectory = path.join(process.cwd(), "posts");
  const fileNames = await readdir(postsDirectory);

  return fileNames.map((fileName) => fileName.replace(/\.md$/, ""));
};

export const getSortedPostsData = async (): Promise<PostsMetadata[]> => {
  const postsDirectory = path.join(process.cwd(), "posts");
  const fileNames = await readdir(postsDirectory);

  const allPostsData = await Promise.all(
    fileNames.map(async (fileName) => {
      const id = fileName.replace(/\.md$/, "");

      const fullPath = path.join(postsDirectory, fileName);
      const fileContents = await readFile(fullPath, "utf-8");

      const matterResult = matter(fileContents);

      return {
        id,
        ...matterResult.data,
      };
    })
  );

  return allPostsData.sort((a: any, b: any) => {
    if (a.date < b.date) {
      return 1;
    } else {
      return -1;
    }
  });
};

export const getPostsById = async (id: string) => {
  const fullPath = path.join(process.cwd(), "posts", `${id}.md`);
  const fileContents = await readFile(fullPath);

  const matterResult = matter(fileContents);

  const processedContents = await remark()
    .use(html)
    .process(matterResult.content)
  
  const contentHtml = processedContents.toString();
  
  return {
    id,
    contentHtml,
    ...matterResult.data
  }
};
this is the full util file
here allPostsData is working fine , but getPostsById is not working fine
and both operate on same files
so it's not the issue with the files
something is off with static generation of [id] pages
build logs
Image
oh lol figured it out
Avatar
Clown
?
Avatar
Giant pandaOP
the error log :
Page changed from static to dynamic at runtime /posts/oauth-blog, reason: headers
see more here https://nextjs.org/docs/messages/app-static-to-dynamic-error
    at s (/var/task/.next/server/chunks/154.js:30:28531)
    at u (/var/task/.next/server/chunks/154.js:30:25998)
    at s (/var/task/.next/server/chunks/154.js:30:19935)
    at v (/var/task/.next/server/chunks/231.js:1:1990)
    at we (/var/task/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:1:262655)
    at /var/task/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:1:273539
    at Object.toJSON (/var/task/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:1:276836)
    at stringify (<anonymous>)
    at Oe (/var/task/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:1:265286)
    at Me (/var/task/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:1:265817) {
  page: '/posts/oauth-blog'
}
Page changed from static to dynamic at runtime /posts/oauth-blog, reason: headers
see more here https://nextjs.org/docs/messages/app-static-to-dynamic-error
    at s (/var/task/.next/server/chunks/154.js:30:28531)
    at u (/var/task/.next/server/chunks/154.js:30:25998)
    at s (/var/task/.next/server/chunks/154.js:30:19935)
    at v (/var/task/.next/server/chunks/231.js:1:1990)
    at we (/var/task/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:1:262655)
    at /var/task/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:1:273539
    at Object.toJSON (/var/task/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:1:276836)
    at stringify (<anonymous>)
    at Oe (/var/task/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:1:265286)
    at Me (/var/task/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:1:265817) {
  page: '/posts/oauth-blog'
}
Error: Runtime exited with error: exit status 1
Runtime.ExitError
Avatar
Clown
Welp
Avatar
Giant pandaOP
but i am still not sure why page turned dynamic from static
:thinq:
Avatar
Clown
Logs had all the answer
Avatar
Giant pandaOP
this is my [id] page
import { getPostsById, getPostsIds } from "@/utils/posts";

export const generateStaticParams = async () => {
  const fileIds = await getPostsIds();
  return fileIds.map((id) => {
    id;
  });
};

const Home = async ({ params }: { params: { id: string } }) => {
  const { id } = params;
  const blogData: any = await getPostsById(id);
  return (
    <div className="prose dark:prose-invert m-auto">
      <div className="text-center p-10">
        <div>
          <h1>{blogData.title}</h1>
        </div>
        <div>Created on ({blogData.date})</div>
      </div>
      <article>
        <div dangerouslySetInnerHTML={{ __html: blogData.contentHtml }} />
      </article>
    </div>
  );
};

export default Home;
so nothing here which should dynamically change , all pages should be statically build and run
Page changed from static to dynamic at runtime /posts/oauth-blog, reason: headers
:thinq:
Avatar
Clown
I dont think it can do fs read at runtime
Without going dynamic
Avatar
Giant pandaOP
no my other page does
and works totally fine
Avatar
Clown
Does it also use staticParams?
Avatar
Giant pandaOP
no but it's not a dynamic route
so it statically renders by default
Avatar
Clown
Wait wut?
Avatar
Giant pandaOP
?
import { getSortedPostsData } from "@/utils/posts";
import { BlogTile } from "../components/BlogTile";

const Home = async () => {
  const allPostsData = await getSortedPostsData();
  return (
    <div className="h-full flex flex-col space-y-20">
      <div className="text-center text-5xl">All Blogs</div>
      <div className="grid grid-flow-row gap-5 decoration-0 grid-cols-4 h-full grid-rows-3">
        {allPostsData.map(({ id, date, title, about }) => (
          <BlogTile key={id} id={id} title={title} date={date} about={about} />
        ))}
      </div>
    </div>
  );
};

export default Home;
this page is /posts
it's not a dynamic route like [id]/pages.tsx
so it statically renders by default
and is working fine
or am i confusing statically rendering with prerendering + caching ?
:thinq:
let me remove generateStaticParams and try if issue resolves
ok removing it worked
but joulev said that they both statically render
:thinq:
Avatar
Clown
Well duh, but are u using headers somewhere
Avatar
Giant pandaOP
so why generateStaticParams is problem ?
Avatar
Clown
its not the main problem
Thing is, if you dont use generateStaticParams it wont be static, it will be dynamic.

But something is forcing it to be dynamic at runtime.
Avatar
Giant pandaOP
hmm true
Avatar
Clown
anyways, using headers somewhere?
Avatar
Giant pandaOP
it does have a layout file as well
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
import { ReactNode } from "react";
import Link from "next/link";

export default function Layout({ children }: { children: ReactNode }) {
  return (
    <div>
      {children}
      <div className="p-10">
        <Link href="/posts">
          <ArrowBackIcon /> Go Back to Posts
        </Link>
      </div>
    </div>
  );
}
can this be problem ?
Avatar
Clown
Dont think so
Avatar
Giant pandaOP
these are the only 2 files that are local to this route
Avatar
Clown
Its saying its due to headers () so its either tripping or we both are
Avatar
Giant pandaOP
prolly the 2nd 🤣
Avatar
Clown
What about the root layout?
Yeah well probably the latter(monkee brain)
Avatar
Giant pandaOP
that shouldn't be problem coz /posts is rendering fine ?
my root layout uses sessions but that shouldn't be a problem anyways right ?
coz it just takes children and displays them
Avatar
Clown
I honestly dont know but maybe
Its too late rn for my brain to work. So i guess I'll have to leave it you 😭
Avatar
Giant pandaOP
i'll update here if i find something
thanks for your help
Avatar
Giant pandaOP
okay i figured it out : so as in the screenshot the route /posts is not statically generated but fetched at runtime from server as a lambda , so it works fine , but the [id] pages are statically rendered and thus can't use session and stuff coz that's in cookies so basically can't use static generation when i am using sessions. Prolly that static generation thing is for very specific use-cases where we want to deliver static content to everyone.
Image
Answer
Avatar
Giant pandaOP
and this is pretty logical too , if it was static no way we can validate a user so anyone can acces that route