我,一个后端工程师,在前端世界被毒打了两天两夜

作为一个后端工程师,我本以为用 React 给自己的独立项目做个官网是手到擒来的事。然而,为了解决 SEO 和首屏加载问题,我在 React、Next.js 和 Astro 之间反复横跳。这篇文章记录了我从信心满满到怀疑人生的全过程,以及最终对前端技术选型的一点感悟。

一个关于 React, Next.js, Astro 和一个心碎后端仔的真实故事。

0. 故事的开始,一切都那么美好,甚至有点不真实 #

“嗨,不就是个网站嘛,分分钟搞定!”

我,一个在后端混了七八年的 Java 程序员。

我的世界,纯粹又朴素,信奉的是稳定压倒一切。每天打交道的都是 Spring Boot、MySQL、Redis、Docker、k8s、Linux 这些“实在亲戚”。我们之间的沟通方式简单直接:一个请求,一个响应;一个事务,要么成功,要么回滚。干净利落,没有那么多花里胡哨。

前端那些 JS 和 CSS 的玄学问题,在我看来就是一团乱麻。

直到我搞了个人的小项目,一个叫 PigeonPod 的 WebApp。

后端,那必须是我的舒适区,稳如老狗。

但前端,总得有个脸面。

该怎么选技术?我的思路很简单,典型的后端稳重思维:

  1. JS 框架要选生态最强的。 就像 Java 选 Spring Boot 一样,不出错,不一定是最好的,但是干啥都能用,出什么问题都能找到答案。React,全世界都在用,社区庞大得像个帝国,遇到问题随便一搜都有答案,简直就是 JS 届的 Spring Boot。用户足够多,文档足够全,简直就是 AI 的最爱。就它了。
  2. UI 库要选口碑好、够稳定的。 我可不想用个半成品,三天两头出 breaking change。在几个技术社区上研究了一圈,发现 Mantine UI 评价相当不错,样式简洁大气,组件够多,迭代了很久,该踩的坑前人都踩完了。完美。

接下来就是干。

当然,学习 React 和 Mantine 的过程也啃了不少文档,花了不少时间。但这笔“学费”我交得心甘情愿。我就想着,把这套东西搞熟了,以后写前端不就能像用 Spring Boot 一样,一招鲜吃遍天了嘛。

事实证明,前期的投入是值得的,PigeonPod 应用本身开发得还算顺利。

于是,我乘胜追击,准备给我的 PigeonPod 做个时髦的 Landing Page 充充门面。

这不更是小 case?

我直接把 PigeonPod 的前端代码复制一份,把 App 里的组件稍微改改,CV 大法一开,很快啊!一个看起来相当唬人的官网就上线了。

我看着屏幕上自己的杰作,心满意足地往椅背上一靠,长舒一口气。

“咱也是个全栈了!”

当时的我,天真得像个两百斤的孩子。

1. Lighthouse 给了我 85 分,Google 却给了我一记耳光 #

“我的网站,加载起来像是在进行一场庄严的宗教仪式。”

官网是上线了,但问题也来了。

每次打开我的 Landing Page,总感觉……慢一拍?

那种感觉,作为一个后端,我再熟悉不过了:就像是执行了一条没加索引的 SELECT *,数据量不大,速度也不慢,但是就是没那种爽感。

我不能忍 🫤

熟练地按下 F12,打开 Network 面板,看着那长长的网络请求瀑布,我陷入了沉思。

一顿操作猛如虎:字体加载优化、图片懒加载、分级加载图片……这些都是前端优化里的小门道。效果立竿见影,性能直接提升了 40%。

与此同时,我可不是对 SEO 一无所知的“小白”。我从一开始就知道,单纯的 React SPA 对搜索引擎就是个灾难。

所以,我早就“未雨绸缪”,给我的 Landing Page 上了一套 pre-render 脚本。这玩意儿会在项目构建的时候,提前跑一遍我的页面,把渲染好的 HTML 抓下来,直接塞进 index.html 里。这样,爬虫一来,至少能看到点实实在在的内容,不至于对着一个空的 <div> 发呆。

看着 performance 92; Best Practices 100; SEO 85 的 lighthouse 评分,我长舒一口气,感觉自己又行了。

AI 在手,前端我有 🐮

然后,真正的“耳光”在一个月后扇了过来。

我心血来潮,想看看我的项目有没有被 Google 收录。我在搜索框里郑重地敲下 “PigeonPod”,回车。

结果……比我的钱包还干净 🤷

GitHub 项目页排在第一我倒是能理解,GitHub 这种大站的权重岂是我能比得过的,但是我在 Reddit 上发的帖子都有,甚至还有一个朋友自己部署在群晖上的 PigeonPod 应用都排在第三,就是我自己的 Landing Page 没有,Google 压根不知道我的站点一样。

我不服 🫤

Lighthouse 的 SEO 85 分呢?我那套 pre-render 的“骚操作”呢?难道都是幻觉?

我这才被迫重新、并且是真正深入地去理解前端渲染那点事。我才发现,我那种 pre-render 的小伎俩,顶多算是给爬虫准备了一份“内容简介”。它也许能骗过 Lighthouse 的模拟测试,但在 Google 真正的大规模、复杂的索引算法面前,我这种“作弊”行为,跟裸奔没什么两样。

人家真正看重的是根正苗红的 SSR (服务端渲染)SSG (静态站点生成)

这两种模式,打个比方就是:请求来了,我在服务器上把逻辑跑完,HTML 页面需要的全部内容都准备好,直接把一个“满汉全席”成品扔给浏览器和爬虫。 而我之前做的 React SPA + pre-render 方案,充其量只是在“满汉全席”的菜单上,用小字附上了一份“菜品介绍”。

Lighthouse 看了看菜单说:“嗯,菜品很丰富,85分。”

Google 的爬虫走进来,看了一眼空荡荡的餐桌,然后把我那份菜单扔进了垃圾桶。

2. Next.js — 声称爱你,却只想带你回 Vercel #

“我以为我找到了救世主,结果他是我命中注定的劫。”

行,既然 pre-render 这条小路走不通,那就上正道,搞真正的 SSG。

问题明确了,解决方案也就清晰了:换框架!

我需要一个能支持 SSG、能兼容我现有 React 代码、并且生态足够强大的框架。打开 Google,搜索框还没打完,答案就已经自己跳了出来:

Next.js 🤩

“The React Framework for Production”

这口号,霸气!

再看它的特性:“SSG 快如闪电”、“SEO 天选之子”、“从现有 React 应用无缝切换”……

每一个字都精准地砸在了我的心巴上。这不就是为我量身定做的银弹吗?我甚至都不需要改动太多代码!

我当时就想,这不就是 React 生态里的 Spring Boot 吗?Spring 本身很灵活,但做 Web 开发还是得上 Spring Boot 这个“全家桶”。同理,React 本身只是个库,Next.js 才是那个能带它走向生产环境的“亲哥”啊!

说干就干!

我花了整整几个小时,对着文档,升级依赖、改目录结构、调整路由(虽然超过一半的活都是 AI 干的……终于,在 npm run dev 敲下回车的那一刻,我的 Landing Page 在 Next.js 的框架下,成功运行了!

那一刻,我感觉自己掌控了整个宇宙。

好了,本地跑通了,下一步,部署!

我熟练地打开了 赛博菩萨 Cloudflare 的主页 ,准备走部署流程。

就在这时,Vercel 的铁拳砸了下来。

我这才知道,Next.js 里的某些核心功能,比如它那个吹得神乎其神的图片自动优化 (<Image>),根本不是框架自带的,它依赖 Vercel 平台的后端服务!

我人都傻了 🤯

好家伙,我以为我找的是个技术合伙人,结果是个必须和丈母娘(Vercel)绑死的“上门女婿”!它对你所有的好,所有的承诺,都是为了最后让你心甘情愿地走进 Vercel 这个家门。

Next.js 从来就不是一个纯粹的开源框架,它是 Vercel 的销售手册和护城河。它所有的“最佳实践”,最终都指向一个目的地:“Deploy with Vercel”。

我感到一些 恶心 不适 🤕

我不信邪,难道离了 Vercel 就活不了了?很快,我发现了 OpenNext 这个项目,它宣称能让 Next 项目兼容 AWS、Cloudflare 等平台。

我又燃起了希望。

于是,我又花了几个小时,研究 OpenNext 的文档,改配置,尝试部署……

我又一次失败了。

这个迁移过程遇到了无数稀奇古怪的问题,我顺手点开了它的 GitHub,发现代码提交频繁,issues 区哀鸿遍野。我瞬间意识到,这玩意儿就是个半成品,我可能会掉进一个永远也填不完的坑里。

算了,放弃。

我又想到了 Next.js 的最后一个“和平分手”选项:静态导出 (next export)

官方宣称,使用这个功能,可以将 Next 项目导出为纯静态文件,可以部署在任何地方。这不就行了吗!我赶紧舍弃了图片优化功能,开始修改代码以满足静态导出的条件。

然后,我又失败了。

因为 Next 的静态导出,和我用的国际化库 next-intl 在路由处理上有着莫名其妙的兼容问题。虽然这是 Next 官方推荐的国际化库,但是无论我怎么折腾,它就是没法为我所有的语言页面生成对应的静态 HTML 文件。

这个过程又花了我几个小时。

我看着满屏的错误日志,那一刻,我真的累了。我感觉自己就像个小丑 🤡

3. Astro — 美丽新世界,可惜我的 UI 库没买到船票 #

“在绝望的尽头,我看到了一座灯塔,然后一头撞了上去”

被 Next.js 这么一折腾,我对整个 React 全家桶生态产生了深深的怀疑。

我不想再挣扎了。我决定和 React 框架暂时分手,去看看外面的世界。Vue、Svelte 这些,虽然名声在外,但设计理念和技术生态完全不同,短时间内再去学一套,我的肝可能不同意。

就在我快要放弃,准备躺平,接受我的 Landing Page 就是个“搜不到的废物”这个设定时,一个名字闯入了我的视野:

Astro 🚀

它的 Slogan 简直是一股清流:“The web framework for content-driven websites.”

Landing Page 不就是最典型的内容驱动网站吗?

我抱着死马当活马医的心态,点开了它的文档。结果越看,眼睛越亮,心跳越快。

  • “Island Architecture”(岛屿架构): 默认发送零 JS 到客户端,页面上的交互组件像一个个“孤岛”一样,按需加载。翻译一下:快,极致的快!
  • “UI-Agnostic”(UI 框架无关): 你可以在同一个项目里,同时使用 React、Vue、Svelte 等任何你喜欢的组件。翻译一下:我之前的 React 组件还能接着用,不用重写!
  • “Deploy Anywhere”(随处部署): 默认输出纯静态文件,你想把它部署在哪都行。翻译一下:彻底告别被平台绑架的恶心感!

这简直就是我的梦中情框啊!

它就像一个编译工具,而不是一个大包大揽的运行时框架。它在编译期就把能干的活全干完了,生成最纯粹、最轻量的 HTML 和 CSS,然后把交互的部分交给具体的 UI 库去处理。

这不就是我们后端最推崇的“关注点分离”吗?专业的事交给专业的工具去做!

我感觉自己被治愈了 ❤️‍🩹

我仿佛看到了一个没有平台绑架、没有复杂配置、回归 Web 本质的美丽新世界。

吸取了前一次在部署前不知道 Next.js 和 Vercel 强绑定吃过的亏,在开始之前,我就我当前的技术栈和部署平台向地表三大最强 AI 师傅 (Gemini 2.5 Pro, ChatGPT 5, Claude Sonnet 4.5) 咨询,他们都告诉我:超棒的选择! 三大 AI师傅 异口同声的保证,让我信心爆棚,感觉这次稳了。

希望的火焰再次燃起!🔥

我立刻动手,边学边把我的 Landing Page 往 Astro 迁移(当然 AI 还是干活的主力)整个过程出乎意料的顺畅,Astro 的语法简洁又直观。

我开心地把我那些用 Mantine UI 写的 React 组件一个个地请进 Astro 的新家。

然后,在敲下编译命令的那一刻,报错了。

无论我和 AI 师傅怎么修改,Mantine 相关的组件在编译时总是抛出各种奇奇怪怪的错误。

我感觉不对劲,一种不祥的预感笼罩了我。

我立刻去 Google 搜索,然后,我在 Mantine 的官方文档里,找到了一个 FAQ:

“Can I use Mantine with Astro?”

答案只有三个词,却像一把冰冷的刀,插进了我千疮百孔的心里:

“Not a chance.” (门儿都没有。)

官方给出的解释是:“…Astro does not support React context, which is required for Mantine to work.” (Astro 不支持 React context,而这是 Mantine 工作所必需的。)

我这才了解到,所有基于 CSS-in-JS 技术的 UI 库 (比如 Mantine, Styled-Components),都深度依赖 React context 来实现主题切换、样式注入等核心功能。而 Astro 为了追求极致的性能,在它的编译魔法里,把这个 context 给“优化”掉了。

我笑了。

是那种通宵改 bug 最后发现是网线没插的笑。

我绕了一大圈,躲过了 Next.js 的平台绑架,却一头撞死在了 Astro 和 CSS-in-JS 的兼容性墙上。

前前后后,快两天的时间就这么过去了。

我终究还是没能走出这个新手村 🫠

4. 血战后的顿悟 — 写给后端程序员的前端“黑皮书” #

“我失去了时间,却看清了整个江湖”

这两天,我没写出几行能用的代码,我的 Landing Page 项目回到了原点。

但我心里反而异常平静 😐

我终于把前端技术圈这些让人眼花缭乱的名词、框架、库,它们之间错综复杂的关系,给彻底搞明白了。这笔“学费”,交得值。

所以,我把这些顿悟写下来,希望能为所有像我一样,对如今百花齐放的前端技术栈感到困惑的后端同行们,提供一份“避坑指南”。

JS Frameworks 的 “路线之争” #

我之前天真地以为,这些框架只是实现同一个目标的不同工具。现在我明白了,它们代表着三种截然不同的建站哲学。

  1. “SPA 应用专家” (纯 React / Vue / Angular / Svelte ):

    • 哲学: “重客户端”的典范,追求极致的交互体验。它们的目标是把浏览器变成一个应用(Application)的运行环境。
    • 适合场景: 复杂的、重交互的 Web 应用。比如我的 PigeonPod 主应用本身,各种 SaaS 产品的管理后台,在线画图、文档工具等等。
    • 给后端的忠告: 这是造应用的锤子,别用它来钉展示内容的钉子。用它们去做“门面”网站,就是在自找麻烦。
  2. “内容至上纯粹派” (Astro):

    • 哲学: “重服务器”的回归,追求极致的加载速度和 SEO。它的世界里,内容为王,JS 只是点缀。它信奉“非必要,不加 JS”,把能做的都在构建时做完,给你一个最纯粹的 HTML 页面。
    • 适合场景: 内容展示型网站。官网、博客、文档、营销页面。
    • 给后端的忠告: 如果你只想做一个高性能、SEO 拉满的“门面”,Astro 就是那个简单、直接、正确的答案。 它符合我们后端“KISS (Keep It Simple, Stupid)”的原则。
  3. “大一统全能帝国” (Next.js):

    • 哲学: 它是个野心家。它既想拥有 SPA 的交互能力,又想要 SSG/SSR 的性能和 SEO。它不仅是前端框架,还能让你写后端 API。它想做的,是一个“全栈开发平台”。
    • 它很强大,真的。 但它的问题也在这里:它的“全能”是以深度绑定自家 Vercel 平台为代价的。它的很多最佳实践,最终都指向一个闭环生态。
    • 给后端的忠告: 选择 Next.js 不仅仅是一个技术选型,更是一个平台和生态的抉择。 你得到的是一站式的便利,失去的是部署的自由。如果你愿意拥抱 Vercel 的生态,它会给你丝滑的体验;如果你想挣脱,就会像我一样,被各种“特性”卡住喉咙。

另外 Vue 和 Svelte 生态也有他们自己对标 Next 的全栈框架: Nuxt 和 SvelteKit,但我没深入了解过,不做评价。

UI Components 的 “门派之别” #

  1. CSS-in-JS 派 (Mantine, Styled-Components): 深度依赖 JS 运行时和 React Context,和 Astro 这种“零 JS”理念的框架天生八字不合。

  2. Utility-First / Headless UI 派 (Tailwind CSS, Radix UI): 在构建时就确定好样式,不依赖运行时,是 Astro 这类 JS 框架的灵魂伴侣。

暴论时间 #

搞清楚了上面这些,一些过去让我困惑的事情,现在都有了答案。

  • 暴论一:现代前端的很多复杂性,都是为了解决“用 SPA 去做本不该它做的事情”而产生的。 我们本可以简单地写 HTML 来展示内容,但我们非要先用 JS 去模拟一个应用,然后再发明 SSR、SSG 等一大堆“补丁”去优化这个模拟过程,让它“看起来像”一个静态网站。何苦呢?

  • 暴论二:不要迷信任何“无缝迁移”的鬼话。 任何框架的切换,本质上都是哲学思想的切换,伤筋动骨是必然的。所谓“无缝”,往往只是营销口号。作为工程师,你要有把它推倒重来的觉悟。

写到这里,我长舒一口气。我感觉,我 总算 大概是搞清楚了前端娱乐圈的本质。

虽然,还是个菜鸟 😅

5. 路在何方? #

那么,我的 PigeonPod Landing Page 升级计划呢?

答案已经很明显了:推倒重来。

我之前以为,这次血战换来的最终答案会是 Astro + Tailwind CSS。理论上,这个组合完美无瑕,性能拉满,自由度最高。

但当我真的开始尝试用它来复刻我之前用 Mantine 做出的页面时,现实又给了我狠狠一巴掌。

我发现,对于一个像我这样 CSS 经验约等于零、审美基本靠“居中对齐”的后端工程师来说,直接使用 Tailwind 这种原子化的 CSS 框架,无异于一场灾难。它给了你无限的自由,但同时也带来了无限的选择。每一个边距、每一个圆角、每一个阴影,都需要我自己去调试。

想做出原来用 Mantine 那种开箱即用的精致感?太难了,这又是一个巨大的时间黑洞。

就在我再次陷入绝望,以为自己注定只能在“性能”和“好看”之间二选一的时候,我找到了这个故事的最后一块拼图:

shadcn/ui

它不是一个传统的 UI 库,而是一系列你可以直接复制粘贴到自己项目里的、用 Tailwind CSS 写好的高质量组件。

这似乎正是我为 Astro 寻找的那个“中间地带”:它既给了我像 Mantine 一样可以直接使用的、设计精美的成品组件,又保留了 Tailwind 的所有优点,能和 Astro 完美协作,还没有额外的 JS 运行时。

于是,我的新计划也清晰了起来:

PigeonPod 应用本身,继续使用 React + Mantine UI,因为它适合做“应用”。

而那个备受折磨的 Landing Page,我准备用 Astro + shadcn/ui 去尝试新生。

当然,这只是一个新的开始。我还没来得及敲下第一行代码,天知道前面还有多少坑在等着我。但我希望,这一次,方向是真的对了。

写到这里,我的这段踩坑经历也就告一段落了。这篇文章,更多的是分享我的心路历程。接下来,我还会再写一篇更严肃纯粹的技术文章,从架构和原理的角度,去仔细对比和分析市面上这些主流的 JS frameworks 和 UI components,到底应该如何选择和取舍。

最后,想对所有和我一样,在前端世界里感到迷茫的后端同仁们说:

搞清楚你要做的,到底是一个“应用”,还是一个“网站”。

这个问题,可能比选择哪个框架,重要一百倍。