Nuxt Nation 大会即将到来。加入我们,时间为 11 月 12 日至 13 日。
文章·  

边缘运行的 Nuxt

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

引言

2017 年 9 月,Cloudflare 推出了 Cloudflare Workers,使开发者能够在其 边缘网络 上运行 JavaScript。这意味着您的代码将部署到全球 100 多个位置的整个边缘网络中,大约需要 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 在 Worker 中运行,我们不得不重写 Nuxt 的某些部分,使其与环境无关(可在 Node.js、浏览器或 V8 中运行)。

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

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

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

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

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

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

最后,为了在开发(Node.js)和在 Cloudflare 上的生产环境(边缘运行时)之间提供相同的开发体验,我们创建了 unjs/unenv:一个库,通过模拟或添加已知依赖项的 polyfill 来转换 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)。**

此外,通过利用像 drizzle-orm 这样的对象关系映射 (ORM),开发者可以连接边缘和无服务器数据库,例如 D1TursoNeonPlanetscale 等。

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

结论

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

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

← 返回博客