西部数据的存储产品线非常庞杂,从蓝盘、黑盘这类消费级机械硬盘,到企业级 Ultrastar 系列,再到 My Cloud 系列 NAS 设备,每种产品都有容量、接口类型、缓存大小、转速、质保年限等几十个属性字段。要做这样一个产品的展示与管理系统,如果前端项目没有一个清晰的工程化架构,随着产品数据不断膨胀,代码很快就会变成一团乱麻。Vue 3 配合 Vite 提供了非常好的工程化基础,下面结合一个西部数据存储产品管理系统的搭建过程,完整梳理一下工程化落地的关键环节。

项目初始化与目录结构设计
工程化的第一步是把项目骨架搭好。使用 Vite 创建 Vue 3 项目非常简单,执行 npm create vite@latest wd-storage-admin -- --template vue-ts 即可生成一个基于 TypeScript 的模板。相比 Vue 2 时代的 webpack 配置,Vite 开发阶段的冷启动速度提升明显,尤其是产品管理系统这种页面数量多的项目,改一行代码秒级热更新的体验会好很多。
目录结构建议按照业务职责划分,而不是简单按文件类型堆放。推荐的结构如下:
wd-storage-admin/ ├── src/ │ ├── api/ # 接口模块,按业务拆分 │ │ └── product.ts │ ├── assets/ │ ├── components/ # 通用组件,如产品规格表、容量筛选器 │ ├── composables/ # 组合式函数,如 useProductFilter │ ├── router/ │ ├── stores/ # Pinia 状态模块 │ ├── styles/ │ ├── types/ # 产品相关的 TS 类型定义 │ ├── utils/ │ ├── views/ │ │ ├── product/ │ │ └── dashboard/ │ ├── App.vue │ └── main.ts ├── .env.development ├── .env.production └── vite.config.ts
这种结构的核心思想是让同一业务功能的代码尽量靠近。比如产品筛选的逻辑抽成 composables/useProductFilter.ts,产品列表页和产品对比页都可以复用,避免了选项式 API 时代逻辑分散在 data、methods、computed 里难以复用的问题。这也是组合式 API 在工程化层面带来的最大收益:逻辑关注点聚合,按功能而非选项组织代码。
类型定义与接口层封装
存储产品的属性字段多且格式不统一,机械硬盘有转速和盘片尺寸,SSD 有闪存类型和写入寿命,NAS 有盘位数量和 RAID 支持。如果统一塞进一个松散的对象里,后期维护成本极高。正确的做法是在 types/product.ts 中定义清晰的类型体系:
// 产品基础类型
export interface BaseProduct {
id: string;
model: string; // 型号,如 WD40EFRX
brand: string;
category: ProductCategory;
capacityGB: number;
price: number;
releaseDate: string;
}
// 机械硬盘特有属性
export interface HDDProduct extends BaseProduct {
category: 'hdd';
rpm: number; // 转速,5400 或 7200
cacheMB: number; // 缓存大小
formFactor: '3.5' | '2.5';
}
// SSD 特有属性
export interface SSDProduct extends BaseProduct {
category: 'ssd';
nandType: 'QLC' | 'TLC' | 'MLC';
interfaceType: 'SATA' | 'NVMe PCIe 3.0' | 'NVMe PCIe 4.0';
tbw: number; // 总写入字节数
}
export type Product = HDDProduct | SSDProduct;
用可辨识联合类型之后,TypeScript 能根据 category 字段自动收窄类型,访问 SSD 的 tbw 属性时如果对象实际是 HDD,编译阶段就会报错。这种类型约束在多人协作的项目里价值巨大,能拦住大量低级错误。
接口层建议统一封装请求实例和错误处理,避免每个页面各自写 fetch 逻辑:
import axios from 'axios';
import type { Product } from '@/types/product';
const request = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 10000,
});
// 响应拦截器统一处理业务码
request.interceptors.response.use((response) => {
const { code, data, message } = response.data;
if (code !== 0) {
return Promise.reject(new Error(message));
}
return data;
});
export function fetchProducts(params: ProductQuery) {
return request.get<Product[], Product[]>('/products', { params });
}
注意这里用了 import.meta.env 读取环境变量,这是 Vite 的标准方式,取代了 webpack 时代的 process.env。开发环境连测试服务器,生产环境连正式接口,只需要维护 .env.development 和 .env.production 两个文件即可。
状态管理与按需引入的性能优化
状态管理方面,Vue 3 官方推荐 Pinia。以购物车或者产品对比列表为例,定义一个 store 非常直观:
import { defineStore } from 'pinia';
export const useCompareStore = defineStore('compare', {
state: () => ({
items: [] as Product[],
maxCount: 4,
}),
actions: {
toggle(product: Product) {
const index = this.items.findIndex((i) => i.id === product.id);
if (index > -1) {
this.items.splice(index, 1);
} else if (this.items.length < this.maxCount) {
this.items.push(product);
}
},
},
});
性能优化是工程化绕不开的话题,产品管理系统常见的优化点有三个。第一是组件库按需引入,以 Element Plus 为例,配合 unplugin-vue-components 插件可以做到模板里写了什么组件就打包什么组件,体积能从完整引入的一兆多压缩到几百 KB。第二是路由懒加载,把产品详情页、数据看板等页面用 () => import('@/views/product/Detail.vue') 的方式动态导入,首屏只加载登录页和列表页的代码。第三是产品大列表的虚拟滚动,产品目录可能有几千条记录,用 vue-virtual-scroller 之类的方案只渲染可视区域内的行,配合分页接口,列表再长也不会卡顿。
最后再提一点构建层面的配置。在 vite.config.ts 中开启 build.rollupOptions.output.manualChunks,把 vue、axios、echarts 这类稳定的第三方依赖单独拆包,利用浏览器缓存避免每次发版都让用户重新下载全部资源。对于产品官网这种访问量大的站点,这一步优化带来的带宽节省非常可观。工程化没有银弹,但把这些环节一个个做扎实,项目就能在业务扩张时保持健康的状态。