我已经做了大约4年的网页编程,最近我终于开始在一个服务器端渲染的框架上重建一个完整的项目。从纯HTML和CSS做起,一路走来,到现在使用现代库如React,虽然我在合同项目中接触过服务器端渲染(SSR),但我从未从头开始构建过一个这样的服务器端渲染项目。
SSR的基本介绍如果你还不了解SSR是什么,或者不知道为什么它很重要(就像我之前不了解一样),SSR是一种在服务器端渲染你的应用,并将渲染好的HTML发送给客户端的方法。这意味着用户的浏览器里不会运行任何JavaScript。如果某个组件需要运行自己的JS(即需要被水化),你可以把它切换到客户端进行渲染。
当我第一次听说SSR时,我认为它仅仅是在使用高资源消耗框架时,减少旧设备负担的一种方法。在某种程度上,这在某种程度上仍然是SSR的应用场景之一,但最终我明白了它真正的、非常简单的理由:——爬虫抓取的元数据和SEO优化。
使用Next构建的网站在Ahrefs的得分
我想为我的工具包网站(snippp.io)建立索引并生成丰富的预览效果,以便工具包和代码片的标题在Twitter和Bluesky上就会显示,并且能够被搜索引擎抓取。
这个原版的 app 是用 React 开发的,作为一名用户,这个 app 运行得非常完美:你加载页面,它就会立刻显示内容!浏览器的标题会显示你正在查看的内容的名称,感觉一切都很完美。
然而,在点击链接和页面显示之间,有在几毫秒内发生的几个步骤被忽略了。React 总是在第一次渲染时呈现一个正在加载中的页面版本。通常来说,React 只会在渲染完成后才触发任何 fetch 请求。
经典的客户端处理方式重要的事情发生在这几毫秒里。我们来看看标准React应用的操作顺序,这可能比你想象的更重要。
useEffect
钩子。在我们的例子中,它会发送一个请求从数据库获取一些信息并等待响应。所以,从用户的角度看,一切都很棒。他们点击链接,250毫秒后就能看到你的内容。但对爬虫来说,要么无法发起请求,要么无法等待250毫秒,你的页面可能会一直显示为一个正在加载的页面,且页面标题为空。
开始服务端渲染!在 Next.js 中,我们能够创建一个服务器端运行的组件,该组件会先获取我的信息数据,用这些信息填充页面的元数据信息,然后用这些信息渲染页面的其余部分。因此,当一个爬虫向我的服务器请求页面时,它会收到一个最终的 HTML 页面进行爬取,而不是一个稍后填充内容的页面骨架。
为了完整性,将这250毫秒(或可能更少)拆分一下!
现在,爬虫、元数据请求者和搜索引擎索引器可以从一开始就能看到你所有的内容!为分享链接生成丰富的预览,让搜索引擎索引你所有的内容,并获得你所选SEO工具中的100%健康得分。
SSR是不是更快?
我提到我们可以通过使用服务端渲染来缩短请求时间,但它是如何工作的呢?其实,一个客户端应用总是从客户端位置访问数据库。所以如果数据库在法国,而你的服务器从美国加州访问它,这显然会比从西班牙访问要慢一些。
不过,如果你能将你的数据库和服务器都放在同一个区域或同一个地理位置,你可以大幅降低数据库的响应延迟。尽量把它们部署在同一个本地网络里,甚至在同一栋楼或同一个数据中心里。
当然,两者之间仍有差距,但在仅发送完全渲染的HTML时,传输速度仍然可能非常快。如果服务器运行了适当的硬件,页面渲染时间甚至可能比客户端设备更快。
考虑一些其他的优化,比如访问缓存数据,可以让服务器端渲染流程比普通的 React 应用更快,并且学习曲线非常平缓。例如:
学 Next 难不难?来自 React 出发,理解起来非常容易,只是因为我在新的基础上重建我的应用,感觉有些繁琐。我把所有的组件、工具及原仓库里的其他一切内容都搬过来了,这样我有了一个良好的开端,不过我认为一开始就为服务器端渲染构建所有内容可能更简单。这里有一些关于我的经历值得注意的地方:
最近我用自己制作的一个模板创建了许多原型 _(Vite、React、TS、Tailwind、Prettier、Lucide、React Router 和 Vercel 分析工具,可在此获取 ) ,但我可以将 React Router 换成 Next.js 并调整文件夹结构。这样我认为可以更好地着手原型开发,更快速且简便,并且如果我想要在此基础上构建完整的应用,还能改善 SEO。
在未来,我很想尝试其他SSR框架如Next,看看它们的工具能为其他使用场景提供多少帮助,但我现在理解为什么大家都倾向于使用Next了。从React转过来学Next很容易,大多数你想要在服务器上做的事情都被很好地抽象化了,而且只需简单地切换即可使组件保持活性。由于Next的高度抽象性,有些细节上的微调工作可能无法实现,不过我还没遇到需要进行这种细节调整的情况。