全栈项目之博客系统 学习日记 (第一章)
前言 🚀
AI Agent 时代的 IT 行业,单会前端或者单会后端已经不足以满足市场需求,"AI + 全栈" 才是程序员的核心竞争力。这个系列我将从前端到后端,一步一个脚印,打造一个功能完备的博客系统 ------ 包含登录功能、文章系统、AIGC 生成功能,后端将采用 NestJS 框架搭建。
作为系列的开篇,我们先聚焦前端基础搭建,用 React + TypeScript + Vite 构建项目骨架,搭配 shadcn/ui 组件库和 Tailwind CSS 样式,再通过 React Router 实现路由管理,为后续功能开发打下坚实基础~
一、初始化 React 项目 🏗️
想要开启前端开发,第一步就是搭建标准的项目结构。按照以下步骤操作,快速初始化一个 React + TypeScript + Vite 项目:
- 打开终端,执行初始化命令:
npm init vite - 给项目命名为
notes(对应博客系统的核心功能) - 框架选择
React(成熟稳定,生态丰富) - 变体选择
TypeScript(静态类型检查,减少开发 bug) - 后续配置默认选择即可完成初始化
初始化完成后,执行 cd notes 进入项目目录,再通过 pnpm i 安装依赖,最后用 npm run dev 启动项目,就能看到默认的 React 初始页面啦~
如果对 React 的组件思想、Vite 的构建原理或 TypeScript 的类型定义还不熟悉,建议先翻翻我前面的文章补充相关基础知识点,再继续后续开发哦~
二、UI 组件库:shadcn/ui ✨
1. 什么是 shadcn/ui?
shadcn/ui 是一个基于 Tailwind CSS 和 Radix UI 构建的开源 UI 组件库,它不像 Ant Design 那样需要全局引入,而是采用 "按需下载、本地修改" 的模式,组件源码会直接复制到项目中,支持完全自定义样式和逻辑。
2. 为什么选择 shadcn/ui?
- 严格按需加载:只下载当前页面需要的组件,不会引入冗余代码,有效减少项目体积
- 可定制性强:组件源码本地化,支持根据需求修改样式、逻辑,适配各种设计风格
- 与 Tailwind CSS 深度融合:无需额外编写大量样式,直接通过 Tailwind 工具类扩展样式
- 类型安全:完全支持 TypeScript,每个组件都有完善的类型定义,开发体验更流畅
3. 安装 shadcn/ui
执行命令:pnpm i shadcn@latest安装完成后,打开 package.json 文件,就能看到 shadcn 的版本号(本项目使用 3.7.0 版本),表示组件库已成功引入项目。
三、配置 Tailwind CSS 🎨
shadcn/ui 本身基于 Tailwind CSS 构建,必须先配置好 Tailwind,才能解锁 shadcn 的完整功能。而且 shadcn 的初始化命令会校验 Tailwind 配置,未配置或配置不规范会直接终止执行,所以这一步至关重要~
配置步骤:
- 安装依赖:执行
npm install tailwindcss @tailwindcss/vite,同时安装 Tailwind 核心包和 Vite 插件 - 配置 Vite:在
vite.config.ts中引入 Tailwind 插件,确保样式能被正确解析(后续会详细说明 Vite 完整配置)

- 引入样式:在
src/index.css清空所有样式再添加@import 'tailwindcss';,加载 Tailwind 基础样式

- 清理冗余文件:清空默认生成的
app.css,避免样式冲突 - 适配布局:在
App.tsx中添加弹性布局相关样式,确保页面结构自适应
四、配置 Vite:路径别名与类型声明 🛠️
Vite 作为现代化构建工具,配置路径别名能让模块导入更简洁,提升开发效率。具体配置如下:
1. 核心配置:路径别名
打开 vite.config.ts,添加 resolve.alias 配置,将 @ 映射到 src 目录:
typescript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'
import path from 'path' // Node.js 内置模块,用于处理文件路径
export default defineConfig({
plugins: [react(), tailwindcss()],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'), // __dirname 表示当前文件所在目录
}
}
})

这样一来,我们导入组件时就可以用 @/components/Button 替代 ../../components/Button,路径更简洁,维护更方便~
2. Node 类型声明
由于我们使用了 Node.js 的 path 模块,TypeScript 会缺少类型声明,导致编译报错。需要单独安装类型声明文件:
- 执行命令:
pnpm i -D @types/node(-D表示开发依赖,只在开发环境生效)
3. 避坑指南:安装错误处理
如果不小心输错命令(比如少写 types 的 s),会导致类型声明缺失,项目爆红。此时需要按以下步骤修复:
Remove-Item -Recurse -Force node_modules, pnpm-lock.yaml:删除 node_modules 和锁文件(Windows 系统)pnpm i:重新安装所有依赖pnpm i -D @types/node:正确安装 Node 类型声明文件
五、TS 配置文件:目录输出建议 📝
为了获得目录输出建议能力以提升我们的项目开发效率,并适配 Vite 中配置的路径别名(@ -> src),需要在 TypeScript 配置文件中同步配置 baseUrl 和 paths,确保 TypeScript 能正确识别路径别名,避免类型校验报错。
配置方式
在 tsconfig.json 文件的 "compilerOptions" 配置块中添加以下内容:
json
{
"compilerOptions": {
// 保留原有其他配置项...
"baseUrl": ".",
"paths": {
"@/*": [
"src/*"
]
}
}
}
baseUrl: 设定模块解析的基础目录为项目根目录(.),TypeScript 会基于该目录解析非相对路径的模块。paths: 配置路径映射规则,将@/*映射到src/*,与 Vite 中的别名配置保持一致,保证在 TS 代码中使用@/xxx形式引入文件时,类型检查和代码提示功能正常工作。- 需要注意的是:该配置必须和 Vite 的别名配置配合使用,否则会出现「TS 类型提示正常,但运行 / 打包报错」的问题。
配置完后,我们来到app.tsx。观察下面图片,src目录下的目录或文件会被提示出来供我们选择,理解目录输出建议带来的效果:

六、初始化 shadcn/ui:按需加载组件 📦
配置完 Tailwind CSS、Vite 别名和 TS 路径后,才能初始化 shadcn/ui------ 因为 shadcn 的 CLI 会依赖这些配置,确定组件的安装路径和代码规范。
1. 执行初始化命令
在终端输入:npx shadcn@latest init,执行后会出现交互配置:
- 选择样式风格:默认选择
Neutral主题(简洁百搭,适合博客系统) - 其他配置保持默认
2. 初始化后生成的核心文件
components.json:项目根目录下的核心配置文件,记录 shadcn 的基础配置(组件路径、主题风格、是否支持 TS 等),后续添加组件时会自动更新,无需手动修改src/components/目录:包含通用组件和 UI 组件子目录,所有下载的 shadcn 组件都会放在src/components/ui/下src/lib/目录:存放 shadcn 依赖的工具函数(如cn函数,用于合并 Tailwind 类名)
3. 按需添加组件:以 Button 为例
shadcn 的核心优势是按需加载,我们以常用的 Button 组件为例,演示如何添加和使用:
-
执行命令:
npx shadcn@latest add button -
CLI 会自动完成以下操作:
- 将 Button 组件源码复制到
src/components/ui/button.tsx - 自动引入
cn工具函数,处理样式合并 - 更新
components.json,记录已添加的 Button 组件
- 将 Button 组件源码复制到
-
在
App.tsx中使用组件:
tsx
import { Button } from '@/components/ui/button';
function App() {
return (
<>
<Button variant='default'>金手指</Button>
<Button variant='destructive'>银手指</Button>
</>
);
}
运行项目后,就能看到两个不同样式的按钮 ------variant='default' 对应默认样式,variant='destructive' 对应危险操作样式(红色),直接开箱即用,无需额外编写样式~

4. 小知识:npx 是什么?
npx 是 Node.js 自带的工具,核心作用是 "临时安装并执行 npm 包中的命令",无需全局或本地预先安装包。比如执行 npx shadcn@latest add button 时,npx 会临时下载 shadcn 包,执行添加组件的命令,完成后自动删除包,不会占用项目依赖资源,特别适合试用工具或执行一次性命令~
七、前端路由配置:接管页面跳转 🚦
前端路由是单页应用(SPA)的核心,负责管理页面跳转和组件渲染。本项目使用 React Router v7 实现路由功能,让所有页面通过路由加载。
1. 目录规划
新建 src/router 目录,所有路由配置都放在这里,在目录下新建 index.tsx,集中管理路由规则。
2. 安装依赖
执行命令:pnpm i react-router-dom(本项目使用 7.13.0 版本)React Router DOM 是专门用于浏览器环境的路由库,提供了路由管理、导航、参数传递等核心功能,是 React 项目实现页面跳转的首选方案。
3. 导入核心路由组件
在 router/index.tsx 中导入以下核心组件:
tsx
import {
BrowserRouter as Router, // 浏览器路由根组件,包裹所有路由配置
Routes, // 路由容器,管理所有 Route 子组件
Route // 单个路由规则,映射路径与组件
} from 'react-router-dom';
BrowserRouter:基于 HTML5 的 History API 实现,URL 格式更美观(如/mine而非/#/mine)Routes:路由规则容器,只能包含 Route 组件,会自动匹配当前 URL 对应的 RouteRoute:定义单个路由,通过path指定 URL 路径,element指定对应的组件
4. 路由懒加载:优化性能 🚀
(1)什么是路由懒加载?
路由懒加载是指 "只有当用户访问某个路由时,才加载对应的组件代码",而不是在项目初始化时一次性加载所有组件。
(2)为什么需要路由懒加载?
如果项目页面较多,一次性加载所有组件会导致初始打包体积过大,页面加载速度变慢,影响用户体验。懒加载能拆分代码包,减小初始加载体积,提升首屏加载速度。
(3)实现路由懒加载
通过 React 内置的 Suspense 组件和 lazy 函数实现:
tsx
import { Suspense, lazy } from 'react'; // 导入懒加载核心工具
// 懒加载页面组件,只有访问对应路由时才加载
const Home = lazy(() => import('@/pages/Home'));
const Mine = lazy(() => import('@/pages/Mine'));
lazy函数:接收一个函数,该函数动态导入组件,返回一个 PromiseSuspense组件:包裹懒加载的路由,当组件正在加载时,显示 fallback 中的占位内容
5. 自定义 Loading 组件:提升用户体验 ⏳
为了让用户在组件加载时不感到无聊,我们可以自定义一个 Loading 动画作为占位:
-
新建
src/components/Loading目录,创建index.tsx和loading.module.css文件 -
编写 Loading 组件(使用模块化 CSS 避免样式污染):
loading.module.css(定义双球旋转动画):
css
.wrapper>div { position: fixed; left: 0; right: 0; top: 0; bottom: 0; margin: auto; width: 60px; height: 60px; opacity: 0.6; border-radius: 50%; background-color: #d44439; animation: loading 1.4s infinite ease-in-out; } .wrapper>div:nth-child(2) { animation-delay: -0.7s; /* 第二个球延迟动画,形成交替效果 */ } @keyframes loading { 0%, 100% { transform: scale(0.0); } 50% { transform: scale(1.0); } }index.tsx(组件结构):
tsx
import styles from './loading.module.css'; export default function Loading() { return ( <div className={styles.wrapper}> <div></div> <div></div> </div> ); } -
在路由配置中使用:
tsx
<Suspense fallback={<Loading />}>
<Routes>
{/* 路由规则 */}
</Routes>
</Suspense>
这样,当组件加载时,页面会显示两个交替缩放的红色小球,让等待过程更友好~
这里只需要观察动画效果,首页与我的 页面实现在这个系列的后面文章我会一一讲解。

八、面试官会问 ❓
- **shadcn/ui 和 Ant Design 的区别是什么?**答:① 引入方式:shadcn 按需下载源码到本地,Ant Design 需全局或按需引入依赖包;② 可定制性:shadcn 支持修改组件源码,Ant Design 定制样式需通过主题配置或覆盖样式;③ 体积:shadcn 只包含所需组件,体积更小;Ant Design 即使按需引入也会有基础依赖体积;④ 技术依赖:shadcn 基于 Tailwind CSS,Ant Design 有自研样式系统。
- **路由懒加载的实现原理是什么?**答:基于 ES6 的
import()动态导入语法,React.lazy接收一个返回 Promise 的函数,当路由被访问时,才执行动态导入加载组件代码。Suspense组件监听 Promise 状态,加载完成前显示 fallback 占位内容,加载成功后渲染组件。 - **为什么要使用模块化 CSS?**答:① 避免样式污染:模块化 CSS 会为类名添加唯一哈希值(如
.loading_wrapper_123),不同组件的同名类不会冲突;② 提高可维护性:样式与组件绑定,便于后续修改和删除,不会影响其他组件;③ 支持 TypeScript 类型提示,减少样式类名拼写错误。 - **Vite 配置路径别名的作用是什么?**答:① 简化导入路径:用
@/components/Button替代../../components/Button,避免层级过深导致的路径混乱;② 提高项目可维护性:如果目录结构调整,只需修改别名配置,无需逐个修改文件中的导入语句。 - **Tailwind CSS 的优势是什么?**答:① 原子化样式:提供大量预定义工具类(如
flex、bg-gray-50),无需编写自定义 CSS;② 响应式设计:内置响应式前缀(如md:flex),轻松实现多端适配;③ 样式复用:通过@apply合并常用样式,减少重复代码;④ 与 shadcn/ui 深度融合,无需额外适配。
九、结语 🌟
至此,博客系统的前端基础框架已经搭建一部分了!我们通过 React + TypeScript + Vite 构建了项目骨架,用 shadcn/ui 和 Tailwind CSS 实现了组件化开发和样式美化,通过 React Router 实现了路由管理、懒加载,为后续功能开发铺平了道路。
接下来,我们将聚焦前端功能开发,实现首页、登录页面等核心界面。如果在搭建过程中遇到问题,欢迎在评论区交流~ 让我们一起朝着 "全栈工程师" 的目标稳步前进!