Cover Image for 如何使用 Next.js 构建博客和个人网站(免费托管!)
[Blog][Next.js]
2025年3月16日

如何使用 Next.js 构建博客和个人网站(免费托管!)

嗨!我决定创建自己的博客和个人网站。对于博客,我使用了一个现成的模板并进行了自定义,而个人页面则是从头开始构建的。在本文中,我将分享我如何选择模板、修改模板、设计个人页面以及开发网站的过程。如果您也想创建类似的东西,您可能会在这里找到一些有用的想法。

网站截图

网站截图

选择模板

当我开始制作博客时,我意识到从头开始构建它会花费太多时间。因此,我决定寻找现成的 Next.js 模板。他们的目录提供了博客、在线商店、个人页面,甚至是 AI 初创公司网站的解决方案。

Next.js 截图

在博客模板中,我选择了一个不需要数据库的模板。我希望网站是完全静态的,这样我就可以将其托管在GitHub Pages上,而 GitHub Pages 不支持数据库。

我的目标是创建一个没有基础设施成本的免费博客。这就是为什么我选择了使用 Next.js 静态生成Markdown 文件作为数据源的模板。这种方法使得添加新文章变得容易,同时保持一切无服务器。

设置项目

要开始,请使用命令行创建项目:

npx create-next-app --example blog-starter blog-starter-app

之后,只需将模板的示例文章替换为您自己的文章。

代码截图

最后一步是为存储库设置 GitHub Pages 并将 CNAME 链接到所需的域名。

设计个人页面

博客已经准备好了,但我还需要一个个人页面来展示关于我自己和我项目的信息。

Figma 社区提供了许多免费的和付费的各种项目模板。关键是要检查许可证。我在寻找免费使用的选项,但最后,我只是从现有设计中汲取灵感并创建了自己的设计。

Figma 截图

开发和实施

对于开发,我使用了 Next.jsTailwind CSS

  • Next.js 非常适合,因为我将个人页面集成到了现有的博客模板中。
  • 我选择了 Tailwind CSS,因为它的便利性——它允许您直接在代码中为元素设置样式,而无需单独的 CSS 文件。这加快了开发速度并保持代码整洁。

由于这种方法,实现花费的时间非常少

这是 header 的结构示例:

const Header: React.FC<{ opacity?: boolean }> = ({ opacity }) => {
  const { asPath, locale } = useRouter();
  const { t } = useTranslation();

  return (
    <>
      <header
        className={cn(
          "sticky top-0 w-full specm:h-[3.375rem] h-[2.25rem] z-10 font-montserrat font-semibold text-[0.875rem] flex items-center border-b border-neutral-200",
          opacity ? "bg-[#ffffff99]" : "bg-white"
        )}
      >
        <SpecContainer className="flex justify-between">
          <Link href="/" locale={locale} className="font-[arial-black]">
            PROGOSLING
          </Link>
          <div className="flex specm:gap-[2.5rem] gap-[0.625rem]">
            <Link
              href="/"
              locale={locale}
              aria-disabled={asPath === "/"}
              className="aria-disabled:opacity-50 aria-disabled:pointer-events-none hover:underline"
            >
              {t("common:header.home")}
            </Link>
            <Link
              href="/blog"
              locale={locale}
              aria-disabled={asPath === "/blog"}
              className="aria-disabled:opacity-50 aria-disabled:pointer-events-none hover:underline"
            >
              {t("common:header.blog")}
            </Link>
            <Link locale={locale} href="/#projects" className="hover:underline">
              {t("common:header.projects")}
            </Link>
          </div>
          <div className="specm:block hidden" />
        </SpecContainer>
      </header>
      <div className="bg-[#381DDB] font-raleway font-bold text-[0.75rem] text-white">
        <SpecContainer className="flex justify-between items-center">
          <nav className="flex gap-2 items-center">
            {locales.map(({ id, name }, i) => (
              <React.Fragment key={id}>
                {i > 0 && <span></span>}
                <Link
                  href={asPath}
                  locale={id}
                  aria-disabled={locale === id}
                  className="block py-[0.375rem] aria-disabled:opacity-50 aria-disabled:pointer-events-none"
                >
                  {name}
                </Link>
              </React.Fragment>
            ))}
          </nav>
          <ul className="flex specm:gap-2">
            {social.map(({ element, id }) => (
              <li key={id}>{element}</li>
            ))}
          </ul>
          <a href="mailto:[email protected]" className="group">
            {email}
          </a>
        </SpecContainer>
      </div>
    </>
  );
};

这是 主页 的样子:

export default function Index({
  allPosts,
  postsCount,
}: {
  allPosts: Post[];
  postsCount: number;
}) {
  const { locale } = useRouter();
  const { t } = useTranslation();

  return (
    <Layout
      title={t("index-page:meta.title")}
      description={t("index-page:meta.description")}
      header={<Header />}
    >
      <div className="mt-[3rem]" />
      <Main />
      <div className="w-full specl:my-[6.25rem] specm:my-[5rem] my-[2.5rem] border-b border-neutral-200" />
      <AboutMe />
      <LastProjects />
      <Blog allPosts={allPosts} postsCount={postsCount} />
    </Layout>
  );
}

最终想法

最后,我实现了:

一个完全静态的博客——没有后端,没有数据库。
一个个人页面——集成到项目中并根据我的风格进行了自定义。
免费托管——部署在 GitHub Pages 上。

现在,我可以添加内容并继续开发项目

如果您正在考虑创建自己的网站,请尝试类似的方法——使用现成的解决方案并根据您的需求进行调整

继续阅读

加入我们的社区