学习 Nuxt,包含 100+ 技巧!
文章·  

Nuxt on the Edge

了解我们如何使 Nuxt 3 能够在边缘运行时上运行,从而在靠近用户的服务器端渲染。

简介

在 2017 年 9 月,Cloudflare 推出了 Cloudflare Workers,使其能够在他们的 边缘网络 上运行 JavaScript。这意味着您的代码将在大约 30 秒内部署到遍布全球一百多个地点的整个边缘网络上。这项技术使您可以专注于编写靠近用户的应用程序,无论他们身在何处(约 50 毫秒延迟)。

worker 的运行时与 Node.js 或浏览器不同,它使用 Google Chrome 开发的 JavaScript 引擎 V8 执行代码。到目前为止,您可以在其平台上运行的是在到达您的服务器之前在边缘运行的小型脚本,以提高性能或根据请求标头添加一些逻辑,例如。

在 2020 年 11 月,在开发 Nuxt 3 时,我们决定在边缘运行时 / V8 隔离区中生产环境运行 Nuxt

当使用像 CloudFlare Workers 这样的平台时,它解锁了从世界各地约 50 毫秒内服务器渲染页面的能力,而无需处理服务器、负载均衡和缓存,费用约为 每百万次请求 0.3 美元。 截至今天,新的平台正在涌现,例如 Deno Deploy,让应用程序可以在 V8 隔离区上运行。

2024 年更新: 我发布了 NuxtHub,让您可以在边缘上使用 Nuxt 构建全栈应用程序,在您的 Cloudflare 帐户上零配置。它包括数据库、blob 存储、KV、远程存储等。

挑战

为了使 Nuxt 在 workers 中运行,我们不得不重写 Nuxt 的某些部分,使其环境不可知(在 Node.js、浏览器或 V8 中运行)。

我们从服务器开始,创建了 unjs/h3:一个为高性能和可移植性构建的最小 http 框架。它取代了我们在 Nuxt 2 中使用的 Connect,但与其兼容,因此您可以继续使用 Connect/Express 中间件。在 workers 中,对于每个传入的请求,它都会在生产环境中启动 Nuxt,将请求发送给它,然后发回响应。

在 Nuxt 2 中,在生产环境中内存中启动服务器的持续时间(也称为冷启动)约为 300 毫秒,因为我们必须加载服务器和应用程序的所有依赖项才能处理请求。

通过研究 h3,我们决定代码拆分附加到服务器的每个处理程序,并在请求时才延迟加载它们。当您启动 Nuxt 3 时,我们只在内存中加载 h3 和相应的处理程序。当请求进入时,我们加载与路由对应的处理程序并执行它。

通过采用这种方法,我们将冷启动时间从约 300 毫秒减少到约 2 毫秒

为了在边缘上运行 Nuxt,我们还面临另一个挑战:生产包的大小。这包括服务器、Vue 应用程序和 Node.js 依赖项的组合。Cloudflare workers 目前对 worker 大小有限制:1MB(免费计划)和 5MB(每月 5 美元计划)。

为了实现这一点,我们创建了 unjs/nitro,我们的服务器引擎,当运行 nuxt build 命令时,它会将您的整个项目打包,并将所有依赖项包含在最终输出中。它使用 Rollupvercel/nft 来仅跟踪 node_modules 使用的代码,以删除不必要的代码。对于基本的 Nuxt 3 应用程序,生成的输出总大小约为 700kB gzip。

最后,为了在开发(Node.js)和 Cloudflare 上的生产环境(边缘运行时)之间提供相同的开发者体验,我们创建了 unjs/unenv:一个通过模拟或为已知依赖项添加 polyfills 来转换 JavaScript 代码以在任何地方(平台无关)运行的库。

在 Nuxt,我们认为您应该有自由选择最适合您的托管提供商。

这就是为什么您可以在以下平台上部署具有边缘端渲染的 Nuxt 应用程序:

我们还支持许多其他部署提供商,包括 静态托管传统的 Node.js 无服务器和服务器主机

推动全栈能力

现在我们的 Nuxt 可以在边缘运行时上运行,我们可以做的不只是渲染 Vue 应用程序。 感谢 server 目录,创建一个 API 路由只需一个 TypeScript 文件。

要添加 /api/hello 路由,请创建一个 server/api/hello.ts 文件

server/api/hello.ts
export default defineEventHandler((event) => {
  return {
    hello: 'world'
  }
})

您现在可以在页面和组件中通用地调用此 API

pages/index.vue
<script setup>
const { data } = await useFetch('/api/hello')
</script>

<template>
  <pre>{{ data }}</pre>
</template>

当创建 useFetch$fetch 时,需要注意的重要一点是,在服务器端渲染期间,如果您调用 API 路由,它将模拟请求并直接调用函数代码:避免 HTTP 请求并减少页面渲染时间

在开发者体验方面,您会注意到,当创建服务器文件时,Nuxt 服务器会继续运行,而无需重建 Vue 应用程序。这是因为 Nuxt 3 在创建 API 和服务器路由时支持热模块替换 (HMR)。

此外,通过利用对象关系映射 (ORM),如 drizzle-orm,开发人员可以将 Edge & Serverless 数据库连接起来,例如 D1TursoNeonPlanetscale 等。

我创建了 Atidone,一个开源演示,展示了一个在边缘上运行的具有身份验证和数据库的全栈应用程序。源代码可在 GitHub 上以 MIT 许可证获得,网址为 atinux/atidone

结论

我们对边缘端渲染及其解锁的功能感到兴奋。我们在 Nuxt 的团队迫不及待地想看看您将在此基础上构建什么!

欢迎加入我们的 Discord 服务器 或在 Twitter 上提及 @nuxt_js 以分享您的作品。