vebai-loom
| Install | |
|---|---|
npm install vebai-loom |
|
| Latest Version: | 2.0.0 |
| Vue: | 3 |
| License: | MIT |
| Last Updated: | Oct 12, 2026 |
| Links: | Gitee · npm |
vebai-loom
vebai-loom 是一套面向 Vue 3 中后台的可复用前端内核,把中后台项目里最重复、也最容易写散的部分收敛成四块能力:http、permission、handler、dynamic-form。
它要解决的不是「少写几行代码」,而是三类反复出现的问题:接口请求的重复处理与登录态联动、权限与动态路由散落在各处、列表和表单逻辑在业务组件里越堆越厚。内核把这些逻辑收到统一入口,并且不绑定任何 UI 组件库:它只产出数据和描述符,渲染交给使用方自己的组件。
http:基于 axios 的请求内核,内建防重复请求、短期缓存、上传下载、token 刷新与统一错误处理。permission:登录态校验、动态菜单与路由生成、路由守卫,支持role/operate/menu/menuAndOperate四种权限模式。handler:列表查询内核,覆盖分页、排序、多选、增删改、导出、筛选与路由 query 同步。dynamic-form:框架无关的表单描述符引擎,把 schema 编译成与渲染无关的描述符,支持校验规则、字段联动与描述符缓存。
内核不直接依赖具体实现,而是通过 Notifier、ConfirmService、SessionAdapter、Logger、Translator、ControlRegistry、TableFilterAdapter、RouteAdapter 等注入接口访问外部能力:http / permission / handler 保留 Vue 3 + vue-router,dynamic-form 完全框架无关。
变更明细见 CHANGELOG.md。
目录
- 设计原则
- 目录结构
- 依赖要求
- 安装与引入
- 快速接入
- 注入接口实现
- HTTP 请求
- Permission 权限
- Handler 列表
- DynamicForm 动态表单
- 表单承载(FormHost)
- 编写自己的适配器
- 常见注意事项
- 速查表
- 脚本与构建
- 两套哲学的取舍
设计原则
-
零 UI 组件库依赖:
src/内不出现ant-design-vue/element-plus等 UI 组件库,package.json也不声明它们。所有渲染都由使用方实现。 -
注入接口:内核不直接依赖具体实现,而是通过接口访问外部能力:
接口 作用 Notifier消息提示(success / error / warning / info) ConfirmService确认框、结果弹窗 SessionAdapter登录态:token、authType、用户信息、菜单、路由 Logger/Translator日志与文案 ControlRegistry动态表单控件注册表(type → 组件) TableFilterAdapter表格筛选下拉渲染 RouteAdapter路由读写(让 handler 可脱离组件运行) -
分层:
http/permission/handler保留 Vue3 + vue-router。dynamic-form为纯 TS 引擎,只输出描述符。
目录结构
src/
setup.ts 统一注入入口(setupVbCore / resetVbCore)
core-deps.ts 应用级依赖容器(CoreDeps)
shared/ 通用工具、本地存储、文案表(business.ts 为业务辅助入口)
interfaces/ 注入接口(notifier / confirm / session / logger / translator / control / table-filter / route)
types/ 框架无关类型
http/ 请求内核
permission/ 权限内核(permission.ts + routes.ts 纯函数)
handler/ 列表内核
dynamic-form/ 表单描述符引擎(descriptor / engine / rules)
route/ 路由适配器(vue / memory)
test/ 纯函数单测(node:test)
scripts/ 测试与构建辅助脚本
examples/ antd / element-plus 适配器写法示例(不参与构建、不导出、不声明依赖)
dist/ 构建产物(npm 发布内容,仓库中不跟踪)
依赖要求
| 入口 | 需要安装 |
|---|---|
vebai-loom/dynamic-form |
axios、ts-md5 |
vebai-loom/http |
axios、ts-md5 |
vebai-loom/permission |
axios、ts-md5、vue、vue-router |
vebai-loom/handler |
axios、ts-md5、vue、vue-router |
vue / vue-router 为 optional peer:只用 dynamic-form 时不会被强制安装;使用 permission / handler 时请自行安装。
安装与引入
npm install vebai-loom
使用 permission / handler 时还需要:
npm install vue vue-router
包入口指向构建产物 dist,并提供以下子路径:
vebai-loom/http vebai-loom/permission vebai-loom/handler vebai-loom/dynamic-form
vebai-loom/interfaces vebai-loom/route vebai-loom/shared vebai-loom/shared/business
import { DynamicForm, createHttp, Handler } from 'vebai-loom';
import { createControlRegistry } from 'vebai-loom/interfaces';
import { createVueRouteAdapter } from 'vebai-loom/route';
本地开发也可以直接依赖该包:
{
"dependencies": {
"vebai-loom": "file:../vebai-loom"
}
}
快速接入
推荐用统一入口 setupVbCore() 注入一次,它会登记应用级依赖、配置 http、注册 handler 默认依赖,并可顺带创建 permission。
import { setupVbCore } from 'vebai-loom';
// 项目启动时注入一次
const core = setupVbCore({
deps: {
session: mySessionAdapter,
notifier: myNotifier,
confirm: myConfirm, // handler 需要
tableFilter: myTableFilter, // handler 需要
logger: myLogger, // 可选,默认 console
translator: myTranslator // 可选,默认内置中文
},
http: {
baseURL: import.meta.env.VITE_BASE_URL,
timeout: 30000,
repeatRequestTime: 1000,
cacheSize: 200,
logout: () => core.permission?.logout() // 可选
},
permission: permissionConfig, // 可选:传入即创建(内部会立即请求登录状态)
controls: myControlRegistry // 可选:供动态表单渲染器读取
});
// 挂到应用
app.use(core.permission!.router);
之后各处直接取用,不再重复传全局依赖:
import { createHttp, Handler, createVueRouteAdapter } from 'vebai-loom';
const http = createHttp(); // 已由 setupVbCore 配好
// 列表页 setup:只传组件级的 route(不传则走 useRoute/useRouter)
const handler = Handler.build(
{ queryApi: { url: '/api/user/page', method: 'get' }, page: true },
{ route: createVueRouteAdapter() }
);
创建权限后:
- 已登录 → 拉取菜单、生成路由、跳到目标页或首页。
- 未登录 → 跳
loginPath。
多后台 / 多环境 / 单测仍可用独立实例:
import { createHttpClient, createRequestConfig } from 'vebai-loom';
const other = createHttpClient(createRequestConfig({ session, notifier, name: 'other', baseURL: '/other' }));
注入接口实现
Notifier
import type { Notifier } from 'vebai-loom/interfaces';
export const myNotifier: Notifier = {
success: (msg) => { /* toast success */ },
error: (msg) => { /* toast error */ },
warning: (msg) => { /* toast warning */ },
info: (msg) => { /* toast info */ }
};
包内提供 silentNotifier(静默实现)用于测试。
ConfirmService
import type { ConfirmService } from 'vebai-loom/interfaces';
export const myConfirm: ConfirmService = {
confirm: async (option) => {
// option: { title?, content?, confirmText?, cancelText?, width? }
return true; // 用户确认返回 true
},
alert: async (option) => { /* 仅提示,无取消 */ }
};
包内提供 passthroughConfirmService(confirm 恒为 true)作占位。
SessionAdapter
import type { SessionAdapter } from 'vebai-loom/interfaces';
export const mySession: SessionAdapter = {
getToken: () => token,
setToken: (t) => { token = t; },
getAuthType: () => authType,
setAuthType: (v) => { authType = v; },
getInfo: () => userInfo,
setInfo: (v) => { userInfo = v; },
getRoutes: () => routes,
setRoutes: (v) => { routes = v; },
getMenus: () => menus,
setMenus: (v) => { menus = v; },
destroy: () => { /* 清空登录态 */ },
setCurrRoute: (route) => { /* 可选:记录当前路由 */ }
};
ControlRegistry
import { createControlRegistry } from 'vebai-loom/interfaces';
export const controls = createControlRegistry({
input: { component: MyInput },
select: { component: MySelect, props: { clearable: true } }
});
TableFilterAdapter
枚举标签组件(Tag)
BizEnumHelper 把枚举值渲染成状态标签;标签组件由使用方注入,默认是纯 span。
import { BizEnumHelper } from 'vebai-loom';
// ant-design-vue 的 Tag、Element Plus 的 ElTag,或自有组件
BizEnumHelper.setTag(Tag);
// 也可以放进统一入口,启动时注册一次
setupVbCore({ deps: { /* ... */ }, tag: Tag });
getTag(value) 会把枚举项里除 label / value 之外的字段(如 color、disabled)作为 props 传给标签组件;getTag(value, false) 只输出纯文本。旧写法 setTagNode(createVNode(Tag)) 仍可用,内部取 VNode 的组件类型。
import type { TableFilterAdapter } from 'vebai-loom/interfaces';
export const myTableFilter: TableFilterAdapter = {
buildFilter(kind, ctx) {
// kind: 'text' | 'number' | 'date'
// ctx: { handler, column?, name? }
return { filterIcon: () => null, filterDropdown: (opt) => null };
},
buildSelectFilter(filters, ctx, option, multiple, ignoreType) {
return { /* 同上,返回表格框架能识别的筛选属性 */ };
}
};
包内提供 noopTableFilterAdapter 作空实现。
Logger
import type { Logger } from 'vebai-loom/interfaces';
export const myLogger: Logger = {
log: (...args) => console.log(...args),
warn: (...args) => console.warn(...args),
error: (...args) => console.error(...args)
};
包内提供 consoleLogger(默认)与 silentLogger;http / permission 可通过 logger 注入。
Translator
import type { Translator } from 'vebai-loom/interfaces';
export const myTranslator: Translator = {
t: (key, params) => i18n.t(key, params)
};
包内提供 createTranslator(catalog) 与内置中文表 zhCNMessages(默认 defaultTranslator)。http / permission 可通过 translator 注入;buildFormItemRules(title, type, rules, translator?) 也支持。
RouteAdapter
import type { RouteAdapter } from 'vebai-loom/interfaces';
const adapter: RouteAdapter = {
getQuery: () => ({}),
pushQuery: (query) => {},
replaceQuery: (query) => {}, // 可选;提供时优先使用
watchQuery: (cb) => {} // 可选
};
包内提供两个实现:
createVueRouteAdapter():基于useRoute/useRouter,需在组件 setup 内调用。createMemoryRouteAdapter(initial?):纯内存实现,用于单测与组件外。
HTTP 请求
基本用法
import { createHttp, createHttpClient, createRequestConfig, httpRequest } from 'vebai-loom';
// 默认实例(使用 setDefaultRequestConfig 配置)
const http = createHttp();
await http.get('/api/user/list', { pageNo: 1 });
await http.post('/api/user/save', { name: '张三' });
await http.put('/api/user/save', payload); // put / delete / head / patch 均已支持
await http.request('delete', '/api/user/remove', { id: 1 });
// 简写(GET/HEAD 拼 query,POST/PUT/PATCH/DELETE 带 body,带防重复与短期缓存)
const list = await httpRequest('get', '/api/user/list', { pageNo: 1 });
const saved = await httpRequest('post', '/api/user/save', payload);
// 独立实例:多后台 / 多环境 / 单测(不参与 name 缓存)
const other = createHttpClient(createRequestConfig({ session, notifier, name: 'other', baseURL: '/other' }));
上传 / 下载
http.upload('/api/file/upload', formData, (e, requestId) => {
console.log('进度', e.loaded, e.total);
}, { requestId: 'upload-1' });
http.download('get', '/api/export', { type: 'excel' });
download()在请求失败时会reject,调用方需自行catch;文件名解析已对无filename=的响应头做防御。
单次请求配置
await httpRequest('post', '/api/x', payload, {
resubmitable: true, // 允许重复请求
returnRespone: true, // 返回完整 AxiosResponse
hideError: true // 业务错误不弹提示
});
await httpRequest('get', '/api/x', {}, undefined, true); // force=true,跳过缓存
响应约定
请求层按下面约定解析响应体(同时满足才视为业务响应):
{ "errcode": 0, "ok": true, "success": true, "result": {} }
- 业务成功 → 返回
data.result(除非returnRespone)。 data.errcode == 44001→ 提示「登录凭证过期」并触发退出。- 业务失败 → 提示
data.errmsg并抛错。 - 响应不匹配上述结构 → 原样返回
AxiosResponse。 - 响应头出现
authorization-refresh→ 延迟 3 秒调用deps.refreshToken。
RequestConfig 工厂
createRequestConfig({
session, // 必需
notifier, // 必需
baseURL: '/',
timeout: 30000,
name: 'default', // 同名实例会被复用
returnRespone: false,
resubmitable: false,
headers: {},
refreshToken: () => {}, // 可选
logout: () => {}, // 可选,默认 session.destroy()
repeatRequestTime: 1000, // 可选,防重复请求窗口(毫秒)
cacheSize: 200, // 可选,短期响应缓存上限
logger: myLogger, // 可选,默认 console
translator: myTranslator // 可选,默认内置中文
});
Permission 权限
配置
PermissionConfig 有四种模式,公共字段一致:
| 字段 | 说明 |
|---|---|
mode |
'role' | 'operate' | 'menu' | 'menuAndOperate' |
loginPath |
登录页路径 |
loadingPage |
加载页路径 |
strict |
严格模式,见下 |
history |
'hash'(默认)或 'web' |
baseRoutes |
静态基础路由(登录页、404、loading 等) |
mainRoute |
主框架路由,动态菜单会作为其 children 挂载 |
routerConfig |
菜单来源配置 |
whiteList |
免登录白名单(按路由 name 匹配) |
refreshTokenPath |
刷新 token 接口 |
onNotAuth |
退出前回调,支持同步/异步 |
filterOfPermi |
是否按权限过滤菜单(仅 role 模式生效) |
loginCheckPath |
登录状态检查接口,默认 /api/public/admin/isLogin |
模式专属字段:
role:roles: string[]、routeMetaName(路由 meta 上角色字段名)。operate:operates: string[]、routeMetaName。menu:checkType: 'name' | 'path'。menuAndOperate:menus: string[]。
strict 语义
strict: true(默认)→ 登录校验要求 同时具备 token 与 authType。strict: false→ 仅要求 token。
菜单来源(三选一)
// 1) 静态路由数组
routerConfig: { menus: [ /* RouteRecordRaw[] */ ], parentName: 'index' }
// 2) Promise
routerConfig: { menus: fetchRoutes(), parentName: 'index' }
// 3) 动态接口
routerConfig: {
parentName: 'index',
menus: {
url: '/api/sys/menu/list',
method: 'get',
cache: true, // 为真时优先读 session.getMenus(),未命中再请求并写回
tree: { id: 'id', parent: 'parentId' },
dataKey: 'result', // 可选,取嵌套数据
generatorRoute: (menu) => ({ // 菜单项 → 路由
path: menu.path,
name: menu.code,
component: () => import(`/src/views/${menu.component}`),
meta: { title: menu.name, type: menu.type, hide: !menu.visible, actions: menu.actions }
})
}
}
checkType 生效规则:menu 模式下按 name 或 path 匹配路由;其它模式固定按 path。
常用方法
const permission = usePermission();
permission.router; // 供 app.use() 使用
permission.checkAuthority(route); // 角色模式下判断路由权限
permission.login(authType, token, info);// 登录成功后调用,会重新初始化菜单
permission.logout(); // 清登录态并跳登录页
permission.clearAuth(); // 只清登录态,不跳转
permission.refreshToken(); // 主动刷新 token
permission.dispose(); // 摘除路由守卫
permission.start(); // autoStart=false 时手动启动
resetPermission(); // 重置单例(HMR / 测试)
PermissionConfig.autoStart默认true:创建时自动检查登录态并初始化菜单;置为false后由调用方自行调用permission.start()(返回 Promise)。
resetPermission()会先dispose()再置空单例,可安全地重新createPermission()。
Handler 列表
Handler.build 默认在组件 setup 内调用(内部使用 useRoute() / useRouter())。
notifier / confirm / tableFilter 由 setupVbCore() 注入一次,无需每次传;只有组件级的 route 需要按需传入(不传则走 useRoute/useRouter):
Handler.build(config); // setup 内,最简
Handler.build(config, { route: createVueRouteAdapter() }); // 显式注入 vue-router 路由
Handler.build(config, { route: createMemoryRouteAdapter() }); // 组件外 / 单测
开启
route: true后,查询参数通过replace同步到 query(不堆历史记录)。
import { Handler } from 'vebai-loom';
const handler = Handler.build({
queryApi: { url: '/api/user/page', method: 'get' },
page: true,
rowKey: 'id',
autoQuery: true,
route: true, // 查询参数与路由 query 双向同步
pageSize: 20,
apis: {
remove: { url: '/api/user/remove', method: 'post', autoRefresh: true },
export: { url: '/api/user/export', method: 'get', download: true }
}
}); // 全局依赖已由 setupVbCore() 注入;需要显式路由时再加第二个参数
HandleConfig
| 字段 | 说明 |
|---|---|
queryApi |
列表查询接口 |
page |
是否分页 |
autoQuery |
默认 true,创建后自动查询 |
sort |
前端排序函数 |
treeTable |
true 或 { id, pid },组织为树 |
pageSize / params / rowKey / listKey |
分页与数据结构配置 |
route |
与路由 query 同步 |
queryBefore |
查询前钩子,返回 boolean 或 Promise |
queryAfter |
查询后钩子 (list, data) => void |
apis |
操作名 → Api |
Api:{ url, method, title?, download?, autoRefresh?, confirmTitle?, confirmTip? }
Handler 方法与状态
| 成员 | 说明 |
|---|---|
list / loading / loaded |
列表数据与加载状态 |
pagination / pageParam / params |
分页与查询参数 |
query() / search() / reset() |
查询 / 回到第一页查询 / 重置参数 |
getIndex(index) |
计算序号 |
edit(data, key?) |
设置当前编辑数据 |
getData() / getId(key?) |
取当前数据 |
handle(name, data?, auto?, confirm?) |
调用 apis[name] |
remove() / disable() / move() / export() |
常用操作的封装 |
importResult(data) |
展示导入结果 |
selectedKeys / selectedObjs / onSelectedChange / setSelectedObjs / removeSelectedObjs |
多选 |
filter(type) / selectFilter(...) |
生成表格筛选属性(交给 TableFilterAdapter 渲染) |
onChange(pagination, filters, sorter, extra) |
传给表格的排序处理 |
表格列可直接使用:
columns = [
{ title: '名称', dataIndex: 'name', ...handler.filter('text') },
{ title: '状态', dataIndex: 'status', ...handler.selectFilter(statusState) }
];
// 表格事件
// @change="handler.onChange"
DynamicForm 动态表单
DynamicForm 是纯 TS 引擎:不 import vue,也不返回 VNode。它输出一份「描述符」,由使用方渲染器渲染。
基本用法
import { DynamicForm } from 'vebai-loom';
const form = { userName: '', status: 1 };
const engine = new DynamicForm([
{ type: 'input', name: 'userName', title: '用户名', rules: ['required'] },
{ type: 'select', name: 'status', title: '状态', list: statusList, firstOption: true }
], { labelWidth: 100, layout: 'horizontal' }, form);
const descriptor = engine.createDescriptor();
// descriptor.kind === 'form',交给你的渲染器
适配器写值时会调用描述符里的 onChange,引擎据此写回模型:
field.onChange(value); // 内部 setLinkData + 触发 item.onChange
engine.getModel(); // 当前模型
engine.setValue('a.b', 1); // 按路径写值
engine.invalidate(); // 外部直接改了模型时,手动失效描述符缓存
engine.createDescriptor(); // 带缓存;force=true 强制重建
表格(
type: 'table')不再往业务数据里写__index,提交前无需清理。
支持的控件类型
input、password、number、textarea、inputGroup、radio、checkbox、switch、select、treeSelect、radioGroup、checkboxGroup、datePicker、dateRangePicker、autoComplete、table、group、span、multipleText、fileUpload、filePicker、imageUpload、excelImport、editor、customRender。
通用字段
| 字段 | 说明 |
|---|---|
type / name / title |
控件类型、字段名、标题 |
rules |
'required' / 正则 / 对象 / 函数,或它们的数组 |
attrs |
透传给控件的属性 |
width / style / colSpan / colFlex |
布局 |
hideLabel / labelWidth / labelAttrs / labelStyle |
标签 |
disabled / depand |
布尔或 (form) => boolean |
onChange({ name, value, data, index }) |
值变化回调 |
help |
帮助文本 |
描述符结构
FormDescriptor
├── layout / labelAlign / labelWidth / justifyLabel / attrs
└── rows: RowDescriptor[]
└── cols: ColDescriptor[]
└── node: FieldDescriptor | SpanDescriptor | TableDescriptor
| GroupDescriptor | InputGroupDescriptor | CustomDescriptor
FieldDescriptor 关键字段:
control:控件类型name/field:完整点路径 / 叶子字段名value+valueType:'value' | 'checked' | 'date' | 'dateRange'options/treeData/fieldNamesrules/attrs/labelAttrs/style/placeholderonChange(value):写回回调encrypt(password)、customAdd(select)、dateFormat(日期)
渲染器职责
渲染器需要:
- 把
FormDescriptor渲染成对应框架的表单容器与栅格。 - 按
control从ControlRegistry取控件组件。 - 按
valueType绑定值与回调:value→ 常规值绑定;checked→ checkbox / switch;date/dateRange→ 用dateFormat在字符串与日期对象之间转换(dayjs / Date 由适配器负责)。
- 把
rules转成框架的校验规则。 table/group:用描述符里的columns/items/onAdd/onRemove/onMove渲染。
参考实现见 examples/antd/dynamic-form-render.ts 与 examples/element-plus/dynamic-form-render.ts。
编写自己的适配器
表单承载(FormHost)
FormHost 把表单的校验、提交、成功提示与自动关闭收进内核,并用 display 切换承载方式:
| display | 承载方式 |
|---|---|
page |
页面内卡片 |
modal |
弹窗 |
drawer |
抽屉 |
内核不依赖任何 UI 库:承载容器、按钮、表单渲染与校验实例都由 FormHostAdapter 注入,入口为 vebai-loom/form-host(与框架无关的 vebai-loom/dynamic-form 分开)。
import { FormHost } from 'vebai-loom/form-host';
import { createAntdFormHostAdapter } from './adapters/antd-form-host';
const adapter = createAntdFormHostAdapter();
<FormHost
display="drawer"
:visible="visible"
title="编辑用户"
:adapter="adapter"
:form-items="formItems"
:form="form"
:init-form="{ name: '' }"
url="/api/user/save"
method="post"
draft
@update:visible="visible = $event"
@success="onSuccess"
/>
FormHostAdapter 需要提供:
button:底部按钮组件。renderForm(engine):渲染表单主体,通常复用已有的描述符渲染器。renderContainer(context):按display渲染 page / modal / drawer 容器。validate()/resetValidation():表单校验与清空校验。
提交流水线由 runFormSubmit() 提供,可在纯 Node 环境测试:校验 -> onSubmitBefore -> json / formData 组装 -> httpRequest -> Notifier 成功提示 -> onSuccess。
内核只依赖 interfaces 里的接口:
- 实现
Notifier/ConfirmService。 - 实现
SessionAdapter(token、用户信息、菜单持久化)、Logger、Translator。 - 用
createControlRegistry()把控件类型(input/select/ ...)映射到自己的组件。 - 实现
TableFilterAdapter(表格筛选下拉)。 - 写一个渲染器消费
FormDescriptor,把描述符渲染成你的组件。 - 需要组件外使用 handler 时,注入
RouteAdapter(createVueRouteAdapter()或createMemoryRouteAdapter())。
examples/antd 与 examples/element-plus 提供可直接参照的实现(它们不参与构建、不被导出、不在 package.json 声明依赖)。
常见注意事项
- 初始化顺序:先
setDefaultRequestConfig,再createPermission;否则权限初始化会取不到请求实例。 Handler.build的作用域:默认必须在组件setup内调用(依赖useRoute()/useRouter());注入RouteAdapter后可在组件外运行。- 日期:内核只传字符串与
dateFormat,字符串与日期对象的互转由适配器完成。 filterOfPermi:仅role模式有明确判定语义;menu模式由后端按权限下发菜单,不再二次过滤。strict:默认要求 token + authType;只有确实不需要 authType 时才设为false。- 菜单缓存:
DynamicMenuApi.cache = true时,getMenus会先读session.getMenus(),未命中再请求并写回;退出登录会清空。 - input 归一化:
input默认执行trim与 Unicode 空白过滤,可用trim: false/filterUnicode: false关闭。 - 密码字段:
password若提供encrypt,描述符不再回显原值,适配器提交前会经过encrypt。 - 重复初始化:
initialize()是幂等的,重复登录不会累积子路由;如需重建可调用resetPermission()。 - 导入结果:
importResult会把errMsgs先用escapeHtml()转义再拼 HTML,适配器可安全渲染。 - 依赖安装:使用
permission/handler时需自行安装vue与vue-router(它们是 optional peer)。
速查表
| 能力 | 入口 |
|---|---|
| 配置请求 | setDefaultRequestConfig(createRequestConfig(deps)) |
| 发请求 | createHttp() / httpRequest() |
| 权限 | createPermission / usePermission / resetPermission |
| 列表 | Handler.build(config, deps) |
| 动态表单 | new DynamicForm(items, attrs, form) → createDescriptor() |
| 纯函数与工具 | vebai-loom/shared、vebai-loom/shared/business |
| 参考适配器 | examples/antd、examples/element-plus |
脚本与构建
在包目录内执行:
| 脚本 | 作用 |
|---|---|
npm run typecheck |
基础类型检查 |
npm run typecheck:strict |
核心模块严格模式检查(shared / interfaces / types / routes / rules) |
npm run typecheck:examples |
antd 示例类型检查 |
npm test |
纯函数单测(node:test,零新增依赖) |
npm run build |
生成 dist 与 .d.ts,并把本文档复制为 dist/README.md |
npm publish |
发布前自动执行 prepublishOnly(npm run build) |
两套哲学的取舍
dynamic-form是框架无关的描述符引擎,渲染完全交给使用方。http / permission / handler保留 Vue3 + vue-router;handler通过注入RouteAdapter获得组件外运行能力。
permission 默认在创建时自动检查登录态(autoStart: true);置为 false 后由调用方调用 permission.start()。
这是有意为之的取舍:渲染引擎彻底解耦收益最大,而列表/权限逻辑留在 Vue 生态成本更低。
Related Packages
Vue 3 plugin for a shared Axios instance (JSON headers, multi-database base URL,...
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 2.0.0 | ^3.2.37 | MIT |
Pre-releases (1)
| Version | Released | License |
|---|---|---|
| 0.0.0-stage |