选型理由
之前做公司官网,有几个硬需求:
- SEO 友好(需要搜索引擎收录)
- 组件库好看但不要模板感
- 能快速迭代,别被框架束缚
- Vue 技术栈(团队主力方向)
对比了几套方案:
| 方案 |
SEO |
自定义程度 |
开发效率 |
| Vite + Vue SPA |
差 |
高 |
中 |
| Nuxt.js + Element Plus |
好 |
低(模板感重) |
高 |
| Nuxt.js + shadcn-vue |
好 |
高 |
高 |
| Astro + Vue |
好 |
高 |
中 |
选了 Nuxt.js + shadcn-vue。Nuxt 负责 SSR/SSG 和路由,shadcn-vue 提供无头组件(拿过来直接用但可以随便改),自由度拉满。
项目结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| my-site/ ├── app.vue # 根布局 ├── nuxt.config.ts # 核心配置 ├── assets/css/main.css # 全局样式 ├── components/ │ ├── ui/ # shadcn-vue 组件 │ │ ├── Button.vue │ │ ├── Card.vue │ │ └── ... │ └── site/ # 业务组件 │ ├── HeroSection.vue │ ├── FeatureGrid.vue │ └── Footer.vue ├── pages/ │ ├── index.vue # 首页 │ ├── about.vue # 关于 │ └── products/[id].vue # 产品详情 └── server/ └── api/ # Nitro 服务端 API
|
shadcn-vue 的组件直接复制源码到 components/ui/,想改就改,没有「组件库覆盖不了设计稿」的烦恼。
关键实践
1. CSS 变量驱动主题
shadcn-vue 的核心是 CSS 变量,换主题只需要改几行变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| :root { --background: 0 0% 100%; --foreground: 222 47% 11%; --primary: 221 83% 53%; --primary-foreground: 0 0% 100%; --muted: 210 40% 96%; --radius: 0.5rem; }
.dark { --background: 222 47% 11%; --foreground: 210 40% 98%; --primary: 217 91% 60%; }
|
不写死颜色值,全项目通过 hsl(var(--primary)) 引用。暗色模式一键切换。
2. SSR 下的客户端交互
Nuxt 默认 SSR,但像轮播图、动画库这种依赖 window 的组件需要特殊处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <script setup> // ClientOnly 包裹,只在浏览器端渲染 </script>
<template> <ClientOnly> <Swiper :modules="[Autoplay]" :slides-per-view="1"> <SwiperSlide v-for="item in banners" :key="item.id"> <img :src="item.image" :alt="item.title" /> </SwiperSlide> </Swiper> <template #fallback> <div class="h-64 bg-muted animate-pulse rounded-lg" /> </template> </ClientOnly> </template>
|
#fallback 插槽提供 SSR 时的骨架屏,避免布局抖动。
3. SEO 元数据管理
Nuxt 的 useSeoMeta 直接搞定:
1 2 3 4 5 6 7 8
| useSeoMeta({ title: '公司名称 - 产品标语', description: '官网描述,150 字以内', ogTitle: '公司名称', ogDescription: '分享时的描述', ogImage: 'https://cdn.example.com/og-image.png', })
|
不需要额外插件,Nuxt 内置的 SEO 能力已经很够用。
4. 静态生成 (SSG)
官网不需要服务端实时渲染,直接预渲染成静态文件:
1 2 3 4 5 6 7 8 9
| export default defineNuxtConfig({ nitro: { prerender: { routes: ['/', '/about', '/products'], crawlLinks: true, }, }, })
|
npx nuxt generate 之后产出纯静态 HTML,扔到 Nginx 上就行。
5. Tailwind CSS 的克制使用
shadcn-vue 基于 Tailwind,但官网页面容易写得全是 class,可读性差:
1 2 3 4 5
| <!-- 不推荐:class 地狱 --> <div class="flex flex-col items-center justify-center min-h-screen px-4 py-16 bg-gradient-to-b from-slate-50 to-white">
<!-- 推荐:抽成语义化组件 --> <HeroSection />
|
页面级组件保持干净,工具类只在 components/ui/ 和 components/site/ 内部使用。
部署
CI/CD 流程:
1 2 3 4 5
| npx nuxt generate
scp -r .output/public/* user@server:/var/www/site/
|
配合 Nginx 配置 Gzip + 静态资源强缓存:
1 2 3 4
| location /_nuxt/ { expires 1y; add_header Cache-Control "public, immutable"; }
|
感受
shadcn-vue 最大的价值不是组件多——是组件属于你。复制到项目里的代码,你想怎么改就怎么改,不会因为组件库升级导致 UI 崩掉。
Nuxt 4 的 DevTools 也比以前好用很多,热更新快,Vue DevTools 对接丝滑。
官网这种项目,选型对了就成功了一半。剩下的一半是把组件和样式管清楚。