在人力资源与薪酬管理领域,Namely 这类平台需要处理员工档案、薪资核算、绩效与排班等高度耦合又各自演进的业务。Vue 3 提供的组合式 API 与更灵活的工程化能力,让前端团队可以把复杂规则拆成可测试的单元,并通过统一的构建与规范降低协作摩擦。

模块化目录与领域驱动拆分
Namely 的业务天然按领域划分,例如组织管理、薪资计算、福利模块。在 Vue 3 工程化实践中,我们通常采用领域驱动的结构,将 src/modules 下的每个文件夹视为一个独立域,内部包含视图、组合式函数、类型定义与单元测试。这样当薪资税法变更时,开发者只需聚焦 payroll 域,不会意外破坏员工档案模块。
除了业务模块,工程化还要求清晰的共享层。我们把通用的表单校验、金额格式化、权限指令放到 src/shared 中,并以 TypeScript 的 index.ts 统一导出。通过 ESLint 与 Prettier 强制目录依赖方向,禁止业务模块反向依赖具体页面,从而保证架构边界。下面是一段组织树组合式函数的示例:
import { ref } from 'vue';
import type { DeptNode } from '../types';
// 加载部门树并处理扁平数据
export function useDeptTree() {
const tree = ref<DeptNode[]>([]);
const loading = ref(false);
async function load(pid: string) {
loading.value = true;
try {
const res = await fetch('/api/dept?pid=' + pid);
tree.value = await res.json();
} finally {
loading.value = false;
}
}
return { tree, loading, load };
}
这种写法把数据获取与组件解耦,在 Namely 的 HR 后台中,组织树既出现在员工调动页,也出现在成本中心配置页,复用组合式函数避免了逻辑复制。同时,由于函数返回的是标准响应式对象,测试时可直接调用并断言,不需要挂载组件。
基于 Vite 的构建优化与依赖治理
薪资平台往往引入大量报表组件与第三方计算库,传统 Webpack 构建在冷启动和增量编译上容易变慢。Vue 3 配合 Vite 利用原生 ES 模块与预构建,使 Namely 本地开发启动时间从十秒级降到两秒以内。我们还通过 vite.config.ts 的 manualChunks 将薪资引擎、图表库拆分为独立 chunk,避免单次发布体积过大。
在工程化层面,依赖治理同样关键。HR 系统对版本稳定性要求高,我们使用 pnpm 的严格模式锁定传递依赖,并编写脚本扫描 package.json 中带有 beta 标记的包。针对 Namely 常见的多语言薪资规则,我们把地区配置以 JSON 形式动态导入,结合 Vite 的 glob 导入能力自动注册,减少手工维护路由的成本。
// vite 自动收集薪资地区配置
const regionFiles = import.meta.glob('../regions/*.json');
const regions = {};
for (const path in regionFiles) {
const name = path.split('/').pop().replace('.json', '');
regions[name] = regionFiles[path];
}
上述方式让新增一个州或国家的薪资逻辑时,只需放置文件即可被系统识别。构建时 Vite 会按需打包,不会把所有地区规则塞进首屏。对于拥有上百薪资模板的 Namely 来说,这种工程化手段显著降低了发布风险。
状态治理与权限细粒度控制
HR 与薪资数据敏感,Namely 需要在前端控制字段级权限。我们利用 Pinia 建立 auth 与 salary 两个 store,前者保存当前用户可看的部门与字段白名单,后者缓存薪资计算结果但读取时经过权限拦截。Vue 3 的 computed 与 watch 让这种派生状态非常自然。
在工程化规范中,我们禁止组件直接修改 salary store 的原始数据,所有变更走 actions 并打点日志。借助自定义指令 v-role,模板中可声明式隐藏按钮,例如只有薪酬管理员可见的调薪入口。下面示例展示权限指令的简化实现:
import { Directive } from 'vue';
// 根据角色隐藏元素
export const roleDirective: Directive = {
mounted(el, binding) {
const allowed = (window as any).__roles__.includes(binding.value);
if (!allowed) el.style.display = 'none';
}
};
通过将权限判断收敛到指令与 store,Namely 的前端代码避免了在业务组件里写大量 if 判断。当审计要求变更时,只需调整 auth store 的映射逻辑,不用逐个页面改动。配合 Vue 3 的 <script setup> 语法,单文件组件的可读性也进一步提升,新成员能快速理解平台工程化全貌。