Zane-Cody's Hoard
回到归档

这个小屋是怎么搭起来的

4 分钟#建站#Next.js

从选型到上线:为什么用 Next.js 16 静态导出、为什么内容用 Markdown、毛玻璃效果具体怎么做的。

开一个新站最费时间的从来不是写代码,是决定「用什么写」。这篇把当时的取舍记下来,省得以后自己都忘了。

为什么是静态导出

这个站没有任何需要服务端的东西:没有登录、没有数据库、没有实时数据。所有内容在构建时就确定了。

所以直接开静态导出:

// next.config.ts
const nextConfig: NextConfig = {
  output: "export",        // 构建产物是 out/
  images: { unoptimized: true },
  trailingSlash: true,     // 导出成 /about/index.html,兼容性好
};

好处很实在:

  • 部署自由。产物就是一堆 HTML/CSS/JS,丢到 Vercel、Cloudflare Pages、GitHub Pages 还是自己的 nginx 都能跑,不会被某个平台绑住。
  • 省钱。静态托管的免费额度通常够用一辈子。
  • 快。没有服务端渲染的往返,首屏就是 HTML。

代价也要说清楚:没有服务端就意味着不能有 API 路由、不能有 Server Actions、不能用 ISR。以后要是想加评论系统,得挂第三方(比如 Giscus)。

为什么内容用 Markdown 而不是 MDX

MDX 很诱人:能在正文里直接写 React 组件。但它把内容格式和框架版本绑死了 —— MDX 的编译器和 React 版本强耦合,升级框架时正文有可能集体编译失败。

对一个要放很多年的个人站来说,这个风险不划算。所以用最朴素的方案:

unified()
  .use(remarkParse)
  .use(remarkGfm)
  .use(remarkRehype, { allowDangerousHtml: true })
  .use(rehypeSlug)
  .use(rehypeShiki, { theme: "synthwave-84" })
  .use(rehypeStringify, { allowDangerousHtml: true });

产出的是纯 HTML 字符串,跟 React 什么版本毫无关系。想加新语法就加插件,不想用了就删掉,正文一个字都不用动。

内容比框架活得久。让内容依赖框架的实现细节,是给自己埋雷。

毛玻璃是怎么做的

关键只有一行:

.card {
  backdrop-filter: blur(18px) saturate(150%);
}

但毛玻璃必须有东西可以「透」。如果背景是一片纯色,模糊前后完全一样,效果等于没有 —— 这是很多人做毛玻璃翻车的原因。

所以底下铺了一层极光:几个大幅模糊的彩色球体在缓慢漂移。

.aurora-blob {
  position: absolute;
  border-radius: 999px;
  filter: blur(90px);
  animation: drift 26s ease-in-out infinite;
}

有了彩色的、会动的底,上面那层 backdrop-filter 才有意义。

用 @theme inline 串起设计变量

Tailwind 4 允许把 CSS 变量注册成工具类:

@theme inline {
  --color-sakura: var(--c-sakura);
  --color-violet: var(--c-violet);
}

inline 这个关键字是关键。不加它,Tailwind 会把变量的值抄进每个工具类;加上之后生成的是 var(--c-sakura) 引用 —— 运行时改变量就能整体换色,不用重新构建。

最后

整站的取舍其实就一句话:能在构建期做完的事,绝不留给运行时。

页面是构建期生成的、代码高亮是构建期算的、内容是构建期读的。浏览器拿到的就是最终结果,只需要跑两个客户端组件:音乐播放器和照片墙灯箱。

剩下的时间,应该花在往里面填东西上。