项目初始化:Vite + React + shadcn/ui

从"选了三个月UI库"到"十分钟搭好开发环境",一个前端老油条的选型和搭建笔记

选UI库这件事,我纠结了整整三个月。

去年年初,我们启动了一个新的智能体前端项目。需求不复杂:一个对话界面、一个设置面板、一个历史记录侧边栏、再加上一些表单和图表。看起来就是个标准的中后台应用。但我卡在"用哪个UI库"这个问题上,迟迟下不了手。

Ant Design用过,组件丰富但样式太"Ant味",定制起来像在和框架打架。Material-UI(MUI)也试过,设计系统完整,但包体积太大,而且升级版本经常breaking change。Chakra UI体验不错,但TS支持总觉得差口气。

就在我快被逼疯的时候,一个朋友甩过来一个链接,说:"你看看这个。shadcn/ui。不是npm包,直接把组件源码复制到你项目里。"

我点开一看,官网首页就一句话:"Beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source."

复制粘贴?这听起来也太不"工程化"了。但我还是决定试试。结果这一试,就再也没回过头。

从那以后,我们团队的每一个新项目,起手式都是:Vite + TypeScript + TailwindCSS + shadcn/ui。这套组合拳打下来,项目初始化十分钟搞定,开发体验丝滑到飞起,而且再也没有出现过"升级UI库导致整个项目崩掉"的惨剧。

这篇文章,我就把这套方案的完整初始化流程、避坑指南和实战经验,从头到尾讲一遍。如果你是正准备启动一个新React项目的前端开发者,照着这个做,能少走至少两周的弯路。

一、为什么是Vite + React + shadcn/ui?

在开始动手之前,先花点篇幅聊聊"为什么选这套组合"。毕竟2026年的今天,前端工具链多得让人眼花缭乱,选错了后期维护成本会让你崩溃。

1.1 Vite:为什么不用Create React App了?

我入行的时候,创建React项目只有一种选择:create-react-app(CRA)。但那已经是老黄历了。

CRA在2025年3月被正式标记为deprecated,官方推荐迁移到Vite或Next.js。CRA慢、配置臃肿、热更新卡顿,这些问题大家都心知肚明,但至少它"能跑"。

Vite不一样。它利用ESM(ES Module)和esbuild,开发服务器启动速度几乎跟项目大小无关------我见过最大的项目(几百个组件),npm run dev冷启动也就一两秒。热更新(HMR)更是快到离谱,改完代码几乎不用刷新就能看到变化。

我们团队还有一个刚入行的前端实习生,第一次用Vite的时候感慨:"怎么比我的Python热重载还快?"

最狠的一点是:Vite的配置极其简洁。 不需要eject,不需要craco,一个vite.config.ts文件搞定所有事情。

总结一句话:2026年的今天,新建任何React项目,如果不考虑SSR和SEO需求,Vite就是默认选项,没有之一。

1.2 React 19:做智能体前端到底有啥好处?

React 19在2024年底正式发布,带来了几个让我们团队集体"真香"的新特性。

对我们智能体前端项目来说,最有价值的是Actions 。它专门用来简化表单提交和异步操作的状态管理。以前的智能体对话输入框,发消息的时候要手动管理isPendingerror、重置输入框状态这些琐碎逻辑。用了useActionState Hook之后,代码量直接砍半,而且不用再担心忘记处理loading状态导致的重复提交问题。

另一个让团队兴奋的是React Compiler 。以前写函数组件,为了性能优化要在各种地方加useMemouseCallback,代码丑不说,还容易写错导致闭包陷阱。开启React Compiler之后,编译器会在构建时自动分析组件的依赖关系,做细粒度的重新渲染优化。我们实测下来,一个中等复杂度的页面开启了Compiler之后,不必要的重渲染减少了60%以上,而且我们可以把代码里所有手写的useMemouseCallback删掉,代码可读性提升了不止一个档次。

Server Components虽然我们前期用得不多(智能体前端大部分是CSR),但后期要做的对话历史管理功能,用Server Components可以直接在服务端fetch数据,减少客户端API调用。

1.3 shadcn/ui:它到底跟传统UI库有什么不一样?

说人话版本:shadcn/ui不是npm包。它是一堆你可以直接复制到你项目里的组件源码。

传统UI库(Ant Design、MUI)的逻辑是:你从npm安装一个大的依赖包,然后从里面import组件。问题在于:你没法改它的源码。设计团队要你把按钮圆角从4px改成6px,你得去翻文档找覆盖方法,可能要写一堆复杂得离谱的CSS选择器才能生效。

shadcn/ui的逻辑完全不同。你运行npx shadcn@latest add button,CLI会直接把button.tsx的完整源码复制到你的components/ui/目录下。这个文件完全属于你。你可以随便改------改圆角、改颜色、加新变体、删不需要的属性,想怎么改就怎么改。

用了一年多shadcn/ui,我最想强调的三个好处是:

  • 没有版本锁死的烦恼:传统UI库从v4升级到v5,breaking change能让你改几十个组件。shadcn/ui不存在"升级"这个概念------你复制进来的代码,是"冻住"的。除非你主动去shadcn/ui官网复制新版本覆盖,否则它永远不会变。
  • 打包体积极小:传统UI库即使你只用一个Button,打包器也常常保守地保留整个库的代码。shadcn/ui只打包你显式复制过的组件。典型的一个shadcn/ui项目,bundle只增加20--50KB,远小于传统库的200-500KB。
  • 完全可定制 :你想给Button加一个"brand"变体,传统UI库可能要写一堆createThemestyleOverrides甚至TypeScript的类型增强。shadcn/ui只需要打开button.tsx,在buttonVariants对象里加一个条目,完事。

截至2026年初,shadcn/ui的GitHub星标数已经突破11万,npm周下载量接近200万,是React生态中增长最快的UI解决方案。这套"复制代码,而非安装依赖"的模式,正在重塑前端UI层的工程化实践。

1.4 为什么这三件套搭在一起这么顺?

Vite提供极致的开发体验和构建性能,React 19提供最新的前端能力和性能优化工具,shadcn/ui提供高质量、可定制的组件。三者没有依赖冲突,配置互相兼容,上手难度低,简直就是现代前端项目初始化的"黄金标准"。

截至2026年初,这套技术栈的组合已成为许多新React项目的默认选择,无论是企业内部系统、SaaS应用,还是个人项目,都能快速搭建出专业且可维护的前端架构。

二、十分钟极速初始化:从0到1跑起来

理论讲得差不多了,现在动手。我把整个过程拆成了6步。全程跟着做,十分钟内你就能看到一个漂亮的shadcn/ui组件跑在浏览器里。

环境要求:Node.js 18以上(建议LTS版本),任何现代代码编辑器(VSCode推荐)。

步骤1:创建Vite + React + TypeScript项目

打开终端,执行下面这行命令:

bash 复制代码
npm create vite@latest my-agent-frontend -- --template react-ts

my-agent-frontend可以换成你自己的项目名。-- --template react-ts告诉Vite生成React + TypeScript的模板。

然后进入项目目录安装依赖:

bash 复制代码
cd my-agent-frontend
npm install

npm run dev跑起来看看效果,访问http://localhost:5173,你应该能看到Vite + React的默认首页。这证明项目骨架已经搭好了。

步骤2:集成TailwindCSS v4

Vite项目里集成Tailwind,在2026年已经变得极其简单。之前需要安装postcss、配置postcss.config.js、手写tailwind.config.js。现在Tailwind v4有了官方的Vite插件,全程只需要一两分钟。

安装tailwindcss和它的Vite插件:

bash 复制代码
npm install tailwindcss @tailwindcss/vite

打开vite.config.ts,导入tailwindcss并在plugins数组中添加:

ts 复制代码
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import tailwindcss from '@tailwindcss/vite';  // 👈 加这行

export default defineConfig({
  plugins: [
    tailwindcss(),  // 👈 加这行(注意放在react之前)
    react(),
  ],
});

打开src/index.css,删除所有内容,只保留一行:

css 复制代码
@import 'tailwindcss';

这一步告诉Tailwind所有工具类都应该生效。不需要 再写@tailwind base;这些。

步骤3:配置路径别名(@/)

路径别名@/可以避免你写../../../components/ui/button这种恶心人的相对路径。这是所有现代React项目的标配。

vite.config.ts中,resolve字段里配置别名:

ts 复制代码
import path from 'path';

export default defineConfig({
  // ... plugins 部分不变
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
});

TypeScript那边也得同步配置,否则编辑器会报找不到模块。创建或修改tsconfig.json(如果用的是JS版就创建jsconfig.json):

json 复制代码
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

重启IDE,这时候你可以在项目里写import Button from '@/components/ui/button'了。

步骤4:初始化shadcn/ui

运行shadcn CLI的初始化命令:

bash 复制代码
npx shadcn@latest init

CLI会问你几个问题。我建议你这么选:

  • Which style would you like to use?New York(现代一点,组件样式设计感更强)或者Default(简洁稳妥)都可以。
  • Which color would you like to use as base color? 建议选Slate,中性的灰色调,搭配自由度最高。未来切换主题色也很方便。
  • Do you want to use CSS variables for colors?yes。这是shadcn/ui实现暗黑模式和动态主题切换的基础。

执行init之后,CLI会帮你做几件事:安装class-variance-authorityclsxtailwind-mergelucide-react等必要的依赖,同时自动创建components.json配置文件并在src/下生成lib/utils.ts

步骤5:添加第一个组件

现在往项目里加一个Button组件看看效果:

bash 复制代码
npx shadcn@latest add button

执行完这条命令,你的src/components/ui/目录下会多出一个button.tsx文件。打开它,你会看到完整的组件源码------一个基于Radix UI原语构建、使用Tailwind CSS变量(如bg-primary)设计、支持各种变体(variantsize)的Button,所有的样式和逻辑都写在这个文件里。

步骤6:写几行代码验证一下

src/App.tsx改成下面这样:

tsx 复制代码
import { Button } from '@/components/ui/button';

function App() {
  return (
    <div className="flex min-h-screen items-center justify-center">
      <Button>
        你好,shadcn!
      </Button>
    </div>
  );
}

export default App;

运行npm run dev,打开浏览器,你应该能看到一个漂亮的、带圆角和悬停效果的按钮出现在屏幕中央。这就是shadcn/ui组件的默认设计风格,基于Tailwind CSS变量(如--primary--background)定义,颜色自然贴合Tailwind的调色板。

三、高阶配置

基础流程走完了,但要让项目真正"好用",下面这些配置最好也一起做了。这些都不是可选项,而是我们团队在过去一年里从无数次踩坑中总结出的"血泪经验"。

3.1 明暗主题切换(Dark Mode)

现代应用默认就要支持暗黑模式,shadcn/ui天然支持CSS变量主题系统,实现起来非常优雅。shadcn的组件都使用了如--background--foreground这类CSS变量,因此当我们在<html>上添加dark类时,变量的值会自动切换为深色模式下的配置。

最佳实践是用next-themes库来管理。它跟shadcn/ui是官方推荐组合,能完美处理localStorage持久化和系统主题跟随。

安装next-themes

bash 复制代码
npm install next-themes

src/main.tsx中包裹ThemeProvider:

tsx 复制代码
import { ThemeProvider } from 'next-themes';

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
      <App />
    </ThemeProvider>
  </StrictMode>,
);

创建src/components/ThemeSwitcher.tsx

tsx 复制代码
import { useTheme } from "next-themes";
import { Button } from "@/components/ui/button";
import { Moon, Sun, Monitor } from "lucide-react";

export function ThemeSwitcher() {
  const { theme, setTheme } = useTheme();

  return (
    <div className="flex gap-2">
      <Button variant="outline" size="icon" onClick={() => setTheme("light")}>
        <Sun className="h-4 w-4" />
      </Button>
      <Button variant="outline" size="icon" onClick={() => setTheme("dark")}>
        <Moon className="h-4 w-4" />
      </Button>
      <Button variant="outline" size="icon" onClick={() => setTheme("system")}>
        <Monitor className="h-4 w-4" />
      </Button>
    </div>
  );
}

这三个按钮分别对应亮色、暗色和跟随系统。用户的选择会自动保存到localStorage,刷新页面不丢失。

3.2 样式冲突的处理

把shadcn/ui集成到一个已有的老项目里,或者项目里同时存在多套CSS方案,很容易出现样式冲突------比如按钮突然变了颜色,布局乱掉,甚至整个页面的字体都不一样。

这个问题我遇到过一次,查了整整一天。症状是shadcn组件样式完全没生效,按钮显示成了原生的HTML按钮(丑得没法看)。后来发现是index.css@import 'tailwindcss'被放在了其他样式导入后面,导入顺序导致样式被覆盖。

解决方案只有一个原则 :确保@import 'tailwindcss'@import './index.css'出现在任何其他自定义样式之前

css 复制代码
/* src/index.css */
@import 'tailwindcss';

/* 然后是任何其他全局样式或者第三方库样式 */

如果项目里有自己的base.css或者第三方UI库,需要把Tailwind的导入放在最顶部。

3.3 React Compiler性能优化

React 19最大的性能彩蛋之一就是React Compiler。它能在构建时自动分析组件的依赖关系,生成更细粒度的重新渲染代码,避免了开发者在日常开发中为了优化手写大量useCallbackuseMemomemo

安装babel-plugin-react-compiler

bash 复制代码
npm install -D babel-plugin-react-compiler

修改vite.config.ts,在React插件里加上babel配置:

ts 复制代码
export default defineConfig({
  plugins: [
    tailwindcss(),
    react({
      babel: {
        plugins: [["babel-plugin-react-compiler", { target: "19" }]],
      },
    }),
  ],
});

重启开发服务器。这时候你可以自信地删掉代码里那些为了"避免子组件重渲染"而写的useCallbackuseMemo。编译器会自动帮你做更精准的优化。

3.4 代码规范与格式化

团队协作时,统一代码风格比选对UI库重要得多。我们配了一套ESLint + Prettier + Husky的组合拳:

bash 复制代码
npm install -D eslint prettier @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-react-hooks eslint-config-prettier husky lint-staged

根目录创建.prettierrc

json 复制代码
{
  "semi": false,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5"
}

安装Husky和lint-staged,配置pre-commit钩子。每次git commit之前自动跑格式化和lint,确保提交到仓库的代码风格统一。这步不做,早晚因为空格和换行问题在Code Review里吵起来。

四、实战经验与避坑指南

这章是全篇最值钱的部分,记录了我们团队在过去一年里被shadcn/ui"坑"过无数次之后总结出的生存经验。

4.1 组件安装的取舍策略

shadcn/ui CLI提供了npx shadcn@latest add --all一次性安装所有组件的命令。千万不要在生产项目里用。

--all会把Dialog、Alert Dialog、Tooltip、Avatar、Carousel等几十个组件的源码一股脑复制进你的components/ui/目录。哪怕你只用其中三个,这些文件也会全部打在你的bundle里(虽然每个都很小,但文件数量多也会影响构建速度和模块依赖分析的复杂度)。

正确做法是按需添加。当产品经理提了新需求,需要加弹窗的时候,运行npx shadcn@latest add dialog,然后把<Dialog>组件import进来。这样你的UI目录永远只包含实际使用的组件,干净、易懂、维护成本低。

4.2 定制化组件的正确姿势

shadcn/ui最大的价值就是"代码即所有权"。遇到设计团队要求修改组件细节,直接打开components/ui/button.tsx源码改,不要在外面包一层或者写覆盖样式

举个栗子。如果设计师要求所有按钮的圆角从rounded-md改成rounded-lg

tsx 复制代码
// components/ui/button.tsx
const buttonVariants = cva(
  "inline-flex items-center justify-center rounded-lg ...", // 这里直接改
  // ...
)

一个真实案例:某客户要求Button增加一个带彩色渐变背景的"AI专用"样式。传统做法是翻阅组件库文档写className="..."覆盖,或者加一层wrapper。用shadcn/ui,我们直接在buttonVariants对象的variants分支里加了一个ai变体,按钮自己的样式、悬停效果、禁用状态一次定义好,调用的时候只需要<Button variant="ai">Ask AI</Button>,代码语义化超强。

4.3 路径别名踩坑实录

配置完vite.config.ts里的@别名之后,有时候VSCode还是不认识@/components/ui/button,import下面画红线。

大概率是TypeScript不知道路径映射。在根目录的tsconfig.json(或jsconfig.json)里加上:

json 复制代码
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

改了tsconfig.json之后,关掉VSCode再重新打开项目,应该就正常了。

4.4 IDE集成与智能提示

VSCode用户强烈建议安装Tailwind CSS IntelliSense插件。这个插件能帮你自动补全Tailwind的类名,悬停时展示CSS效果,极大提升开发效率。插件商店直接搜索"Tailwind CSS IntelliSense"安装即可。

对于TypeScript项目,shadcn/ui的组件都有完整的类型定义,不用额外安装@types包,写代码时自动补全和类型提示也是开箱即用的。

4.5 v4版本升级注意事项

我们踩过坑。因为某个老项目还在用Tailwind v3,迁移到v4后shadcn/ui的CLI配置和CSS变量定义细节变了,导致组件样式失效。

在Tailwind v4中,postcss.config.jstailwind.config.js不再是必须的。所有配置集中迁移到了vite.config.ts中通过插件引用,以及src/index.css里的@import 'tailwindcss'@theme语法块中。如果你在升级后遇到样式全乱的问题,检查一下vite.config.ts里是不是忘了加tailwindcss()插件,或者src/index.css里是不是没有@import 'tailwindcss'

五、项目结构推荐与后续扩展

初始化完成之后,我们团队习惯把项目结构组织成下面这样:

复制代码
src/
├── components/
│   ├── ui/              # shadcn/ui 组件(自动生成)
│   ├── chat/            # 智能体对话相关组件(自己写)
│   └── layout/          # 布局组件
├── lib/                 # 工具函数(shadcn 的 utils.ts 在这里)
├── hooks/               # 自定义 React Hooks
├── pages/               # 页面组件
├── stores/              # Zustand 状态管理
├── types/               # TypeScript 类型定义
├── App.tsx
├── main.tsx
└── index.css

这个结构把shadcn/ui的源码(components/ui/)和业务组件(components/chat/components/layout/)分开放置,逻辑清晰,维护方便。

有了这套基础环境,下一步可以逐步引入几个必装的扩展组件库。日常必装(建议第一批添加)的包括:

  • 表单npx shadcn@latest add form------配合react-hook-formzod实现类型安全的表单验证
  • 弹窗npx shadcn@latest add dialog
  • 提示npx shadcn@latest add sonner------toast通知
  • 表格npx shadcn@latest add table------基础表格展示
  • 下拉菜单npx shadcn@latest add dropdown-menu

后期待功能需求扩张时再逐步添加selectcalendardata-table(复杂表格)等其他组件。

智能体前端核心交互是聊天对话框,几个会频繁用到的shadcn组件包括:展示对话气泡用Card;输入问题用Input配合Form做表单验证;展示Markdown格式的回答时用Card搭配react-markdown库;多轮历史对话列表用ScrollArea做滚动容器;侧边栏历史记录列表用SheetSheet配合Button实现。这些都是shadcn/ui原生提供的,不需要额外找第三方库。

六、总结:一套搞定所有"脏活累活"

回到开头那个问题:为什么选Vite + React + shadcn/ui?

Vite扛起了性能和开发体验的旗npm run dev启动快到飞起,配置文件极度简洁,热更新几乎是即时的。再也不用等Webpack慢慢转圈了。

React 19提供了一堆扎实的新功能useActionState简化了智能体对话的异步状态管理,React Compiler帮我们自动优化了90%的性能问题------手动写useCallback的时代已经过去了。

shadcn/ui解决了UI层最头疼的定制问题和版本锁定问题。2025年公司某后端项目用了Ant Design,2026年想升级v5到v6,整个过程改了两周代码。shadcn/ui不存在"跨版本升级",因为代码就在你的项目里,它是"冻结"的,风格稳定可控。而且设计师提出任何新需求,改源码就完事,不用跟组件库打架。

用了一年多,这三样东西已经成了我们团队的"起手三件套"。任何新项目,只要需要做前端界面,统统先用这套组合把架子搭好。十分钟后,一个配置完备、主题可切换、组件库齐全、开发体验拉满的现代化前端项目就立起来了。

然后你只需要专注做一件事:写智能体本身的业务逻辑

相关推荐
ZC跨境爬虫12 小时前
模块化烹饪小程序开发日记 Day4:网络层基础设施与接口治理实践
前端·javascript·数据库·ui·html
冴羽yayujs12 小时前
快速夯实 JavaScrilpt 基础的 33 个概念
前端·javascript·github·前端开发
放下华子我只抽RuiKe512 小时前
React 从入门到生产(二):状态与事件处理
前端·人工智能·深度学习·react.js·机器学习·前端框架·github
Maimai1080812 小时前
React 项目目录结构怎么设计:从基础分层到真实业务落地
前端·javascript·react.js·microsoft·前端框架
Csvn12 小时前
CSS 技巧:移动端适配
前端
小茴香35312 小时前
大文件分片上传(前后端实现Vue+node.js)
前端·vue.js·node.js
Csvn12 小时前
前端技术 - 跨端方案对比
前端
七夜zippoe12 小时前
OpenClaw Chrome 扩展:Browser Relay 配置
前端·chrome·openclaw·brower
之歆13 小时前
DAY_12JavaScript DOM 完全指南(三):高级工程篇
开发语言·前端·javascript·ecmascript