next js dynamic page routing working in localhost but giving file not found error in production - next.js

This is part of my next js project. This website is running perfectly on localhost but when i deploy it on vercel, the /blogs/book/chapter page is giving me file not found enter image description here500 error.
Hosted Page - Website
Source Code - GitHub
Dynamic Routing Folder Structure
Page Structure
chapter.js
import fs from "fs";
import path from "path";
import Head from "next/head";
import DefaultErrorPage from "next/error";
import { useRouter } from "next/router";
import matter from "gray-matter";
import { marked } from "marked";
import styles from "../../../../styles/blog/Chapter.module.css";
import { capitalise } from "../../../../components/blog/Capitalise";
import BlogPostBottom from "../../../../components/blog/BlogPostBottom";
export default function Chapter({ book, chapter, frontmatter, content }) {
// Destructuring
const { description } = frontmatter;
// Router Variable
const router = useRouter();
// If fallback then show this
if (router.isFallback) {
// if (router.isFallback || !book || !chapter || !content) {
return <div>Loading...</div>;
}
if (!book || !chapter || !content || !frontmatter) {
return (
<div>
<DefaultErrorPage statusCode={404} />
</div>
);
}
return (
<div className={styles.bookChapter}>
<Head>
<title>{`${capitalise(chapter)} | ${capitalise(
book
)} | Blog | Manav Goyal`}</title>
<meta
name="description"
content={`Read Blog about this book ${book} covering chapter ${chapter} of topics ${description}`}
/>
</Head>
<h1>{`${capitalise(chapter)} - ${capitalise(book)}`}</h1>
<section
className={styles.bookChapterContent}
dangerouslySetInnerHTML={{ __html: marked(content) }}
></section>
<BlogPostBottom slug={`/blog/${book}`} />
</div>
);
}
export async function getStaticPaths() {
return {
paths: [{ params: { book: "css", chapter: "bootstrap" } }],
// paths: [],
fallback: true,
};
}
// Web crawlers, won't be served a fallback and instead the path will behave as in fallback: 'blocking'
// fallback: true is not supported when using `next export`
export async function getStaticProps({ params }) {
const { book, chapter } = params;
let chapterPost = null;
try {
chapterPost = await fs.promises.readFile(
path.join(`posts/${book}/${chapter}.md`),
"utf-8"
);
} catch (err) {}
const { data: frontmatter, content } = matter(chapterPost);
return {
props: {
book,
chapter,
frontmatter,
content,
},
// redirect: {
// destination: `/blog/${book}`,
// permanent: false,
// },
// revalidate: 1,
};
}
Chapter.defaultProps = {
book: "css",
chapter: "bootstrap",
frontmatter: { description: "CSS", id: "1" },
content: "Error",
};
Posts Folder Structure
Posts Folder Structure
Error
Console
Vercel Function Log

Related

getStatic Path not working for base URL "/" in NextJS

I'm using Prismic and NextJS for the first time.
What I'm trying to is make it so when the user goes to the base url for the page localhost:3000/ in dev something will load. /About and /Pricing are working fine the base url doesn't work.
import { GetStaticPaths, GetStaticProps } from 'next'
import { SliceZone } from '#prismicio/react'
import * as prismicH from "#prismicio/helpers";
import { createClient, linkResolver } from '../../prismicio'
import { components } from '../../slices'
interface HomePageProps {
page: any
}
const HomePage = (props:HomePageProps) => {
return <SliceZone slices={props.page.data.slices} components={components} />
}
export default HomePage
interface HomePageStaticProps {
params: any
previewData:any
}
export async function getStaticProps(props:HomePageStaticProps) {
console.log("DOES NOT FIRE FOR localhost:3000")
const client = createClient({ previewData:props.previewData })
const params = props.params;
const uid = params?.pagePath?.[params.pagePath.length - 1] || "home";
const page = await client.getByUID("page", uid);
return {
props: {
page,
},
}
}
export const getStaticPaths: GetStaticPaths = async () => {
const client = createClient();
const pages = await client.getAllByType("page");
const paths = pages.map((page) => prismicH.asLink(page, linkResolver)) as string[];
console.log(paths) // [ '/pricing', '/about', '/' ]
return {
paths,
fallback: false,
};
}
or to simplify it further
[[...pagePath]].tsx fails when going to localhost:3000/ but does not fail on localhost:3000/about or localhost:3000/pricing.
import { GetStaticPaths, GetStaticProps } from 'next'
interface HomePageProps {
page: string
}
const HomePage = (props:HomePageProps) => {
return <>{props.page}</>
}
export default HomePage
interface HomePageStaticProps {
params: any
previewData:any
}
export async function getStaticProps(props:HomePageStaticProps) {
const params = props.params;
const uid = params?.pagePath?.[params.pagePath.length - 1] || "home";
//const page = await client.getByUID("page", uid);
return {
props: {
page:uid,
},
}
}
export const getStaticPaths: GetStaticPaths = async () => {
const paths = [ '/pricing', '/about', '/' ];
return {
paths,
fallback: false,
};
}
As far as I can see your'e not fetching the right way. In order to to have a clean project I would recommend to use a const var where you can determine between dev and production enviorenment. To do so you can simply create a file for example: constants.js containing the following:
export const baseurl = process.env.NODE_ENV === "production"
? process.env.NEXT_PUBLIC_DOMAIN // <-- your domain on live
: "http://localhost:3000"; // localhost on dev
Now with this you automatically have localhost on your dev. Notice that you need http:// which your'e missing at the moment. Now the next example shows you how to fetch something on your root / by entering the following code:
import { baseurl } from "../utils/constants"; // <-- importing the constant
// This function gets called at build time on server-side.
// It won't be called on client-side, so you can even do
// direct database queries.
export async function getStaticProps() {
// Call an external API endpoint to get posts.
// You can use any data fetching library
const res = await fetch(`${baseurl}/api/posts`)
const posts = await res.json()
// By returning { props: { posts } }, the Blog component
// will receive `posts` as a prop at build time
return {
props: {
posts,
},
}
}
If you are using Create-T3-App
https://github.com/t3-oss/create-t3-app
then
your next.config.mjs will default to this as of Nov 7, 2022
const config = {
reactStrictMode: true,
swcMinify: true,
i18n: {
locales: ["en"],
defaultLocale: "en",
},
};
export default config;
remove
const config = {
reactStrictMode: true,
swcMinify: true,
//i18n: {
// locales: ["en"],
// defaultLocale: "en",
//},
};
export default config;
This will make default "/" pathing work, if you require i18n, I'm sorry I can't help.

NEXT JS: Build exportPathMap for a dynamic page Route

I wanted to build a static export for my NEXT project that looks like following:
- pages
---- index.tsx
---- [pageRoute].tsx
Now I want to statically generate routeId for home page that I have handled as shown below:
import { useRouter } from 'next/router';
import React from 'react';
import { PAGE_ROUTES } from '../constants/config';
import Home from './Home/Home';
type Props = {};
export default function Base({}: Props) {
const router = useRouter();
const route = router.query.pageRoute as string;
let RenderComponent = <div>404: Page Not Found</div>;
switch (route) {
case PAGE_ROUTES.HOME: {
RenderComponent = <Home />;
break;
}
default: {
}
}
return (
<div className='flex flex-col items-center max-w-sm mx-auto'>
{RenderComponent}
</div>
);
}
I am not sure what do I specify in exportPathMaps in next.config.js in order to create static export of home page:
/** #type {import('next').NextConfig} */
module.exports = {
reactStrictMode: true,
exportPathMap: async function (
defaultPathMap,
{ dev, dir, outDir, distDir, buildId }
) {
return {
'/': { page: '/' },
// how do I add configuration for '/home': {page: '/[pageRoute]',query:{pageRoute:'home'}}
};
},
};
when I do this:
'/home': { page: '/[pageRoute]', query: { pageRoute: 'home' } },
It throws error saying:
Error: you provided query values for /home which is an auto-exported page. These can not be applied since the page can no longer be re-rendered on the server. To disable auto-export for this page addgetInitia
lProps
In order to statically pre-render dynamic paths, you should return them from getStaticPaths:
import { useRouter } from 'next/router';
import React from 'react';
import { PAGE_ROUTES } from '../constants/config';
import Home from './Home/Home';
import type { GetStaticPaths } from 'next'
export const getStaticPaths: GetStaticPaths = async () => {
const paths = Object.values(PAGE_ROUTES)
.map(route => [{ params: { pageRoute: route } }])
return {
paths,
fallback: false, // meaning any path not returned by `getStaticPaths` will result in a 404 page
}
}
type Props = {};
export default function Base({}: Props) {
return (
<div className='flex flex-col items-center max-w-sm mx-auto'>
<Home />
</div>
);
}
And, as #juliomalves said, in that case you don't need exportPathMap in next.config.js.
For custom 404 page create 404.tsx in /pages
More about getStaticPaths - https://nextjs.org/docs/api-reference/data-fetching/get-static-paths
fallback: false - https://nextjs.org/docs/api-reference/data-fetching/get-static-paths#fallback-false

My website deployed on Vercel keeps giving me the "429: TOO_MANY_REQUESTS" errors. What could be going wrong, how can I debug this?

Occassionally (maybe about half the time) when I load a page on the website I'm working on, I'm getting an error that looks like this.
429: TOO_MANY_REQUESTS
Code: INTERNAL_FUNCTION_RATE_LIMIT
ID: lhr1::258d8-1638206479250-0a01c8648601
My website hasn't been launched yet, almost nobody visits it but me, so it can't be having too much traffic yet.
The page I'm loading has a getServerSideProps() function that does only one thing - uses prisma to fetch posts from my database, which are sent to my component to be rendered.
I can't imagine what could be causing too many requests.
My vercel usage stats look like this.
What am I doing wrong? What could be causing this? How can I debug this?
For reference, below is all my relevant code. Any chance you could take a look at it and let me know if you have any ideas on what could be happening?
index.tsx has getServerSideProps() function which calls a getPosts() function to fetch the posts.
import Layout from 'components/Layout/Layout'
import PostFeed from 'components/Posts/PostFeed'
import Subnav from 'components/Layout/Subnav'
import Pagination from 'components/Posts/Pagination'
import ProfileHeader from 'components/Users/ProfileHeader'
import TagHeader from 'components/Layout/TagHeader'
import HomeHeader from 'components/CTAs/HomeHeader'
import SubscribeBox from 'components/CTAs/SubscribeBox'
import AdBoxes from 'components/CTAs/AdBoxes'
export default function browse({ posts, postCount, username }) {
return (
<Layout subnav={<Subnav />}>
<PostFeed posts={posts} />
<Pagination postCount={postCount} />
<AdBoxes/>
<SubscribeBox />
<br />
</Layout>
)
}
import { getPosts } from 'prisma/api/posts/get-posts'
import config from 'config.json'
export async function getServerSideProps({ req, query }) {
const { username, sort, tag, search } = query
const { posts, postCount } = await getPosts({
published: true,
searchString: search,
username: username,
tagSlug: tag,
sort: sort,
skip: config.postsPerPage * (parseInt(query.page?.toString()) - 1 || 0),
take: config.postsPerPage,
})
return { props: { posts, postCount, username } }
}
get-posts.ts runs a prisma query and fetches the posts.
import prisma from 'prisma/prismaClient'
export async function getPosts({ username, published, tagSlug, searchString, sort, skip, take }) {
console.log(`Get posts. Sorting: ${sort}`)
// Filter posts by user (to show them on their profile)
let author
if (username) author = await prisma.user.findUnique({ where: { username } })
// Filter by tag
const tagFilter = tagSlug ? {
tags: { some: { slug: tagSlug } }
} : {}
// Search through posts
const search = searchString ? {
OR: [
{ title: { contains: searchString, mode: "insensitive", } },
{ body: { contains: searchString, mode: "insensitive", } },
{ tags: { some: { name: { contains: searchString, mode: "insensitive", } } } },
{ author: { username: { contains: searchString, mode: "insensitive", } } },
],
} : {}
let orderBy = [{ rank: 'desc' }]
if (sort === 'new') orderBy = [{ createdAt: 'desc' }]
if (sort === 'top') orderBy = [{ score: 'desc' }]
const allFilters = {
authorId: author?.id,
published: published,
...search,
...tagFilter,
}
const [posts, postCount] = await prisma.$transaction([
prisma.post.findMany({
where: allFilters,
orderBy: orderBy, //rank: 'desc' //score: 'desc'
take, skip,
include: {
tags: true,
author: {
select: {
username: true
}
},
upvoters: {
select: {
username: true
}
},
// Just for the comment counter
comments: {
select: {
id: true
}
}
}
}),
prisma.post.count({ where: allFilters })
])
return { posts, postCount }
}
the prismaClient which get-posts is using to connect to prisma
import { PrismaClient } from "#prisma/client";
// PrismaClient is attached to the `global` object in development to prevent
// exhausting your database connection limit.
//
// Learn more:
// https://pris.ly/d/help/next-js-best-practices
let prisma: PrismaClient
if (process.env.NODE_ENV === 'production') {
prisma = new PrismaClient()
} else {
if (!global.prisma) {
global.prisma = new PrismaClient()
}
prisma = global.prisma
}
export default prisma
Try going towards getInitialProps which will execute your function on the browser vs getServerSideProps which always goes to your function creating loops as customers refresh your page or traverse through the site.
As to why so many requests, i think as clients traverse your site, you are generating hits to your function in a loop.

Next.js route mismatch in prod build but not in dev

I'm using Next.js and trying to implement incremental static regeneration. My pages structure is:
pages
- [primary]
- article
- [...slug.js]
and my [...slug.js]
import Head from 'next/head'
export default function Article({ post }) {
if (!post) {
return 'loading'
}
const data = post[0];
return (
<div className="container mx-auto pt-6">
<Head>
<title>{`${data.title.rendered}`}</title
</Head>
<main>
<div>{data.content.rendered}</div>
</main>
</div >
)
}
export async function getStaticPaths() {
return {
paths: [{ params: { primary: '', slug: [] } }],
fallback: true,
};
}
export async function getStaticProps({ params }) {
const slug = params.slug[0];
const res = await fetch(`https://.../?slug=${slug}`)
const post = await res.json()
return {
props: { post },
revalidate: 1,
}
}
This works locally when I pass route like: localhost:3000/dance/article/lots-of-dancers-dance-in-unison, it correctly passes the slug and I can query the CMS no problem. But when I run build I get:
Error: Requested and resolved page mismatch: //article /article at normalizePagePath
This is because the static path you are providing for primary is '' (empty).
For empty string value for primary, the static path becomes //article which resolves to /article. This is what the error says.
Though this works in development, it will give the said error in Prod build.
Add a value to the path and it should work!
paths: [{ params: { primary: 'abc', slug: [] } }],

How can I correct SQLite "No such table" in Next.js?

I am studying Next.js and when I was trying to pre-fetch data from a SQLite3 database I encountered the "SQLITE_ERROR: no such table: post" error.
I am certain that the table exists, I've ran a query to be certain and it did returned the expected result. The only other probability that I can think of is that I'm not referencing my database correctly.
I'm using Knex to connect with it.
Here's my code:
database/index.js:
import knex from "knex"
import path from "path"
const database = knex({
client: "sqlite3",
connection: {
filename: path.resolve(__dirname, "database.sqlite")
},
useNullAsDefault: true
})
export default database
libs/posts.js:
import database from "../database"
export const getAllPostsIds = async () => {
try {
let fileNames = await database.select("title").from("post")
return fileNames.map(fileName => {
{
params: {
id: fileName
}
}
})
} catch (error) {
return {
params: {
id: "error: " + error
}
}
}
}
The function call (pages/index.js):
import Head from "next/head"
import Layout from "../components/layout"
import { getAllPostsIds } from "../lib/posts"
export default function Home({ data }) {
return (
<Layout>
<Head>
<title>Home</title>
</Head>
<section></section>
</Layout>
)
}
export const getStaticProps = async ({ params }) => {
const data = await getAllPostsIds()
return {
props: {
data
}
}
}
The relevant tree structure:
|components
|--|layout
|--|--index.js
|database
|--|index.js
|lib
|--|posts.js
|pages
|--|index.js
The error:
{
params: {
id: 'error: Error: select `title` from `post` - SQLITE_ERROR: no such table: post'
}
}
try this:
you can't use __dirname as the path it will return will be different
from the pages directory. Instead you can use process.cwd() which
gives you the directory where Next.js is being executed.
import knex from "knex"
import path from "path"
// Add this line
const __dirname = path.resolve()
const database = knex({
client: "sqlite3",
connection: {
filename: path.resolve(__dirname, "database.sqlite") // or -> path.join(process.cwd(), "database.sqlite")
},
useNullAsDefault: true
})
export default database

Resources