使用nuxt3重构个人网站
不闻不若闻之,闻之不若见之,见之不若知之,知之不若行之,学至于行而止矣。
前言
使用Nuxt 3重构个人网站:从Vite到Nuxt的转型之旅
在前端开发领域,技术的更新换代总是快速而频繁的。作为一名热衷于技术探索的开发者,学习使用新的技术栈来以保持与时俱进。最近,我决定将我的个人网站从基于Vite 5.x、Vue 3、Tailwind CSS、Pinia、Bootstrap 5.x以及Element-Plus组件库的技术栈,转型为使用Nuxt 3、Vue 3、Tailwind CSS、Pinia和Quasar的新架构。
背景与动机
我的个人网站最初是基于Vite 5.x和Vue 3构建的,使用了Tailwind CSS进行样式设计,Pinia作为状态管理工具,Bootstrap 5.x用于快速布局和样式预设,以及Element-Plus组件库来丰富页面交互。然而,对于SPA来说,SEO的支持并不是那么的友好。
此外:
- 首屏加载时间长:SPA将所有页面资源打包在一个文件中,可能导致首屏加载时间较长。
- SEO挑战:由于SPA是通过JavaScript动态渲染内容的,搜索引擎可能难以索引其内容,从而影响SEO效果。不过,可以通过服务端渲染(如Nuxt3的SSR模式)等技术来改善SEO。
- 对JavaScript的依赖:SPA高度依赖于JavaScript,如果用户的浏览器不支持或禁用了JavaScript,则可能导致应用无法正常工作。
随着Nuxt 3的发布,我被其带来的服务器端渲染(SSR)和静态站点生成(SSG)的功能所吸引。Nuxt 3不仅能够提供更快的页面加载速度和更好的用户体验,还能通过其内置的功能和插件生态,简化开发流程,提高开发效率。因此,我决定对网站进行重构,顺便也作为一个学习nuxt的练习项目。
Nuxt 3
- Nuxt 3 vs Vite 5.x
Nuxt 3是一个基于Vue 3的服务器端渲染框架,它提供了丰富的功能和插件生态,支持SSR、SSG和静态网站部署。Nuxt使用约定和一套规范的目录结构来自动化重复的任务,让开发者可以专注于推动功能的开发。配置文件仍然可以自定义和覆盖其默认行为。
认识nuxt3
- 基于文件的路由: 根据
pages/
目录的结构定义路由。这样可以更容易地组织应用程序,避免手动配置路由的需要。 - 代码分割: Nuxt自动将代码拆分成较小的块,这有助于减少应用程序的初始加载时间。
- 内置服务器端渲染: Nuxt具备内置的服务器端渲染能力,因此你不需要自己设置单独的服务器。
- 自动导入: 在各自的目录中编写Vue组件和可组合函数,并在使用时无需手动导入,享受树摇和优化JS捆绑包的好处。
- 数据获取工具: Nuxt提供了可用于处理与服务器端渲染兼容的数据获取的可组合函数,以及不同的策略。
- 零配置的TypeScript支持: 可以编写类型安全的代码,无需学习TypeScript,因为我们提供了自动生成的类型和
tsconfig.json
配置文件。 - 配置好的构建工具: 我们默认使用Vite来支持开发中的热模块替换(HMR),以及在生产中将代码打包成符合最佳实践的形式。
服务器端渲染
-
Nuxt默认具备内置的 服务器端渲染(SSR)能力,无需自己配置服务器,这对于Web应用有许多好处:
- 更快的初始页面加载时间: Nuxt向浏览器发送完全渲染的HTML页面,可以立即显示。这可以提供更快的页面加载时间和更好的用户体验(UX),特别是在网络或设备较慢的情况下。
- 改善SEO: 搜索引擎可以更好地索引SSR页面,因为HTML内容立即可用,而不需要依赖JavaScript在客户端渲染内容。
- 在低功率设备上的更好性能: 减少了需要在客户端下载和执行的JavaScript量,这对于处理重型JavaScript应用程序可能有困难的低功率设备非常有益。
- 更好的可访问性: 内容在初始页面加载时立即可用,改善了依赖屏幕阅读器或其他辅助技术的用户的可访问性。
- 更容易的缓存: 页面可以在服务器端缓存,这可以通过减少生成和发送内容所需的时间而进一步提高性能。
总体而言,服务器端渲染可以提供更快更高效的用户体验,同时改善搜索引擎优化和可访问性。
-
Quasar vs Bootstrap 5.x + Element-Plus
Quasar是一个基于Vue 3的开源UI框架,它提供了丰富的组件和插件,支持多种平台和设备。与Bootstrap 5.x和Element-Plus相比,Quasar更加专注于Vue 3的集成和优化,提供了更加灵活和可定制的组件库。此外,Quasar还支持Material Design、iOS和Android等多种设计风格,使得开发者可以更加轻松地构建出符合用户需求的界面。
创建nuxt项目
要求:Node.js - v18.0.0
或更新版本
npx nuxi@latest init <project-name>
搭建项目结构
首先,我使用Nuxt 3的官方脚手架工具创建了一个新的项目,并配置了必要的依赖和插件。然后,我根据网站的需求,设计了合理的项目结构,包括页面、组件、样式、路由等部分。
leisure-article
├── README.md
├── api # 接口文件
├── app.vue # 入口文件
├── assets # 静态资源
├── components # 全局组件
├── composables # 组合式函数
├── constant # 枚举常量
├── ecosystem.config.js
├── layouts # 布局文件
├── nuxt.config.ts # 配置文件
├── pages # 页面文件
├── plugins # 插件
├── server # 服务端
├── store # 状态管理
├── tailwind.config.ts # tailwindcss配置
├── tsconfig.json
└── utils # 工具类
配置tailwindcss
- 安装
# Using pnpm
pnpm add --save-dev @nuxtjs/tailwindcss
# Using yarn
yarn add --dev @nuxtjs/tailwindcss
# Using npm
npm install --save-dev @nuxtjs/tailwindcss
- 添加到
nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@nuxtjs/tailwindcss'
]
})
- 配置
tailwind-config
import type { Config } from 'tailwindcss'
export default {
prefix: 'cz-',// 配置样式前缀,以cz-xxx开头
content: [
'./components/**/*.{vue,js,ts}',
'./layouts/**/*.vue',
'./pages/**/*.vue',
'./app.{js,ts,vue}'
],
// 3.4+版本的配置,如果不是,查看官网进行修改
darkMode: ['class', '[class="dark"]'],
theme: {
extend: {
boxShadow: {
base: '2px 2px 5px 1px rgba(229,231,235,1)'
}
}
},
plugins: []
} satisfies Config
以上是基于nuxt3集成了tailwindcss
,所以会少很多的配置就可以直接使用,如果不是,需要根据tailwindcss进行配置
bootstrap-icons图标库
使用bootstrap-icons图标库有两种方式,一是使用官方的安装方式,二是使用nuxt3集成的nuxt-bootstrap-icons方式,使用这种方式的好处是有图标提示,但是我这里使用的是第一种方式。至于为什么没有使用集成的图标库,因为在使用过程中发现有些图标无法使用,大概看了源码,基本上也是使用bootstrap-icons进行封装,所以直接使用官网的方式可能会直接一点,直接选择需要的图标复制代码即可。
- 安装
npm i bootstrap-icons
- 引入样式文件
// app.vue
import 'bootstrap-icons/font/bootstrap-icons.css';
集成Quasar组件库
开始的想法是不依赖任务的组件库进行重构,但是基于目前个人的业余时间限制,同时也想着能够更快的重构完成,先基于组件库方法开发吧。
在做组件库选择的时候,为什么没有选择Element-Plus
继续作为UI库,其一原因是它对于响应式的配合度不是很高,然后转而想使用vuetify组件框架进行重构,但是在使用的过程中发现,在进行SSR时,会出现一些组件水合问题,关于这一个问题在其issue
上面也会有一样的问题,但是还是无法解决,对于一个有着强迫症😂的人来说,总感觉哪里怪怪的。
在迁移过程中,我逐渐将原有的Bootstrap 5.x和Element-Plus组件替换为Quasar组件。至于为什么选择Quasar
因为:
- 基于Vue.js
- 开箱即用的提供给网站和应用程序的最先进的UI(遵循《Material指南》)
- 开箱即用的对桌面和移动浏览器(包括iOS Safari!)的最佳支持
- 通过与我们自己的CLI紧密集成,对每种构建模式(SPA、SSR、PWA、移动应用程序、桌面应用程序和浏览器扩展)提供了一流的支持,并提供了最佳的开发人员体验
- 易于自定义(CSS)和可扩展(JS)
- 这是最注重性能的框架
- 自动tree shaking
- 在我们的论坛和Discord聊天基础上的很棒的社区
- 具有包括新功能在内的定期发布周期
- 获得快速修复并听取社区的要求
- 处理整个开发经验(甚至包括创建应用程序的图标和启动画面)
QIcon组件允许你轻松地在其他组件或页面的任何其他区域插入图标。 Quasar开箱即用支持:Material Icons、Material Symbols、Font Awesome、Ionicons、MDI、Eva Icons、Themify Icons、Line Awesome和 Bootstrap Icons。
此外,您可以对任何图标库自行添加支持。
Quasar中有多种图标类型:基于Webfont,基于svg和基于图像。 您不必在网站/应用中仅使用一种类型。
重要的是,其图标库组件还会支持bootstrap-icons
,完美的契合度🙌
以上时来自Quasar官网的介绍,这一看,哎,这不是符合我的需求嘛,开箱即用的桌面和移动浏览器端,噗哈哈哈哈(太开心了🤣🤣🤣)
- 安装
# npm
npm install quasar @quasar/extras
npx nuxi@latest module add quasar
- 配置nuxt.config.ts
quasar: {
// 添加相关插件
plugins: [
'Notify',
'Dialog'
],
extras: {
font: 'roboto-font',
},
components: {
defaults: {
QBtn: {
unelevated: true,
},
},
},
},
迁移页面和组件
接下来,我开始将原有的页面和组件迁移到新的项目中。由于Nuxt 3和Vue 3的API与Vite 5.x和Vue 3基本一致,因此迁移过程相对顺利。我主要关注于页面和组件的布局、样式和交互逻辑的实现,确保它们在新的项目中能够正常工作。
开始码字
时间原因此处省略xxx字(后面抽时间补上噗哈哈哈哈)
部署上线
node环境
- 打包
npm run build
- 编写启动文件
ecosystem.config.js
module.exports = {
apps: [
{
name: 'articleNuxt',
port: '6666',
exec_mode: 'cluster',
instances: 'max',
script: './server/index.mjs'
}
]
}
打包后的文件,然后将ecosystem.config.js复制到。output目录下即可。

-
宝塔面板启动项目
可能第一次启动的时候会出现,找不到package.json提示,此时,关闭然后修改项目目录即可。

nginx配置代理
主要部分配置文件
在添加域名和开启外网访问时,会生成相关的nignx
文件,然后添加以下代理即可。
server
{
# HTTP反向代理相关配置开始 >>>
location ~ /purge(/.*) {
proxy_cache_purge cache_one $host$request_uri$is_args$args;
}
location / {
proxy_pass http://127.0.0.1:端口;# 转发到pm2启动的项目地址,一般默认127.0.0.1地址即可
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
add_header X-Cache $upstream_cache_status;
proxy_set_header X-Host $host:$server_port;
proxy_set_header X-Scheme $scheme;
proxy_connect_timeout 30s;
proxy_read_timeout 86400s;
proxy_send_timeout 30s;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# HTTP反向代理相关配置结束 <<<
#PROXY-START/api/
# 可以不配此处
location ~* \.(php|jsp|cgi|asp|aspx)$
{
proxy_pass https://xxx域名地址;
proxy_set_header Host xxx域名地址;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
}
# 启用api代理
location ^~ /api/
{
proxy_pass https://xxx域名地址/;
proxy_set_header Host xxx域名地址;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
add_header X-Cache $upstream_cache_status;
#Set Nginx Cache
proxy_set_header Accept-Encoding "";
sub_filter "/api/" "/";# 注意将api替换成需要代理的前缀
sub_filter_once off;
add_header Cache-Control no-cache;
expires 12h;
}
#PROXY-END/api/
access_log /www/wwwlogs/server.log;
error_log /www/wwwlogs/server.error.log;
}
完美效果(部分截图)


好了,今天就写到这里吧~,最后祝大家五一节日快乐叭。
