Nuxt3深入探索

Jul 3

前言

最近在做一个工具项目:Mayu, 目的是提供可通过UI快速操作的多个功能,同时将这些功能通过API的形式部署在公网,供其它地方使用。使用Next.js(基于React)或Nuxt.js(基于Vue)的全栈框架配合Netlify, Vercel等平台就可以快速实现这样的服务。我平时写Vue比较多,所以使用后者。

Nuxt 3基本使用

注意

目前Nuxt主流版本是Nuxt 3,不建议去学Nuxt 2了,下面所有的「Nuxt」均指代Nuxt 3。

如果在使用Nuxt前,你还不会Vue 3,请先通过Vue 3官方文档进行学习。此外,你可以结合Nuxt 3官方文档Nitro官方文档来更好地探索Nuxt等用法。

Nuxt是一个服务端渲染(SSR)框架,其打包成品是一个Nitro服务器,由Vue框架驱动前端页面的渲染,Nitro框架提供API接口等功能。

这里只做简单介绍,诸如如何初始化项目等基础知识,请查阅文档进行学习,本文不再赘述。

注意,在使用Nuxt前,请明确你的需求,如果你只是希望在你的Vue项目中加入 基于文件的路由(File-based Routing) 功能,那么大可不必为了该功能而起一个Nuxt项目,你可以使用unplugin-vue-router插件来实现这个功能。

项目结构

通过脚手架初始化的Nuxt 3项目是非常简洁的,很多文件夹和配置是默认不会给的。我们将在之后改造基础项目,这里先说明一下大概的项目结构。

project-root/
- assets   打包进js的资产文件(图片等)
- components 普通自定义组件
- layouts  布局组件,可以创建自定义布局
- pages    路由页面组件
- plugins  Nuxt插件
- public   静态文件
- server   服务端(Nitro)
  | - api   API存放目录, 文件格式为xxx.get.ts, xxx.post.ts等
  | - assets 服务端资产,如json数据等
  | - middleware  服务端中间件
  | error.ts 服务端通用错误处理
app.vue    页面入口
error.vue  通用错误页面
nuxt.config.ts  Nuxt配置文件


...其它目录省略

随着你需求的变化,可能会有更多目录,比如你希望集成项目文档,使用Markdown渲染,那么一般使用@nuxt/content来集成到Nuxt项目中,此时Nuxt就会自动读取根目录下的content文件夹下的markdown文件进行渲染。

改造基础项目

配置文件

经过我的探索,给出一个相对实用的基础配置:

nuxt.config.ts:

export default defineNuxtConfig({
  experimental: {
    clientNodeCompat: true, // 让客户端可以使用Node环境的方法,如Buffer的操作(浏览器环境下不能操作Buffer)
  },
  plugins: [
    '~/plugins/node-client', // 配合clientNodeCompat的插件,将Buffer,process等挂载到globalThis,下面会给出这个plugin的内容
  ],
  app: {  // Nuxt 3开发项目中没有index.html,所以关于页面的配置在这里进行,如head等
    head: {
      title: 'Mayu',
      viewport: 'width=device-width, initial-scale=1, maximum-scale=1',
      charset: 'utf-8',
      meta: [
        { name: 'referrer', content: 'no-referrer' },
      ],
    },
  },
  // 要引入全局css文件可以在这里引入
  css: [
    '~/assets/css/main.scss',
  ],
  // 推荐使用unocss来让你的样式编写更舒服,当然也可以不用
  modules: [
    '@unocss/nuxt',
  ],
  compatibilityDate: '2024-11-16',
  logLevel: 'info',
  devServer: {
    port: 8500,
  },
  devtools: {
    enabled: true,
  },
})

plugins/node-client.ts:

import { Buffer } from 'node:buffer'
import process from 'node:process'

globalThis.Buffer = Buffer
globalThis.process = process

export default defineNuxtPlugin({})

server文件夹

server文件夹是服务端的内容,使用方法与Nitro基本一致,API接口放在server/api文件夹下。需要注意的是默认不支持跨域请求,需要配置一下。

这里使用server/middleware文件夹,Nuxt会读取这个文件夹的.ts文件作为服务端中间件,在每个请求发起前,进行读取headers,记录日志等操作。

如果你需要使用中间件允许请求跨域,可以创建server/middleware/cors.ts:

export default defineEventHandler((event) => {
  setResponseHeaders(event, {
    'Access-Control-Allow-Methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Credentials': 'true',
    'Access-Control-Allow-Headers': '*',
    'Access-Control-Expose-Headers': '*',
  })
  if (event.method === 'OPTIONS') {
    event.node.res.statusCode = 204
    event.node.res.statusMessage = 'No Content.'
    return 'OK'
  }
})

如果你需要Nuxt打印日志,可以添加server/middleware/logger.ts:

你可以使用任意一个日志库来打印日志,我这里用的是tslog

import type { ILogObj } from 'tslog'
import { Logger } from 'tslog'

const logger: Logger<ILogObj> = new Logger()

export default defineEventHandler((event) => {
  logger.info(`Request: method=${event.method}, path=${event.path}`)
})

错误日志打印:创建server/error.ts

import type { ILogObj } from 'tslog'
import { Logger } from 'tslog'

const logger: Logger<ILogObj> = new Logger()

export default defineNitroErrorHandler((error, event) => {
  setResponseHeader(event, 'Content-Type', 'text/plain')
  logger.error(`Error: ${error.stack}`)
  return send(event, `[custom error handler] ${error.stack}`)
})

其它工具

由于Nuxt的SSR特性,你日常在Vue中使用的工具可能不能直接使用,需要安装适配Nuxt的版本,可以在这里搜索,例如:

nuxt.config.ts中:

modules: [
    '@unocss/nuxt', // 适配Nuxt的UnoCSS
    '@pinia/nuxt', // 适配Nuxt的Pinia
    ...
],

在不同平台部署

我们的Nuxt项目可以在服务器端通过node-server的形式打包部署,也可以通过Netlify,Vercel进行部署,区别是构建的预设(preset)不同,如

pnpm run build   # 在本地环境默认构建node-server
pnpm run build --preset netlify   # 为netlify构建,通常不用手动执行,因为netlify会帮你完成

针对不同环境,我们可能需要返回服务端的静态文件,此时需要获取服务端的url,所以我们需要对环境进行区分。

这里和Nitro服务端配置方式完全相同,通过nuxt.config.ts添加配置:

runtimeConfig: {
    baseUrl: 'https://xxx.com/xxx',
},

runtimeConfig是在生产环境中,即项目构建后,你能够读取的变量,通过对应的key来读取。

而在开发环境中,可以通过.env文件来配置:

# 注意,nuxt中前缀是NUXT_,而nitro中是NITRO_
NUXT_BASE_URL=http://localhost:8500

然后就可以通过:

const { baseUrl } = useRuntimeConfig(event)

在服务端中读取。

后续

之后在使用Nuxt 3的过程中,我还会持续探索,目前先做到对一个Nuxt项目进行基本的强化改造,之后我会做一个模板,省得每次起Nuxt项目都要配置。


>
CC BY-NC-SA 4.0 2023-PRESENT © Vincent-the-gamer | Version: v1.1.1