Nuxt 3 生成部署

nuxt3
Created 3/7/2023
Updated 3/7/2023

Nuxt 3 生成部署

Nuxt 应用可以部署到具有 Node.js 环境的服务器,也可以将经过 pre-rendered 预渲染的结果部署到 static 静态网页托管平台,或 serverless 和 edge(CDN)环境

参考

本文主要参考 Nuxt 官方文档 Deployment 这一章节。

Nuxt 使用的后端服务器引擎是 Nitro,也可以查看Nitro 官方文档了解如何配置 Nitro 将 Nuxt 应用部署到服务器。

此外 Nuxt 还专门针对一些主流的云托管平台给出具体的操作指南

如果需要修改 runtime 运行环境参数,可以采用以下任一方法:

  • 在终端运行代码时提供 environment variable 环境变量(特别适用于依赖 CI/CD 的部署环境)
    bash
    # 使用 NITRO_PRESET 作为环境变量
    NITRO_PRESET=aws-lambda nitro build
    
  • 设置 nitro.config.ts 配置文件
    nitro.config.ts
    ts
    import { defineNitroConfig } from "nitropack";
    export default defineNitroConfig({
      preset: 'node-server'
    })
    

渲染模式

网站需要在浏览器上显示出来,所以需要将 Vue 的组件(代码)解析为 HTML、CSS 和 JavaScript,该过程称为渲染 rendering。

Nuxt 提供了丰富的渲染模式,以适用多种应用场景,可以在 Nuxt 的配置文件中进行渲染模式的配置和切换。

nuxt.config.ts
ts
export default defineNuxtConfig({
  ssr: true // 默认开启服务器渲染,即采用「客户端-服务器渲染模式」 universal rendering
  // 如果设置为 false,则表示采用客户端渲染
})

Nuxt 2 支持在客户端渲染 client-side only客户端-服务器两者结合的渲染 universal(由于代码可以在服务器和客户端运行,所以称为「通用」渲染模式)两种模式:

  • 客户端渲染模式 client-side only rendering
    浏览器/客户端下载 HTML 模板和 JS 脚本并执行,再在客户端渲染出完整的网页应用。一般适用于需要处理较多用户交互操作,以及不太需要 SEO 优化的网站。
    由于 Nuxt 是采用 Vue 作为前端框架,Vue 本身就是使用这种模式来构建 SPA 网站的,所以这种模式在 Nuxt 2 项目中可做到开箱即用。
    client-side-render
    client-side-render
  • 通用渲染模式 universal rendering
    当浏览器向服务器发出请求时,服务器会返回一个网站的 HTML 文档(可以是预先生成并缓存在服务器中,或接到客户端请求后再生成),这和传统的服务器端渲染 server-side(使用 PHP 或 Ruby 的传统服务器)类似。这种模式可以有较好的 SEO 优化,一般适用于展现内容为主的网站,如博客、商务网站,Nuxt 默认采用这种模式。
    此外该模式还保留了一定程度的客户端渲染,以便让页面可以处理用户的交互,使得这种渲染模式适用场景更灵活。
    当下载完从服务端发过来是 HTML 后,Nuxt 会在后台加载运行从服务端发来的 JavaScript 代码,然后客户端会再次解析网页,并使用 Vue 接管和控制网页,这样就可以处理用户的交互
    💡 因为使用了服务端进行完整的 HTML,不必依赖客户端,不受设备、浏览器等限制,所以称为通用渲染 ❓
    💡 将静态网页变成可交互的过程称为 Hydration
    universal-render
    universal-render
    说明

    通用渲染模式 universal rendering 是 Nuxt 所采用的默认渲染模式。

    可以通过 Nuxt 的配置文件 📄 nuxt.config.ts 来调整渲染模式

    nuxt.config.ts
    ts
    export default defineNuxtConfig({
      // ssr 全称为 server side rendering 服务端渲染
      // 设置为 false,则表示不会在服务端进行渲染
      // 即网址只采用客户端渲染
      ssr: false
    })
    

Nuxt 3 还提供了一种更先进的渲染模式——混合渲染 hybrid。可以控制每一个路由(页面)的缓存规则,以设定服务器应该如何响应客户端发出的每一条 URL 请求。由于通用渲染一般采用 Node.js 环境,Nuxt 3 还提供一种渲染模式——边缘渲染 edge-side,可以利用 CDN 的 workers 进行渲染,以减低网络的延迟。

  • 混合渲染模式 hybrid rendering
    可以为**每个的路由(页面)**设置不同的渲染和缓存规则,有的页面可能更适合在服务器渲染,有的页面可能更适合在客户端渲染。
    例如在有访问权限约束的网站,对于普通的页面可以先在服务器统一生成(只执行一次渲染),而对于会员专属的页面则应该采用客户端渲染(类似一个动态的网页应用,这些页面应该按需生成)。
    更多信息可以查看社区的讨论
    Nuxt 3 可以在文件 📄 nuxt.config.ts 的属性 routeRules 中为路由配置规则,以设置其渲染和缓存模式,Nuxt 后端服务器会自动注册相应的 middleware 中间件,使用 nitro caching layer 来处理这些路由。
    以下是一系列支持配置的路由规则:
    • 属性 redirect:字符串。为路由定义一个服务端的路由重定向
    • 属性 ssr 和属性 static 以及属性 swr:布尔值。为路由设置不同的渲染模式。
      • ssr: true 采用服务端渲染模式
      • static: true 采用静态页面渲染模式
      • swr: true 采用
      说明
      • Static 渲染模式:在构建时 build 生成静态 HTML 文件。
        这种渲染方式适用于静态内容不会经常变化的网站,如博客、公司官网等。
      • SWR 渲染模式:全称为 Stale While Revalidate 使用过期数据但同时进行重新请求,即在客户端请求数据时,先从缓存中读取数据同时发起请求,最后获取最新的数据,并在获取到数据后更新缓存。
        它会先使用旧数据/缓存显示到页面上,不让用户等待,同时去发起请求获取最新的数据,如果数据有更新,则用返回的新数据刷新页面 UI。
        这种渲染方式可以提高 UX 用户体验,相当于兼容了 static 的快速响应性和 ssr 的实时性,适用于需要频繁更新数据的网站,如社交网站、电商网站等。
      • SSR 渲染模式:全称为 Server Side Rendering 服务器端渲染,该模式会在服务器端生成 HTML 文件,并在客户端进行交互。
        这种渲染方式适用于需要 SEO 优化的网站,如新闻、论坛等。
    • 属性 cors:布尔值。路由是否自动添加 cors headers
      也可以通过属性 headers 来覆盖它
    • 属性 headers:字符串。为路由/页面添加特定的 headers,例如为页面添加 assets
    nuxt.config.ts
    ts
    // example
    export default defineNuxtConfig({
      routeRules: {
        // Static page generated on-demand, revalidates in background
        '/blog/**': { swr: true },
        // Static page generated on-demand once
        '/articles/**': { static: true },
        // Set custom headers matching paths
        '/_nuxt/**': { headers: { 'cache-control': 's-maxage=0' } },
        // Render these routes with SPA
        '/admin/**': { ssr: false },
        // Add cors headers
        '/api/v1/**': { cors: true },
        // Add redirect headers
        '/old-page': { redirect: '/new-page' },
        '/old-page2': { redirect: { to: '/new-page', statusCode: 302 } }
      }
    })
    
    提示

    目前 Nuxt 3 自动支持 Netlify 和 Vercel 两个平台的原生路由规则 ❓

    目前在 Netlify 平台上采用 swr 渲染模式支持完全增量静态生成

  • 边缘渲染 edge-side rendering
    服务端渲染 server side rendering 和通用渲染模式 universal rendering 一般只能在运行着 Node.js 环境的后端中使用,而 Nuxt 3 采用一个全新的服务端渲染引擎 Nitro,让适用场景更进一步
    它支持多种环境,除了浏览器、Node.js,还可以在 CDN edge workers 中渲染 Nuxt 应用,让用户访问网站时所感受到网络延迟更低。

另外 Nuxt 3 现在也已经支持静态页面生成 Full Static site generation,通过这种渲染模式生成的网页可以部署到各种静态页面托管平台,如 VercelGitHub PagesCloudflare Pages 等。

Node 服务器

在终端运行 nuxt build 会生成一个结果文件夹 📁 .output,其中 📄 .output/server/index.mjs 就是服务器的入口文件

将其部署到具有 Node.js 环境的服务器中,并执行以下代码就可以启动应用

bash
node .output/server/index.mjs
# 输出(默认使用 3000 端口)
# Listening on http://localhost:3000

可以通过以下的一些环境变量设置应用 runtime 运行时的参数:

  • NITRO_PORTPROT 设置端口(默认为 3000
  • NITRO_HOSTHOST 设置主机地址
  • NITRO_SSL_CERTNITRO_SSL_KEY 加密方式(除了用于测试,一般不推荐设置)
使用 PM2

如果需要使用 PM2 可以设置 ecosystem.config.js 配置文件

ecosystem.config.js
js
module.exports = {
  apps: [
    {
      name: 'NuxtAppName',
      port: '3000',
      exec_mode: 'cluster',
      instances: 'max',
      script: './.output/server/index.mjs'
    }
  ]
}

静态网页托管

使用以下命令,会在 📁 .output/public 目录中一系列文件,它们可以直接部署到静态网页托管平台上

bash
npx nuxi generate
说明

Nuxt 的爬虫机器人 crawler 会根据路由生成相应的 HTML 文件和 payload 文件(一堆 JS 文件,包含页面相应的数据),

生成静态网页有的两种渲染模式可选:

  • 在配置文件中设置 ssr: true,就会采用服务端的方式(nuxi generate 命令所采用的默认渲染模式),将各路由进行预渲染 pre-render 生成多个静态页面
    而且它会自动生成 /200.html/404.html 作为 fallback 回退页面以处理动态路由和错误的路由
  • 在配置文件设置 ssr: false,那么在终端执行 nuxi build 时会生成一个静态的 SPA 单页面应用
    它会生成一个「空」的 HTML 页面 .output/public/index.html 作为入口(其核心内容仅有 <div id="__nuxt"></div> 元素),Vue 会在客户端再 mounted 到这个页面上

采用 ssr: false 方式适用于页面无法在服务端生成的场景,例如一些代码需要依赖浏览器的 API,但是这种方式就无法利用页面预渲染的诸多好处,例如加快页面的加载速度、更好的 SEO 等

所以推荐采用 ssr: true 方式,对于无法在服务端渲染的部分代码,则使用 Nuxt 内置的 <ClientOnly> 组件进行 wrap 封装,这样应用剩余的部分都可以先进行预渲染,生成静态的页面

相应地,如果应用的大部分页面都无法在服务端生成,需要采用 ssr: false 模式时,也可以在配置文件 nuxt.config.ts 为特定的一些路由设置预渲染模式,以便对其中一两个页面进行优化

nuxt.config.ts
ts
defineNuxtConfig({
  nitro: {
    prerender: {
      routes: ['/user/1', '/user/2']
    }
  }
})

Copyright © 2024 Ben

Theme BlogiNote

Icons from Icônes