当前位置:首页 > 技术 > 正文内容

构建基于Vue3与Vite的企业级前端工程化方案

访客 技术 2026年7月3日 1

初始化与工程配置

在现代化前端开发中,Vite 凭借其极速的冷启动和热更新能力,已成为 Vue3 项目的首选构建工具。以下是基于最新生态搭建企业级应用的基础步骤。

1. 项目初始化

确保本地 Node.js 版本在 18.0 或以上,使用 pnpm 进行包管理以获得更好的磁盘利用率和安装速度。

# 检查 Node 版本
node -v

# 使用 pnpm 创建 Vite + Vue3 模板
pnpm create vite enterprise-admin --template vue

cd enterprise-admin
pnpm install
pnpm dev

2. 核心目录规划

合理的目录结构是维持大型项目可维护性的关键。推荐采用按功能模块划分的结构:

src/
├── services/      # 网络请求与接口定义
├── static/        # 不变化的静态资源
├── shared/        # 跨模块共享的UI组件
├── hooks/         # 自定义组合式函数 (Composables)
├── layouts/       # 页面骨架与布局
├── routing/       # 路由表与守卫配置
├── store/         # 全局状态管理 (Pinia)
├── helpers/       # 纯函数与工具类
├── pages/         # 视图级页面组件
├── App.vue
└── main.ts

3. 生态依赖安装

引入路由、状态管理、UI 组件库以及自动化导入插件,减少样板代码。

pnpm add vue-router@4 pinia axios element-plus @element-plus/icons-vue
pnpm add -D unplugin-auto-import unplugin-vue-components sass

核心模块实现

1. 路由系统配置

利用 Vue Router 4 构建支持嵌套布局和动态加载的路由表。

// routing/index.js
import { createRouter, createWebHistory } from 'vue-router'

const appRoutes = [
  {
    path: '/dashboard',
    component: () => import('@/layouts/AdminLayout.vue'),
    redirect: '/dashboard/home',
    children: [
      { 
        path: 'home', 
        name: 'DashboardHome', 
        component: () => import('@/pages/DashboardHome.vue'),
        meta: { title: '控制台' }
      },
      { 
        path: 'settings', 
        name: 'SystemSettings', 
        component: () => import('@/pages/SystemSettings.vue'),
        meta: { title: '系统设置' }
      },
    ]
  },
  {
    path: '/auth/login',
    name: 'UserLogin',
    component: () => import('@/pages/UserLogin.vue')
  },
  {
    path: '/:pathMatch(.*)*',
    name: 'NotFound',
    component: () => import('@/pages/Error404.vue')
  }
]

const routerInstance = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: appRoutes,
  scrollBehavior: () => ({ left: 0, top: 0 })
})

export default routerInstance

2. 全局状态管理 (Pinia)

使用 Setup Store 语法定义用户鉴权状态,提供更灵活的响应式控制。

// store/auth.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useAuthStore = defineStore('authModule', () => {
  const accessToken = ref(sessionStorage.getItem('access_token') || '')
  const userProfile = ref(null)

  const isAuthenticated = computed(() => accessToken.value.length > 0)

  async function performLogin(payload) {
    // 模拟 API 调用获取凭证
    const mockToken = 'eyJhbGciOiJIUzI1NiIsInR5...'
    accessToken.value = mockToken
    sessionStorage.setItem('access_token', mockToken)
  }

  function clearSession() {
    accessToken.value = ''
    userProfile.value = null
    sessionStorage.removeItem('access_token')
  }

  return { accessToken, userProfile, isAuthenticated, performLogin, clearSession }
})

3. 网络请求层封装

基于 Axios 封装统一的 HTTP 客户端,处理鉴权头注入与全局异常拦截。

// services/httpClient.js
import axios from 'axios'
import { useAuthStore } from '@/store/auth'
import routerInstance from '@/routing'

const httpClient = axios.create({
  baseURL: import.meta.env.VITE_APP_API_URL,
  timeout: 15000,
  headers: { 'Content-Type': 'application/json' }
})

httpClient.interceptors.request.use(
  (reqConfig) => {
    const authStore = useAuthStore()
    if (authStore.accessToken) {
      reqConfig.headers['X-Access-Token'] = authStore.accessToken
    }
    return reqConfig
  },
  (err) => Promise.reject(err)
)

httpClient.interceptors.response.use(
  (res) => res.data.payload,
  (err) => {
    const status = err.response?.status
    if (status === 401 || status === 403) {
      const authStore = useAuthStore()
      authStore.clearSession()
      routerInstance.push({ name: 'UserLogin' })
    }
    return Promise.reject(err)
  }
)

export default httpClient

4. 组合式 API 与组件开发

<script setup> 中利用 Composition API 构建高内聚的业务组件。

<!-- pages/TaskManager.vue -->
<script setup>
import { ref, watchEffect } from 'vue'

const taskList = ref([
  { id: 1, title: '审查代码', done: false },
  { id: 2, title: '编写单元测试', done: true }
])
const newTaskTitle = ref('')

const pendingCount = ref(0)

watchEffect(() => {
  pendingCount.value = taskList.value.filter(t => !t.done).length
})

function addTask() {
  if (!newTaskTitle.value.trim()) return
  taskList.value.push({
    id: Date.now(),
    title: newTaskTitle.value,
    done: false
  })
  newTaskTitle.value = ''
}

function toggleTaskStatus(taskId) {
  const target = taskList.value.find(t => t.id === taskId)
  if (target) target.done = !target.done
}
</script>

<template>
  <div class="task-container">
    <h3>待办事项 (未完成: {{ pendingCount }})</h3>
    <input v-model="newTaskTitle" @keyup.enter="addTask" placeholder="输入新任务..." />
    <ul>
      <li v-for="task in taskList" :key="task.id" @click="toggleTaskStatus(task.id)">
        <span :class="{ completed: task.done }">{{ task.title }}</span>
      </li>
    </ul>
  </div>
</template>

<style scoped>
.completed {
  text-decoration: line-through;
  color: #999;
}
</style>

5. 基础 UI 组件二次封装

对 Element Plus 的对话框组件进行业务级封装,统一交互规范。

<!-- shared/BaseDialog.vue -->
<script setup>
const props = defineProps({
  visible: { type: Boolean, required: true },
  title: { type: String, default: '提示' },
  width: { type: String, default: '500px' },
  showFooter: { type: Boolean, default: true }
})

const emit = defineEmits(['update:visible', 'confirm', 'cancel'])

function handleClose() {
  emit('update:visible', false)
  emit('cancel')
}

function handleConfirm() {
  emit('confirm')
}
</script>

<template>
  <el-dialog
    :model-value="visible"
    :title="title"
    :width="width"
    @close="handleClose"
    destroy-on-close
  >
    <div class="dialog-body">
      <slot />
    </div>
    <template #footer v-if="showFooter">
      <el-button @click="handleClose">取消</el-button>
      <el-button type="primary" @click="handleConfirm">确定</el-button>
    </template>
  </el-dialog>
</template>

工程化与性能调优策略

  • 按需加载与代码分割:路由层面全面采用动态 import(),结合 Vite 的 Rollup 打包机制,自动将不同路由拆分为独立的 Chunk。
  • 组件异步化:对于非首屏渲染的重型组件(如富文本编辑器、图表库),使用 defineAsyncComponent 延迟加载,降低首屏 JS 体积。
  • 视图缓存机制:在 Layout 层结合 <KeepAlive> 与路由 meta.keepAlive 属性,缓存频繁切换的列表页状态,避免重复请求。
  • 长列表渲染优化:面对万级数据量的表格或下拉框,引入 vue-virtual-scroller 或 Element Plus 的虚拟化表格,仅渲染可视区域 DOM。
  • 静态资源优化:利用 vite-plugin-compression 开启 Gzip/Brotli 压缩,并将不变的第三方库配置 build.rollupOptions.output.manualChunks 进行长效缓存。
标签: Vue3vite

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。