- 前端
- UI组件
- 后端
【免费下载链接】uppy
The next open source file uploader for web browsers :dog:
导读
本文以 Uppy 开源仓库中 examples/angular 示例项目为主体,系统讲解如何利用 Angular CLI 完成ng serve本地开发、ng generate代码脚手架、ng build生产构建与ng test单元测试的完整工作流,并深入剖析该示例如何通过@uppy/angular的DashboardComponent与DashboardModalComponent将 Uppy Dashboard 以「内联面板 + 模态弹窗」两种形态集成进 Angular 应用。读完本文,你将掌握一套可直接复用的 Angular + Uppy 文件上传集成方案,以及 Angular CLI 命令与 Uppy 插件声明式用法背后的实现原理。
1. 项目定位:Uppy 仓库中的 Angular 现代化示例
examples/angular是 Uppy 官方仓库中的 Angular 示例应用,其package.json将项目命名为example-angular(见 examples/angular/package.json),README 中标注该项目由 Angular CLI 19.2.6 生成。不过,从 examples/angular/package.json 的依赖版本看,当前仓库实际升级到了@angular/core22.x 与@angular/cli22.x,同时通过workspace:*协议直接引用仓库内 monorepo 的@uppy/core、@uppy/dashboard、@uppy/tus、@uppy/webcam与@uppy/angular包——这意味着该示例始终与 Uppy 最新源码保持同步,是验证 Angular 官方组件的“活文档”。
从源码结构看,这是一个采用Standalone 组件架构的现代 Angular 应用:入口文件 src/main.ts 直接调用bootstrapApplication(AppComponent)引导应用,而非传统NgModule模式;根组件 app.component.ts 以standalone: true声明,并在imports中直接引入CommonModule、DashboardComponent与DashboardModalComponent。
该示例的核心价值在于同时演示了 Uppy Dashboard 的两种主流挂载方式:
- 内联 Dashboard:通过
<uppy-dashboard>标签常驻页面,随时可见; - 模态 Dashboard:通过
<uppy-dashboard-modal>标签与open输入绑定,点击按钮后以浮层形式弹出。
两者共享同一个Uppy实例,是理解「一个 Uppy 核心、多个 UI 挂载点」的绝佳范例。
2. Angular CLI 基础工作流(原 README 核心内容)
本节完整继承 examples/angular/README.md 的 CLI 操作指引,并补充与仓库实际配置相符的细节。
2.1 启动本地开发服务器:ng serve
原 README 明确指出,启动本地开发服务器的命令为:
ng serve服务器启动后,在浏览器中访问http://localhost:4200/即可看到应用。Angular 的 dev server 具备自动热重载能力——只要修改任意源文件,页面会立即自动刷新,无需手动重启。
结合仓库配置,ng serve的实际行为由 angular.json 中projects.angular-modern-examples.architect.serve决定:默认走development配置(对应buildTarget: angular-modern-examples:build:development),该配置在build选项中关闭了optimization、开启sourceMap,便于调试;你也可以通过ng serve --configuration production切到生产模式验证最终表现。此外 package.json 还提供了等价脚本npm start(内部执行ng serve)。
2.2 代码脚手架:ng generate
Angular CLI 内置强大的代码生成(scaffolding)能力。生成一个新组件的命令为:
ng generate component component-name如果想查看所有可用的 schematics(包括components、directives、pipes等),运行:
ng generate --help仓库层面有一个值得注意的细节:当前示例的 angular.json 在schematics节点中将组件、指令、管道都显式配置为"standalone": false。也就是说,在本项目内用ng generate component生成的新组件默认属于传统 NgModule 体系(需手动声明到某个 module 中)。这与示例根组件自己手写standalone: true形成对照——你可以按需选择两种架构风格,这也是 CLI 脚手架行为与手写代码灵活共存的体现。
2.3 生产构建:ng build
执行:
ng buildCLI 会编译整个项目,并将构建产物输出到dist/目录。按 angular.json 的配置,具体输出目录为dist/angular-modern-examples,使用的 builder 是@angular/build:application。默认配置为production,包含:
- 代码压缩与 tree-shaking(
optimization默认开启,生产配置未显式覆盖即生效); outputHashing: "all",为产物文件名追加内容哈希以支持长效缓存;- 资源体积预算校验:初始包超过
500kB发出警告、超过1MB直接报错;任何组件样式超过4kB警告、超过8kB报错(见 angular.json 的budgets配置)。
原 README 强调生产构建会针对性能与速度做优化,仓库的budgets正是这套质量门槛的可视化体现。
2.4 单元测试:ng test
运行单元测试的命令为:
ng test仓库为该项目配置了基于 Karma 的测试基建:architect.test使用@angular/build:karmabuilder,并引入了zone.js/testingpolyfill(见 angular.json)。测试代码位于 src/app/app.component.spec.ts,包含三个用例:
- 应能成功创建
AppComponent实例; - 组件
title属性应为'Uppy Dashboard Angular Example'; - 渲染出的
<h1>文本应包含该标题。
这些用例同时验证了 Standalone 组件的导入(TestBed.configureTestingModule({ imports: [AppComponent] }))与模板渲染链路。
2.5 端到端测试:ng e2e
对于端到端(e2e)测试,原 README 说明运行命令为:
ng e2e并特别提醒:Angular CLI默认并不捆绑任何 e2e 测试框架,你可以自行选择(如 Playwright、Cypress 等)并按需接入。当前仓库的angular.json中也确实没有预置 e2e builder,这与 README 描述完全一致。
3. 深入示例:一个 Uppy 实例,两种 Dashboard 挂载形态
examples/angular的页面布局(见 app.component.html)分为两个 section:上半部分是常驻的内联 Dashboard,下半部分是「打开/关闭」按钮驱动的模态 Dashboard。两者通过模板语法绑定到同一个uppy实例,这正是理解@uppy/angular组件模型的最佳切入点。
3.1 根组件:Uppy 实例的初始化与插件装配
在 app.component.ts 中,组件以readonly风格初始化了一个 Uppy 实例:
uppy = new Uppy({ debug: true, autoProceed: false, restrictions: { maxFileSize: 1000000, maxNumberOfFiles: 3, allowedFileTypes: ['image/*', 'video/*'], }, })debug: true:在控制台输出 Uppy 内部日志,便于开发期排查;autoProceed: false:文件添加后不自动上传,等待用户显式点击上传按钮(Dashboard 内联视图的典型交互);restrictions:限制单文件不超过 1 MB、最多 3 个文件、仅允许图片与视频类型。
随后在ngOnInit()生命周期中装配插件:
ngOnInit(): void { this.uppy .use(Webcam) .use(Tus, { endpoint: 'https://tusd.tusdemo.net/files/' }) .on('complete', (result) => { console.log("Upload complete! We've uploaded these files:", result) }) }这里注册了Webcam(摄像头拍照/录像)与Tus(基于 tus 协议的可断点续传上传器,endpoint 指向公开测试服务https://tusd.tusdemo.net/files/),并监听complete事件在控制台输出上传结果。
组件还为两种 Dashboard 分别定义了属性对象:
dashboardProps = { plugins: ['Webcam'], height: 470, showProgressDetails: true, note: 'Images and video only, 2-3 files, up to 1 MB', restrictions: { /* 与 Uppy 实例一致的限制 */ }, } dashboardModalProps = { target: document.body, onRequestCloseModal: (): void => { this.showModal = false }, closeModalOnClickOutside: true, animateOpenClose: true, }其中dashboardProps.plugins: ['Webcam']表示在 Dashboard 内显示 Webcam 标签页;模态版则额外声明了关闭行为(点击遮罩关闭、开合动画)与onRequestCloseModal回调,用于同步组件状态showModal。
3.2 模板绑定:<uppy-dashboard>与<uppy-dashboard-modal>
页面模板(app.component.html)的核心片段如下:
<uppy-dashboard [uppy]="uppy" [props]="dashboardProps" ></uppy-dashboard> <button class="toggle-button" (click)="toggleModal()"> {{ showModal ? '✕ Close Modal Dashboard' : '📤 Open Modal Dashboard' }} </button> <uppy-dashboard-modal [uppy]="uppy" [open]="showModal" [props]="dashboardModalProps" ></uppy-dashboard-modal>三个关键绑定:
[uppy]:传入共享的Uppy实例,两个组件都指向同一个实例,因此内联面板中选中的文件,在模态面板中同样可见;[props]:传入对应形态的 Dashboard 配置对象;[open](仅模态组件):由showModal布尔状态驱动,toggleModal()方法负责翻转该状态。
这种「组件输入属性 + 模板事件」的用法,让 Uppy 的挂载完全声明式化,开发者无需手动操作 DOM。
4. 源码剖析:@uppy/angular 组件如何工作
@uppy/angular是 Uppy 官方维护的 Angular 组件包装层,公共 API 导出三个组件(见 public-api.ts):DashboardComponent、DashboardModalComponent与StatusBarComponent。本示例用到了前两者,其实现细节值得深入。
4.1 统一的 Angular 包装基类
两个 Dashboard 组件都继承自 utils/wrapper.ts 中的UppyAngularWrapper抽象类,该类封装了插件生命周期管理的核心逻辑:
onMount(defaultOptions, plugin):将组件默认选项(如id、inline、target)与用户传入的props合并,调用this.uppy.use(plugin, options)注册插件,并通过this.uppy.getPlugin(id)拿到插件实例;handleChanges(changes, plugin):响应 Angular 的OnChanges——若uppy输入属性被替换为新的实例,先uninstall旧实例上的插件再挂载到新实例;若props发生变化,则调用this.plugin.setOptions(...)热更新配置;uninstall(uppy):调用uppy.removePlugin(this.plugin)完成卸载,实现组件销毁时的资源清理。
这一基类正是@uppy/angular组件「声明式绑定、响应式更新」的底层保证。
4.2 DashboardComponent:内联挂载
dashboard.component.ts 以@Component({ selector: "uppy-dashboard", template: "", changeDetection: ChangeDetectionStrategy.OnPush, standalone: true })声明,暴露出两个@Input():
@Input() uppy: Uppy<M, B> = new Uppy(); @Input() props: DashboardOptions<M, B> = {};在ngOnInit()中调用onMount({ id: "angular:Dashboard", inline: true, target: this.el.nativeElement }, Dashboard)——注意inline: true表示渲染为页内面板,target指向组件宿主元素。随后ngOnChanges负责响应输入变化,ngOnDestroy负责卸载插件。
4.3 DashboardModalComponent:模态挂载
dashboard-modal.component.ts 额外暴露了第三个输入属性@Input() open: boolean = false,并在ngOnChanges中针对open的翻转做了专门处理:
if (changes["open"] && this.open !== changes["open"].previousValue) { if (this.open && !changes["open"].previousValue) { this.plugin!.openModal(); } if (!this.open && changes["open"].previousValue) { this.plugin!.closeModal(); } }即:open从false变为true时调用openModal(),反向则调用closeModal(),从而把 Angular 的输入绑定翻译成 Uppy Dashboard 原生的模态 API。这也解释了为何示例模板中只需绑定[open]="showModal"即可驱动浮层开合。
从源码结构可以推断:
UppyAngularWrapper的响应式设计(setOptions热更新、uppy实例替换时的重挂载)使得 Angular 的变更检测与 Uppy 的插件系统得以无缝衔接,ChangeDetectionStrategy.OnPush则保证了只在输入真正变化时触发更新,避免不必要的渲染开销。
5. 配置文件全景:从 package.json 到 tsconfig 与 angular.json
原 README 只交代了 CLI 命令,本节将相关配置文件串联起来,帮助读者理解每个命令背后的工程设定。
5.1 依赖与脚本(package.json)
- 运行时依赖:
@angular/core、@angular/common、@angular/forms、@angular/router等 Angular 22.x 系,以及@uppy/angular、@uppy/core、@uppy/dashboard、@uppy/tus、@uppy/webcam(均以workspace:*指向本仓库包),外加rxjs、tslib、zone.js; - 开发依赖:
@angular/cli、@angular/build、@angular/compiler-cli、typescript; - 脚本映射:
start→ng serve、build→ng build、watch→ng build --watch --configuration development、test→ng test。
5.2 TypeScript 编译配置(tsconfig.app.json)
应用编译配置基于仓库根tsconfig.json扩展,关键点:module: "es2022"、moduleResolution: "bundler"(适配现代打包器)、resolveJsonModule: true(允许直接导入 JSON),入口文件为src/main.ts。
5.3 Angular 构建配置(angular.json)
核心要点已在第 2 节分散说明,这里汇总:
| 配置项 | 取值 | 作用 |
|---|---|---|
| builder | @angular/build:application | 现代应用构建器 |
| outputPath | dist/angular-modern-examples | 构建产物目录 |
| polyfills | ["zone.js"] | Zone.js 运行时 |
| styles | ["src/styles.css"] | 全局样式入口 |
| assets | public目录 | 静态资源拷贝 |
| budgets | initial ≤ 500kB(警告)/1MB(报错),组件样式 ≤ 4kB(警告)/8kB(报错) | 体积质量门禁 |
| 生产配置 | outputHashing: "all" | 哈希文件名 |
6. 改造为本项目:最小可复用的 Angular + Uppy 集成模板
基于本示例可以提炼出一个最小集成模板(这正是@uppy/angularREADME 中的官方范式,见 packages/@uppy/angular/README.md):
import { Component, type OnDestroy } from '@angular/core' import { DashboardComponent } from '@uppy/angular' import Uppy from '@uppy/core' @Component({ selector: 'app-uploader', standalone: true, imports: [DashboardComponent], template: '<uppy-dashboard [uppy]="uppy"></uppy-dashboard>', }) export class UploaderComponent implements OnDestroy { readonly uppy = new Uppy() ngOnDestroy(): void { this.uppy.destroy() } }两个实践要点:
- 安装依赖:
npm install @uppy/angular @uppy/core @uppy/dashboard(在 monorepo 内则以workspace:*引用,与本示例一致); - 资源释放:在
ngOnDestroy()中调用this.uppy.destroy(),避免组件销毁后 Uppy 实例残留事件监听与资源,这一点与本示例中DashboardComponent通过UppyAngularWrapper.uninstall()自动清理插件的思路一脉相承。
若需要 Tus 断点续传、Webcam 采集等能力,参照 app.component.ts 的ngOnInit模式,通过this.uppy.use(...)依次装配插件即可。
7. 小结与进一步探索
examples/angular展示了现代 Angular(Standalone +bootstrapApplication)与 Uppy 的最佳整合方式:CLI 层面,ng serve/ng generate/ng build/ng test/ng e2e构成了完整的开发、脚手架、构建与测试闭环;组件层面,@uppy/angular通过统一的UppyAngularWrapper基类把 Uppy 插件的安装、热更新与卸载封装为声明式输入绑定,开发者只需维护uppy、props、open三个属性即可获得完整的上传能力。
若想继续深入,可以从以下仓库路径入手:
- 组件公共 API:packages/@uppy/angular/src/public-api.ts,以及
StatusBarComponent(status-bar.component.ts); - 包装器实现:packages/@uppy/angular/src/utils/wrapper.ts;
- 底层 Uppy 核心与 Dashboard 插件:packages/@uppy/core/src/Uppy.ts 与 packages/@uppy/dashboard/src/Dashboard.tsx;
- 单元测试范式:examples/angular/src/app/app.component.spec.ts;
- 官方组件文档:
@uppy/angular包说明见 packages/@uppy/angular/README.md。
把 examples/angular 作为起点,结合上述源码路径,即可在自己的 Angular 应用中快速落地一套可维护、可断点续传、支持摄像头采集的现代化文件上传方案。
- 前端
- UI组件
- 后端
【免费下载链接】uppy
The next open source file uploader for web browsers :dog:
相关推荐
深入解析 composer/xdebug-handler:CLI 进程无 Xdebug 自动重启机制及 Rector 中的实战应用
深入解析 composer/xdebug handler:CLI 进程无 Xdebug 自动重启机制及 Rector 中的实战应用 本篇技术指南以开源仓库中 c
前端UI组件后端在 Turborepo with-angular 示例仓库中使用 Angular CLI 的完整开发指南
在 Turborepo with angular 示例仓库中使用 Angular CLI 的完整开发指南 导读 examples/with angular 是
构建工具开发工具CLI在 Vercel 仓库中基于 Angular 17 模板工程掌握 Angular CLI 全流程开发
在 Vercel 仓库中基于 Angular 17 模板工程掌握 Angular CLI 全流程开发 导读 本文以 Vercel 开源仓库 packages/s
CLI后端云原生
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考