前端怎么搭建项目基础架构

前端搭建项目基础架构,本质是:在写业务代码之前,把项目的地基打好 。

包括技术选型、目录结构、工程化配置、规范约束、请求封装、路由权限、状态管理、构建部署等。地基打得好,后面开发才快、稳、可维护。

一句话:

选型定方向,目录定边界,配置定规范,封装定效率,部署定上线。

下面以 Vue3 + Vite + TypeScript 为主,讲一套完整的搭建流程。


一、基础架构包含哪些内容

模块 作用
技术选型 框架、UI 库、工具库
项目初始化 Vite 创建、依赖安装
目录结构 分层、分模块
代码规范 ESLint、Prettier、Stylelint、Commitlint
环境变量 开发、测试、生产
请求封装 Axios、拦截器、错误处理
路由与权限 动态路由、菜单、按钮权限
状态管理 Pinia 模块化
组件封装 公共组件、业务组件
工具函数 utils、hooks
样式方案 全局样式、主题、变量
构建优化 分包、压缩、CDN
部署配置 Nginx、Docker、CI/CD
文档与协作 README、Git 规范、分支模型

二、第一步:技术选型

通用后台管理系统

Vue3 + Vite + TypeScript + Vue Router + Pinia + Element Plus + Axios + Sass + ESLint + Prettier

移动端 H5

Vue3 + Vite + TypeScript + Vant + Axios + postcss-px-to-viewport

官网 / 内容站

Nuxt3 + Tailwind CSS + TypeScript

多端小程序

uni-app 或 Taro

React 技术栈

React + Vite + TypeScript + React Router + Zustand/Redux + Ant Design + Axios

选型原则:

  • 团队熟悉
  • 生态成熟
  • 社区活跃
  • 长期维护
  • 适合业务场景

三、第二步:初始化项目

bash 复制代码
npm create vite@latest my-admin -- --template vue-ts
cd my-admin
npm install

安装核心依赖:

bash 复制代码
# 路由、状态、请求、UI
npm install vue-router@4 pinia axios element-plus

# 工具库
npm install @vueuse/core dayjs

# 开发依赖
npm install -D sass eslint prettier eslint-plugin-vue @typescript-eslint/eslint-plugin @typescript-eslint/parser
npm install -D unplugin-auto-import unplugin-vue-components

四、第三步:设计目录结构

text 复制代码
src/
├── api/                # 接口定义
│   ├── user.ts
│   └── order.ts
├── assets/             # 静态资源
│   ├── images/
│   └── icons/
├── components/         # 公共组件
│   ├── BaseTable/
│   └── BaseDialog/
├── composables/        # 组合式函数
│   ├── usePagination.ts
│   └── useRequest.ts
├── directives/         # 自定义指令
│   └── permission.ts
├── layouts/            # 布局
│   ├── DefaultLayout.vue
│   └── BlankLayout.vue
├── router/             # 路由
│   ├── index.ts
│   ├── routes.ts
│   └── guard.ts
├── stores/             # Pinia
│   ├── user.ts
│   ├── permission.ts
│   └── app.ts
├── styles/             # 全局样式
│   ├── index.scss
│   ├── variables.scss
│   └── reset.scss
├── utils/              # 工具函数
│   ├── request.ts
│   ├── storage.ts
│   └── date.ts
├── views/              # 页面
│   ├── login/
│   ├── dashboard/
│   └── system/
├── App.vue
├── main.ts
└── env.d.ts

原则:

  • 按职责分层
  • 按业务分模块
  • 公共和业务分离
  • 页面和组件分离

五、第四步:配置入口和核心文件

1. main.ts

ts 复制代码
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
import router from './router'
import './styles/index.scss'
import { setupDirectives } from './directives'

const app = createApp(App)

app.use(createPinia())
app.use(router)
app.use(ElementPlus)

setupDirectives(app)

app.mount('#app')

2. App.vue

vue 复制代码
<template>
  <router-view />
</template>

3. vite.config.ts

ts 复制代码
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { fileURLToPath, URL } from 'node:url'

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd())

  return {
    plugins: [
      vue(),
      AutoImport({ resolvers: [ElementPlusResolver()] }),
      Components({ resolvers: [ElementPlusResolver()] })
    ],
    resolve: {
      alias: {
        '@': fileURLToPath(new URL('./src', import.meta.url))
      }
    },
    server: {
      port: 5173,
      proxy: {
        '/api': {
          target: env.VITE_API_TARGET,
          changeOrigin: true
        }
      }
    },
    build: {
      rollupOptions: {
        output: {
          manualChunks: {
            vue: ['vue', 'vue-router', 'pinia'],
            element: ['element-plus']
          }
        }
      }
    }
  }
})

六、第五步:环境变量

根目录创建:

.env.development

env 复制代码
VITE_API_BASE_URL=/api
VITE_API_TARGET=http://localhost:3000

.env.production

env 复制代码
VITE_API_BASE_URL=https://api.example.com

使用:

ts 复制代码
import.meta.env.VITE_API_BASE_URL

七、第六步:请求封装

src/utils/request.ts

ts 复制代码
import axios from 'axios'
import { storage } from './storage'
import { ElMessage } from 'element-plus'

const request = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 10000
})

request.interceptors.request.use(config => {
  const token = storage.get<string>('token')
  if (token) config.headers.Authorization = `Bearer ${token}`
  return config
})

request.interceptors.response.use(
  res => {
    const { code, message, data } = res.data
    if (code === 0) return data
    ElMessage.error(message || '请求失败')
    return Promise.reject(new Error(message))
  },
  err => {
    ElMessage.error(err.message || '网络错误')
    return Promise.reject(err)
  }
)

export default request

src/api/user.ts

ts 复制代码
import request from '@/utils/request'

export const login = (data: { username: string; password: string }) =>
  request.post('/login', data)

export const getUserInfo = () => request.get('/user/info')

八、第七步:路由与权限

src/router/index.ts

ts 复制代码
import { createRouter, createWebHistory } from 'vue-router'
import { constantRoutes } from './routes'

const router = createRouter({
  history: createWebHistory(),
  routes: constantRoutes
})

export default router

src/router/guard.ts

ts 复制代码
import router from './index'
import { useUserStore } from '@/stores/user'

router.beforeEach(async (to) => {
  const userStore = useUserStore()

  if (to.path === '/login') return true

  if (!userStore.token) {
    return { path: '/login', query: { redirect: to.fullPath } }
  }

  if (!userStore.userInfo) {
    await userStore.fetchUserInfo()
    const routes = await userStore.generateRoutes()
    routes.forEach(r => router.addRoute(r))
    return { ...to, replace: true }
  }

  return true
})

权限三个层面:

  • 菜单权限:动态生成侧边栏
  • 按钮权限:自定义指令 v-permission
  • 接口权限:后端校验

src/directives/permission.ts

ts 复制代码
import type { App } from 'vue'
import { useUserStore } from '@/stores/user'

export function setupDirectives(app: App) {
  app.directive('permission', {
    mounted(el, binding) {
      const userStore = useUserStore()
      const required = binding.value
      const has = Array.isArray(required)
        ? required.some(p => userStore.permissions.includes(p))
        : userStore.permissions.includes(required)
      if (!has) el.parentNode?.removeChild(el)
    }
  })
}

九、第八步:状态管理 Pinia

src/stores/user.ts

ts 复制代码
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { login, getUserInfo } from '@/api/user'
import { storage } from '@/utils/storage'

export const useUserStore = defineStore('user', () => {
  const token = ref(storage.get<string>('token') || '')
  const userInfo = ref<any>(null)
  const permissions = ref<string[]>([])

  async function doLogin(data: { username: string; password: string }) {
    const res = await login(data)
    token.value = res.token
    storage.set('token', res.token)
  }

  async function fetchUserInfo() {
    const res = await getUserInfo()
    userInfo.value = res
    permissions.value = res.permissions
  }

  function logout() {
    token.value = ''
    userInfo.value = null
    permissions.value = []
    storage.remove('token')
  }

  return { token, userInfo, permissions, doLogin, fetchUserInfo, logout }
})

十、第九步:代码规范

ESLint

.eslintrc.cjs

js 复制代码
module.exports = {
  root: true,
  env: { browser: true, es2021: true, node: true },
  extends: [
    'eslint:recommended',
    'plugin:vue/vue3-recommended',
    'plugin:@typescript-eslint/recommended'
  ],
  parser: 'vue-eslint-parser',
  parserOptions: {
    parser: '@typescript-eslint/parser',
    ecmaVersion: 'latest',
    sourceType: 'module'
  },
  rules: {
    'vue/multi-word-component-names': 'off'
  }
}

Prettier

.prettierrc

json 复制代码
{
  "semi": false,
  "singleQuote": true,
  "printWidth": 100,
  "trailingComma": "none"
}

Commitlint + Husky

bash 复制代码
npm install -D husky lint-staged @commitlint/cli @commitlint/config-conventional
npx husky init

commit-msg:

bash 复制代码
npx --no -- commitlint --edit $1

pre-commit:

bash 复制代码
npx lint-staged

package.json:

json 复制代码
{
  "lint-staged": {
    "*.{js,ts,vue}": ["eslint --fix", "prettier --write"],
    "*.{scss,css}": ["stylelint --fix", "prettier --write"]
  }
}

提交规范:

  • feat:新功能
  • fix:修复
  • docs:文档
  • style:格式
  • refactor:重构
  • perf:性能
  • test:测试
  • chore:构建/工具

十一、第十步:样式方案

src/styles/variables.scss

scss 复制代码
$primary-color: #409eff;
$header-height: 60px;
$sidebar-width: 220px;

src/styles/index.scss

scss 复制代码
@use './reset.scss';
@use './variables.scss' as *;

:root {
  --primary-color: #{$primary-color};
}

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

Vite 全局注入:

ts 复制代码
css: {
  preprocessorOptions: {
    scss: {
      additionalData: `@use "@/styles/variables.scss" as *;`
    }
  }
}

十二、第十一步:构建与部署

构建:

bash 复制代码
npm run build

Nginx:

nginx 复制代码
server {
  listen 80;
  root /var/www/my-admin/dist;
  index index.html;

  location / {
    try_files $uri $uri/ /index.html;
  }

  location /api/ {
    proxy_pass http://127.0.0.1:3000;
  }
}

Docker:

dockerfile 复制代码
FROM node:20-alpine AS build
WORKDIR /app
COPY . .
RUN npm install && npm run build

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf

CI/CD:

  • GitHub Actions
  • GitLab CI
  • Jenkins

十三、可选增强

  • Mock:vite-plugin-mock、MSW
  • 国际化:vue-i18n
  • 主题切换:CSS 变量 + Pinia
  • 错误监控:Sentry
  • 埋点:自定义指令 + 上报
  • 权限指令:v-permission
  • 水印:Canvas 生成
  • 大屏适配:scale 方案
  • 微前端:qiankun、micro-app
  • Monorepo:pnpm workspace + Turborepo

十四、搭建顺序建议

  1. 初始化 Vite 项目
  2. 配置别名、环境变量
  3. 安装 Router、Pinia、UI 库
  4. 设计目录结构
  5. 封装 request
  6. 配置路由和守卫
  7. 配置 Pinia 模块
  8. 配置 ESLint、Prettier、Husky
  9. 配置全局样式
  10. 封装公共组件和工具
  11. 配置构建优化
  12. 配置部署

十五、常见坑

  • 一开始就上微前端、Monorepo,过度设计
  • 目录混乱,业务和公共混在一起
  • 不配 ESLint,代码风格失控
  • 请求不封装,每处都写 axios
  • 权限没设计好,后期返工
  • 环境变量写死,部署要改代码
  • 不配 CI/CD,每次手动部署
  • 不做分包,首屏加载慢

十六、总结

前端项目基础架构的核心:

选型合理、目录清晰、规范统一、封装到位、部署顺畅。

一个合格的基础架构应该:

  • 新人能快速上手
  • 业务开发不用关心底层配置
  • 代码风格统一
  • 权限、请求、路由开箱即用
  • 构建部署自动化
  • 易扩展、易维护

先用成熟模板(如 Geeker-Admin、Vue Vben Admin)快速起步,再根据团队和业务逐步调整,是最高效的方式。

如果你告诉我具体项目类型(后台、H5、小程序),我可以给你一份更精确的基础架构清单和代码模板。

相关推荐
lichenyang4531 小时前
Promise 基础与进阶:状态规则、链式错误处理和异步执行顺序
前端
Amos_Web1 小时前
Rspack 源码解析(二十五):CssParserAndGenerator 如何把 CSS 变成可 Tree Shaking 的模块
前端·rust·前端框架
wespaul1 小时前
VeapAI 自然语言操作实战|第 06 篇:AiConsole 前端运行时——一个 Hub,八个注册表
前端·人工智能·milvus
龙亘川2 小时前
健康服务规范化背后,数字化如何 “辅助赋能“
大数据·前端·人工智能·智慧城市·数据可视化
data analyse 4562 小时前
SourceMap 上传版本与报错版本对不上?版本校验与错误还原设计
大数据·前端·人工智能·数据分析
前端双越老师2 小时前
程序员 1v1 访谈系列第三期:先不要想在工作中有突破
前端·ai编程·全栈
小羊没烦恼!2 小时前
浅谈SQL Server中的事务日志(二)----事务日志在修改数据时的角色
前端·数据库·后端·python·web安全·oracle
myaifas2 小时前
新人的第一个任务该怎么选
前端·产品经理
怕浪猫2 小时前
前端转全栈最低成本的技术栈选择
前端·javascript·面试