My Next.js project is failing to build on Vercel.
I have a BlogAuthor.tsx
file as so:
import Avatar from "../../Common/Avatar/Avatar";
import CopyLink from "../../Common/Widgets/CopyLink/CopyLink";
export default function BlogAuthor({
authorName,
authorAvatar,
postDate,
url,
}) {
return (
<div className="flex w-full lg:px-2">
<Avatar image={authorAvatar} alt={authorName} />
<div className="ml-3 flex flex-col">
<span className="font-semibold">{authorName}</span>
<time className="text-gray-500" dateTime={postDate}>
{new Date(postDate).toDateString()}
</time>
</div>
<div className="ml-auto">
<CopyLink url={url} />
</div>
</div>
);
}
During the build, on Vercel
I get the following error:
> next build
info - Checking validity of types...
Failed to compile.
./components/Blog/BlogAuthor/BlogAuthor.tsx:1:20
Type error: Cannot find module '../../Common/Avatar/Avatar' or its corresponding type declarations.
> 1 | import Avatar from "../../Common/Avatar/Avatar";
| ^
2 | import CopyLink from "../../Common/Widgets/CopyLink/CopyLink";
3 |
4 | export default function BlogAuthor({
Error: Command "npm run build" exited with 1
The blog author is used within a BlogLayout
component. Here is an example of a blog post file:
how-to-value.mdx
:
---
slug: "how-to-value"
title: "Title"
description: "Meta description goes here"
coverImage:
src: "/img/blog/how-to-value/cover.jpg"
alt: "Image alt text"
date: "May 11 2022 12:00:00 AM"
author:
name: "squishyboots"
avatar: "/img/blog/authors/squishyboots.jpeg"
---
//ALL MARKDOWN STUFF GOES HERE
<BlogLink href="/signup" title="Sign up today!" text="Sign up" />
export default ({ children }) => (
<BlogLayout meta={meta}>{children}</BlogLayout>
);
And finally, here is what my [slug].tsx
page looks like:
import { serialize } from "next-mdx-remote/serialize";
import { MDXRemote } from "next-mdx-remote";
import fs from "fs";
import path from "path";
import matter from "gray-matter";
import BlogImage from "@components/Blog/BlogImage/BlogImage";
import BlogLayout from "@components/layouts/BlogLayout/BlogLayout";
import BlogLink from "@components/Blog/BlogLink/BlogLink";
import { HeadOptions } from "@interfaces/interfaces";
const components = {
BlogImage,
BlogLayout,
BlogLink,
};
const BlogPostPage = ({ data, mdxSource, slug }) => {
const headOptions: HeadOptions = {
title: data.title,
description: data.description,
url: slug,
image: data.coverImage,
articleAuthor: data.author,
date: data.date,
};
return (
<BlogLayout meta={headOptions}>
<MDXRemote {...mdxSource} components={components} />
</BlogLayout>
);
};
export async function getStaticPaths() {
const files = fs.readdirSync(path.join("_blog-posts"));
const paths = files.map((filename) => ({
params: {
slug: filename.replace(".mdx", ""),
},
}));
return {
paths,
fallback: false,
};
}
export async function getStaticProps({ params: { slug } }) {
const markdownWithMeta = fs.readFileSync(
path.join("_blog-posts", slug + ".mdx"),
"utf-8"
);
const { data: frontMatter, content } = matter(markdownWithMeta);
const mdxSource = await serialize(content);
return {
props: {
data: frontMatter,
slug,
mdxSource,
},
};
}
export default BlogPostPage;
Therefore, as you can see above I have a components
object that's passed into MDXRemote
. It contains components such as BlogLink
, BlogLayout
etc.
Do I have to add Avatar.tsx
to this list as well? It is not used directly in an .mdx
file.
If so, do I have to include every single component used in this list, even though its just a child of another component? (In this case, BlogAuthor.tsx
)
If this is the case, won't I just have a giant list of components that need adding to every time I use something new in a blog post? That doesn't seem right to me