Argilla 前端目录结构全解析:从 Nuxt 页面组织到 v1 Clean Architecture 分层
【免费下载链接】argillaArgilla is a collaboration tool for AI engineers and domain experts to build high-quality datasets项目地址: https://gitcode.com/GitHub_Trending/ar/argilla
本篇文章基于 Argilla 仓库中 argilla-frontend/docs/structure.md 的官方目录说明,逐层剖析 Argilla 前端(基于 Nuxt 2 + Vue 2 的 Web 应用)的完整目录体系。你将掌握 assets、components、pages、layouts、middleware、plugins、e2e、v1 等每个目录的职责边界与相互调用关系,理解 base 组件与 features 组件的分层哲学,并看懂 v1 新架构中依赖注入容器、领域层与基础设施层的真实组织方式,从而能够快速定位代码、判断新功能应该落在哪个目录。
一、顶层目录总览
structure.md给出的官方结构树完整如下:
. ├── assets │ ├── fonts │ ├── icons │ └── scss ├── database -> Vuex modules (to be removed) ├── models -> Vuex models (to be removed) ├── store -> Vuex store (to be removed) ├── components │ ├── base -> Base and stateless components │ ├── features -> Features used in just one page │ ├── annotation -> Componentes used in Annotation page │ ├── datasets -> Components to support datasets page │ ├── global -> Components used in multiple pages ex: UserAvatarComponent │ ├── login -> Components to support login page │ └── user-settings -> Components to support user settings page ├── e2e -> E2E tests ├── layouts -> Layout components ├── middleware -> Nuxt middlewares ├── pages -> Nuxt global pages ├── plugins -> Nuxt plugins ├── static -> Static resources ├── translations -> Argilla translation resources ├── v1 -> New architecture │ ├── di │ ├── domain │ ├── infrastructure │ └── store │... ├── package.json ├── package-lock.json └── .gitignore对照当前仓库实际内容,可以观察到结构演进:文档中标记为 "to be removed" 的database(Vuex modules)、models(Vuex models)两个目录已经不存在,store(Vuex store)也整体迁移到了 v1/store 之下;原本分散在components下的annotation、datasets、global、login、user-settings子目录,如今统一收纳进 components/features,并在其中新增了dataset-creation、home等功能域;translations目录实际名为translation(与 nuxt.config.ts 中的langDir: "translation/"保持一致)。理解这份"文档基线 + 仓库现状"的差异,比单纯背目录更有价值——它反映了一次从 Vuex 状态管理向 Pinia/组合式 API 演进、从扁平组件目录向"基础组件 + 功能组件"两级体系演进的重构过程。
二、assets:样式与图标的统一入口
assets是构建期会被打包进应用的静态资源目录,与static(运行期原样拷贝)有本质区别。当前仓库中该目录实际包含:
assets/scss:全部 SCSS 样式源文件,其中abstract/存放变量、函数、混入(mixin)等抽象层定义;assets/icons:由 SVG 图标生成的 JS 模块(如 assets/icons/annotation-mode.js 系列),配合 assets/icon-template.js.tmp 模板文件;assets/styles.scss:全局样式入口。
这些资源在 nuxt.config.ts 中被消费:
css: ["~assets/styles.scss"], ... styleResources: { scss: "./assets/scss/abstract.scss", },css将全局样式注入所有页面;styleResources(来自@nuxtjs/style-resources模块)则把abstract.scss中定义的 SCSS 变量与混入自动注入到每个组件的<style>中,使业务组件无需手动@import即可使用主题变量——这是目录结构与构建配置联动的典型例子。
图标生成链路同样值得注意:package.json 中的generate-icons脚本(vsvg -s ./static/icons -t ./assets/icons --tpl ./assets/icon-template.js.tmp)把static/icons下的原始 SVG 批量编译为assets/icons下的 JS 模块,供 base-icon 组件动态渲染。因此"新增一个图标"需要同时改动static/icons与assets/icons两个目录,且后者是生成产物,不应手工编辑。
三、components:base 与 features 的两级组件哲学
components是 Argilla 前端组件体系的核心,遵循"基础组件与业务组件分离"的原则,通过 nuxt.config.ts 的自动导入能力全局注册:
components: [ { path: "~/components", pattern: "**/*.vue", pathPrefix: false, level: 1, }, ],pathPrefix: false意味着所有.vue组件都会以文件名为组件名(如base-tag目录下的文件即为BaseTag),无需在模板中手动import。
3.1 base:基础且无状态的通用组件
base目录(argilla-frontend/components/base)存放"与业务无关、可复用、多为无状态"的原子组件,例如:
base-badge、base-tag:徽章与标签;base-button、base-checkbox、base-switch、base-slider、base-range:基础表单控件;base-icon:图标渲染;base-modal、base-tooltip、base-dropdown:浮层与弹窗;base-input、base-search-bar:输入与搜索;base-toast、base-feedback:全局反馈提示;base-render-markdown、base-code:Markdown 渲染与代码高亮;base-progress、base-loading、base-spinner:加载与进度展示。
这类组件的典型特征是无副作用、不直接依赖后端 API,输入输出完全由 props/events 驱动,因此可以在任何页面中安全复用。例如base-render-markdown底层借助marked、marked-highlight、marked-katex-extension与dompurify(见 package.json)实现安全的高亮与数学公式渲染,供注释(annotation)页面的指导语(guidelines)等场景使用。
3.2 features:服务于单一页面的功能组件
features目录(argilla-frontend/components/features)按"页面/业务域"组织,当前包含annotation、dataset-creation、global、home、login、user-settings六个功能域,与 structure.md 描述的"Features used in just one page"一脉相承。以最重要的 features/annotation(99 个.vue文件、31 个.ts文件)为例,其内部按职责再次细分:
container:标注流程的容器组件,承担数据编排;header:标注页顶部工具栏;guidelines:数据集标注指导语的展示;pagination:记录翻页;progress:标注进度展示;settings:标注设置面板;shortcuts:键盘快捷键。
而global(如UserAvatarComponent一类的跨页面组件)、login、home、dataset-creation、user-settings分别对应登录页、首页、新建数据集流程与用户设置页面。当新功能只属于某个页面时,应放入对应功能域;只有当组件被多个页面共用且与业务无关时,才应该上升到base。
四、pages、layouts、middleware 与 plugins:Nuxt 四大约定目录
4.1 pages:文件即路由
argilla-frontend/pages 采用 Nuxt 的文件系统路由约定,关键页面包括:
index.vue:首页;sign-in.vue:登录页,配套useSignInViewModel.ts;welcome-hf-sign-in.vue:Hugging Face Spaces 环境下的欢迎/登录引导页;user-settings.vue:用户设置;new/_id.vue:新建数据集流程(动态路由参数id);dataset/_id/:数据集详情,其中settings.vue为数据集设置页,annotation-mode/为标注模式页面,useDatasetViewModel.ts与useDatasetSettingViewModel.ts分别是两级页面各自的 ViewModel。
ViewModel 模式(useXxxViewModel.ts)是 Argilla 前端的标准做法:页面组件只负责渲染,业务逻辑收敛到 ViewModel 中,再通过 v1 层的 UseCase 与 Repository 访问后端。
4.2 layouts:页面骨架
argilla-frontend/layouts 定义了四类页面骨架:Home.vue(首页布局)、AuthenticationLayout.vue(登录/认证布局)、AnnotationPage.vue(标注页全屏布局)、InternalPage.vue(内部功能页布局),外加app.vue(应用根布局)与error.vue(错误页)。不同页面通过 Nuxt 的layout属性选择不同骨架,例如标注页面使用沉浸式的AnnotationPage以最大化标注空间。
4.3 middleware:路由守卫
argilla-frontend/middleware 中的两个中间件在 nuxt.config.ts 中被全局挂载:
router: { middleware: ["route-guard", "me"], base: process.env.BASE_URL ?? "/", },- route-guard.ts 按路由名做访问控制:未登录访问任何页面时记录
redirectTo并重定向到sign-in;已登录用户访问sign-in则跳回首页;在 Hugging Face Spaces 环境下将登录入口重定向到welcome-hf-sign-in;对oauth-provider-callback等 OAuth 回调路由做空参数拦截; - me.ts 通过
ts-injecty的useResolve(LoadUserUseCase)加载当前用户,若后端返回 401 则触发$auth.logout()并重定向到登录页——这是路由守卫与 v1 架构协同工作的典型链路。
4.4 plugins:全局注入
argilla-frontend/plugins 在 nuxt.config.ts 中以plugins: [{ src: "~/plugins" }]整体注册。其入口 plugins/index.ts 使用require.context("./", true, /^\.\/.*\.(ts|js)$/)递归加载目录下所有插件模块并执行其默认导出,从而实现"新增插件文件即自动注册"。插件按职责分子目录:
axios/:axios-cache.ts(API 响应缓存)与axios-global-handler.ts(全局错误处理);di/:依赖注入容器初始化入口di.ts;directives/:自定义指令,如tooltip.directive.ts、click-outside.directive.ts、badge.directive.ts、required-field.directive.ts、svg-icon.element.ts;extensions/:工具扩展,如color-generator.ts、copy-to-clipboard.ts、format-number.ts、notification.ts、vue-draggable.ts;language/:language-detector.ts与language-direction.ts;logo/:Logo 渲染逻辑。
五、e2e:Playwright 端到端测试
argilla-frontend/e2e 存放基于 Playwright 的端到端测试(playwright.config.ts),与 package.json 中的e2e/e2e:silent/e2e:report脚本对应,并在postgenerate阶段(nuxt generate后)自动执行静默回归测试。
测试目录按页面划分:annotation-mode-page(标注模式,含 autosave、mac 快捷键、元数据筛选与排序等专项 spec)、dataset-setting-page、datasets-page、login-page、user-setting-page;common/目录则提供 API Mock 工具(dataset-api-mock.ts、record-api-mock.ts、question-api-mock.ts、field-api-mock.ts、metadata-api-mock.ts与login-and-wait-for.ts),使 E2E 测试可以脱离真实后端独立运行。各 spec 目录下的__screenshots__用于维护 Playwright 视觉回归基线。
六、static 与 translation:静态资源与多语言
- argilla-frontend/static 存放运行期原样暴露的静态资源:
fonts/(Raptor 主题字体)、icons/(与assets/icons对应的 SVG 源文件)、images/(Logo、登录页截图、帮助信息图)、js/handlebars.min.js,以及favicon系列与site.webmanifest(在 nuxt.config.ts 的head中被引用)。 - argilla-frontend/translation 是 Argilla 的多语言资源目录,提供
en.js、de.js、es.js、ja.js四种语言文件,与 nuxt.config.ts 的@nuxtjs/i18n配置一一对应(langDir: "translation/"、defaultLocale: "en"、fallbackLocale: "en"、strategy: "no_prefix"、关闭浏览器语言自动探测)。新增语言只需在此目录添加语言文件并在i18n.locales注册。
七、v1:面向 Clean Architecture 的新架构
v1是 Argilla 前端正在演进的新架构(argilla-frontend/v1),替代以 Vuex 为中心的旧模式,其核心是"依赖注入 + 分层职责"。整体分为四层:
7.1 di:依赖注入容器
argilla-frontend/v1/di/di.ts 中的loadDependencyContainer(context)是 v1 架构的心脏:它基于ts-injecty的Container.register(dependencies),将全部 Repository 与 UseCase 显式注册进容器。每个 Repository 注入useAxiosExtension(context)提供的 Axios 实例,UseCase 则声明其依赖的 Repository 或 Storage:
register(GetDatasetsUseCase) .withDependencies(DatasetRepository, useDatasets) .build(), register(LoadRecordsToAnnotateUseCase) .withDependencies( GetRecordsByCriteriaUseCase, GetDatasetProgressUseCase, GetUserMetricsUseCase, useRecords ) .build(),这种注册表式的写法让"组件 → UseCase → Repository → HTTP"的依赖链一目了然,也便于单元测试中替换依赖实现。
7.2 domain:纯业务领域层
argilla-frontend/v1/domain 分为四部分:
entities/(84 个 TS 文件):领域实体模型,如dataset/、record/、user/、workspace/、question/、field/、metadata/、vector/等;usecases/(36 个 TS 文件):业务用例,如get-datasets-use-case.ts、submit-record-use-case.ts、save-draft-use-case.ts、bulk-annotation-use-case.ts、load-records-to-annotate-use-case.ts、dataset-setting/下的一系列配置更新用例;同目录的*.test.ts(如get-dataset-fields-grouped-use-case.test.ts、oauth-login-usecase.test.ts)展示了对 UseCase 的单元测试方式;services/:领域服务接口(如 v1/domain/services 中的IDatasetRepository),定义 Repository 的抽象契约;events/:领域事件定义。
7.3 infrastructure:基础设施实现
argilla-frontend/v1/infrastructure 是 domain 层的实现落地:
repositories/(19 个 TS 文件):如 DatasetRepository.ts,直接面向后端 API。以数据集为例,create走POST /v1/datasets、publish走PUT /v1/datasets/{id}/publish、import/export走/v1/datasets/{id}/import与/export、update走PATCH /v1/datasets/{id}、进度查询走GET /v1/datasets/{id}/progress(配合largeCache()),并在写操作后调用revalidateCache使AxiosCache缓存失效。错误统一映射为DATASET_API_ERRORS常量中的语义化错误码,供上层做用户提示;services/(23 个 TS 文件):如useRunningEnvironment、useLocalStorage、useAxiosExtension、useRoutes、useRole等横切能力;storage/(6 个 TS 文件):Pinia 状态存储,如DatasetStorage、RecordsStorage、DatasetsStorage、MetricsStorage、DatasetSettingStorage、TeamProgressStorage;events/:基础设施层事件处理器(如UpdateMetricsEventHandler、UpdateTeamProgressEventHandler);types/:后端响应类型定义。
7.4 store:状态管理
v1/store 中的create.ts与non-reactive.ts提供状态创建工具,配合@pinia/nuxt(nuxt.config.ts 中disableVuex: false,表明当前仍兼容 Vuex)完成从 Vuex 向 Pinia 的渐进迁移,这也印证了 structure.md 中"Vuex store to be removed"的演进方向。
八、命名规范:kebab-case、PascalCase 与 camelCase
argilla-frontend/docs/conventions.md 定义了全仓库统一的命名约定:
- 文件夹名:kebab-case,例如
base-tag、dataset-creation; - 组件名:PascalCase,例如
BaseTag.vue、UserAvatarComponent.vue; - 类名:PascalCase,例如
Question.ts、DatasetRepository.ts; - 变量/常量名:camelCase,例如
firstName: string。
这套约定与第 3 节所述的组件自动导入机制深度耦合:由于pathPrefix: false,base-tag目录下的BaseTag.vue恰好能被 Nuxt 识别为<base-tag>组件;Vue 官方也要求组件注册名与文件名保持 PascalCase 一致。遵循此规范即可保证"文件名 → 组件名 → 模板标签"三者无缝映射。
九、目录、配置与请求代理的联动
最后,将目录结构放回 nuxt.config.ts 这一"总调度"中看全貌:
ssr: false表明 Argilla 前端是纯客户端渲染(SPA),generate.dir输出到DIST_FOLDER(默认dist);- Axios 采用
proxy: true,/api/与/share-your-progress两个路径被代理到后端地址BASE_URL(默认http://0.0.0.0:6900,可通过环境变量API_BASE_URL覆盖),前端代码中实际请求如/v1/datasets即经由此代理转发; auth策略配置了local策略、redirect: { login: "/sign-in", logout: "/sign-in" },与pages/sign-in.vue、middleware 中的重定向逻辑相互印证;publicRuntimeConfig暴露clientVersion(取自 package.json 版本)与文档站链接,供前端运行时读取。
十、写给开发者的目录导航建议
结合以上分析,在 Argilla 前端做功能开发时的目录导航路径可以概括为:
- 新增页面→ 在 pages 按路由创建
.vue+ 对应useXxxViewModel.ts,需要新骨架时在 layouts 增加布局; - 页面专属 UI→ 在 components/features 对应功能域下新增组件;通用无状态组件→ 放到 components/base;
- 业务逻辑→ 在 v1/domain/usecases 新增 UseCase,并在 v1/di/di.ts 注册依赖;访问后端→ 在 v1/infrastructure/repositories 实现 Repository,接口契约定义在 v1/domain/services;
- 状态共享→ 在 v1/infrastructure/storage 定义 Pinia 存储;
- 路由拦截→ 修改 middleware;全局能力→ 在 plugins 对应子目录新增插件模块;
- 样式与图标→ SCSS 放 assets/scss,图标 SVG 源文件放 static/icons 后执行
npm run generate-icons; - 文案→ 在 translation 各语言文件同步添加;
- 回归保障→ 单元测试跟随 UseCase/组件,端到端场景补充到 e2e。
掌握这份目录地图,你就具备了在 Argilla 前端代码库中"按图索骥"的能力,无论是排查标注流程的 bug、新增数据集设置项,还是理解用户登录与路由守卫的完整链路,都能快速定位到对应的组件、UseCase 与 Repository。
【免费下载链接】argillaArgilla is a collaboration tool for AI engineers and domain experts to build high-quality datasets项目地址: https://gitcode.com/GitHub_Trending/ar/argilla
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考