NextJS version=13.4.4
Hello, I'm trying to create a static page by importing all the .md files from the _project directory.
I know that if I put the generateStaticParams function into a page file, I can give it parameters for the page, and if I set dynamicParams to false, it will only generate the page for the entry points in generateStaticParams, and return a 404 page for the rest of the entry points.
However, if I leave dynamicParams as false, it actually returns a 404 page for all entry points when accessed from the web.
The other way I tried was to set dynamic to "force-static".
This works fine for entry points that exist in generateStaticParams, but for entry points that don't exist in generateStaticParams, It does not return a 404 page and actually access the page.
Can anyone tell me if what I'm doing is wrong?
// app/portfolio/pages.tsx
import Container from "@/app/components/Container";
import ProjectGrid from "@/app/components/portfolio/ProjectGrid";
import {getAllProjects} from "@/app/lib/etc";
import {ProjectType} from "@/types/ProjectType";
export const dynamic = 'force-static';
const Page = async () => {
const projects: ProjectType[] = await getAllProjects();
return (
<>
<Container>
<div className={`font-light sm:text-xl mt-10 text-md`}>
<span className={`font-medium`}>{projects.length}</span>Projects
</div>
<hr className={`mt-3 mb-10`} />
<ProjectGrid projects={projects} />
</Container>
</>
);
};
export default Page;
// app/portfolio/[slug]/page.tsx
import Container from "@/app/components/Container";
import {getAllProjects, getProject} from "@/app/lib/etc";
export const dynamic = 'force-static';
// export const dynamicParams = false;
export const generateStaticParams = async () => {
// get all projects from _project directory
const projects = await getAllProjects();
return projects.map((item) => {
return {
params: {
slug: item.name.replace(/ /g, "-")
}
};
});
};
interface Params {
params: {
slug: string
}
}
const Page = async ({ params }: Params) => {
const { name, description, content }: any = await getProject(params.slug);
return (
<Container>
<div className={"mt-20"}>
<div className={`font-bold text-3xl`}>{ name }</div>
<div className={`font-light text-md`}>{ description }</div>
<div className={`mt-10`} dangerouslySetInnerHTML={{ __html: content }} />
</div>
</Container>
);
};
export default Page;
// app/lib/etc.ts
import {join} from 'path';
import fs from "fs";
import matter from 'gray-matter';
import {ProjectType} from "@/types/ProjectType";
const cwd = process.cwd();
const projectsDirectory = join(cwd, '_projects');
const getAllMdFiles = () => {
return fs.readdirSync(projectsDirectory).filter((path) => /\.md?$/.test(path));
}
const parseMarkdown = async (filename: string) => {
const markdownWithMetadata = fs.readFileSync(
join(projectsDirectory, filename),
'utf-8'
);
const { data } = matter(markdownWithMetadata);
return {
...data,
}
}
type Item = {
[key: string]: string;
}
export const getAllProjects = async () => {
const mdFiles = getAllMdFiles();
const projects: ProjectType[] = [];
for (const file of mdFiles) {
projects.push(await parseMarkdown(file) as ProjectType);
}
return projects;
}
export const getProject = async (slug: string) => {
const parsed = decodeURIComponent(slug);
const markdownWithMetadata = fs.readFileSync(
join(projectsDirectory, `${parsed}.md`),
'utf-8'
);
const { data, content } = matter(markdownWithMetadata);
return {
...data,
content,
}
}