npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

jhl-large-file-upload

v1.0.2

Published

本项目基于 Vue 3 + TypeScript + Vite,目标是沉淀一个性能好、扩展性高、稳定性强的大文件上传前端基础设施,既可以以 npm 插件方式接入现有项目,也提供开箱即用的 Demo 页面便于调试与验证。

Readme

Vue 大文件分片上传组件(Vue 3 + TypeScript + Vite)

本项目基于 Vue 3 + TypeScript + Vite,目标是沉淀一个性能好、扩展性高、稳定性强的大文件上传前端基础设施,既可以以 npm 插件方式接入现有项目,也提供开箱即用的 Demo 页面便于调试与验证。

项目定位与目标

  • 面向大文件/超大文件上传场景,支持 GB 级文件稳定传输
  • 提供 UI + 逻辑一体的「开箱即用模式」,也提供仅暴露能力的「业务自定义模式」
  • 通过合理抽象 Props、事件和暴露方法,方便在不同业务中复用和二次封装
  • 与后端通过固定协议对接,降低前后端协同时的沟通成本

核心能力概览

  • 文件分片上传:前端按固定大小切片,控制并发数上传,降低大文件长连接风险
  • 断点续传:通过校验接口返回的已上传切片列表,实现中断后的续传
  • 秒传支持:利用文件 Hash 判断服务端是否已存在文件,避免重复上传
  • 进度可视化:单文件 Hash 进度、整体上传进度、切片网格状态一目了然
  • 并发调度:内置上传调度器,控制最大并发,支持暂停/恢复
  • SSE 合并结果通知:支持耗时合并任务的异步结果回传
  • 插槽扩展:内置 UI 可用,也可完全隐藏 UI,自定义触发入口和交互
  • 组件实例 API:通过 ref 获取内部上传列表、切片状态,进行业务侧联动

前端架构与角色

  • 上传组件核心:位于 src/components/Upload.vue,负责完整上传流程的编排,包括切片、Hash 计算、校验、分片上传、合并请求、SSE 监听等
  • Demo 页面:位于 src/App.vue,作为插件在真实业务中的使用示例,展示默认 UI + 插槽扩展的写法
  • 构建与开发:通过 Vite 提供本地开发、打包和预览能力,可在此基础上抽离为独立 npm 包发布

上传工作流(前端视角)

  1. 选择文件:通过默认按钮或插槽自定义入口触发原生 <input type="file">
  2. 文件切片:按配置的切片大小将文件切分为多个 Blob,对每个切片建立上传任务
  3. Hash 计算:在 Web Worker 中对所有切片进行 Hash 计算,避免阻塞主线程,并持续回传进度
  4. 上传前校验:调用后端校验接口,判断是否需要上传以及哪些切片已存在
  5. 分片上传:根据校验结果,仅上传缺失的切片,并按最大并发数调度请求,实时更新进度和状态
  6. 合并请求:所有切片上传完成后,向后端发送合并请求,必要时通过 SSE 监听合并结果
  7. 状态管理:在上传过程中维护文件级和切片级状态,支持暂停、恢复、取消以及记录删除等操作

Demo 项目运行说明

当前仓库中的 client 目录既包含上传组件实现,也包含一个 Demo 页面,方便在本地直接体验大文件上传流程:

  • 开发调试:在 client 目录执行 npm install 后运行 npm run dev,打开浏览器访问本地地址即可
  • 构建产物:执行 npm run build 生成构建结果,可用于后续封装发布或集成到其他系统
  • 预览构建:执行 npm run preview 本地预览 build 后的资源

作为 npm 插件的使用方式

1. 安装

npm i jhl-large-file-upload

2. 组件注册

全局注册

import { createApp } from "vue";
import App from "./App.vue";
import { Upload } from "jhl-large-file-upload";
import "jhl-large-file-upload/dist/style.css";

const app = createApp(App);
app.component("Upload", Upload);
app.mount("#app");

局部注册

import { Upload } from "jhl-large-file-upload";
import "jhl-large-file-upload/dist/style.css";

3. 基本用法(带 UI)

<template>
  <Upload
    :upload-url="uploadUrl"
    :sse-url="sseUrl"
    :headers="headers"
    :chunk-size="chunkSize"
    :max-concurrency="maxConcurrency"
    :show-ui="true"
  />
</template>

<script setup lang="ts">
import { Upload } from "jhl-large-file-upload";
import "jhl-large-file-upload/dist/style.css";

const uploadUrl = "http://localhost:8080";
const sseUrl = "http://localhost:8080/events";
const headers = {
  Authorization: "Bearer token",
};
const chunkSize = 5 * 1024 * 1024;
const maxConcurrency = 4;
</script>

4. 自定义入口(插槽)

<template>
  <Upload :upload-url="uploadUrl" :show-ui="false">
    <template #trigger="{ open, upload }">
      <button type="button" @click="open">选择文件</button>
      <input type="file" multiple @change="upload" />
    </template>
  </Upload>
</template>

5. 方法与数据暴露

import { ref } from "vue";
import type { UploadExpose } from "@your-org/vue-large-upload";

const uploaderRef = ref<UploadExpose | null>(null);

uploaderRef.value?.uploadFiles(files);
uploaderRef.value?.pauseUpload(fileId);
uploaderRef.value?.resumeUpload(fileId);
uploaderRef.value?.cancelUpload(fileId);

const fileState = uploaderRef.value?.getFileState(fileId);
const chunkState = uploaderRef.value?.getChunkState(fileId, chunkIndex);
const allFiles = uploaderRef.value?.fileList;

6. 事件流与回调

Props 回调(函数签名与参数说明)

  • onStart(item: FileUploadItem):单文件开始进入 Hash 计算时触发
  • onHashProgress(item: FileUploadItem, percentage: number):Hash 计算进度回调(0–100)
  • onVerified(item: FileUploadItem, shouldUpload: boolean, uploadedChunks: string[]):校验结果回调,包含是否需要上传以及已存在切片列表
  • onChunkProgress(item: FileUploadItem, chunkIndex: number, percentage: number):单切片上传进度回调
  • onChunkSuccess(item: FileUploadItem, chunkIndex: number):单切片上传成功回调
  • onChunkError(item: FileUploadItem, chunkIndex: number, error: unknown):单切片上传失败回调
  • onPaused(item: FileUploadItem):单文件被暂停时触发
  • onResumed(item: FileUploadItem):单文件从暂停恢复继续上传时触发
  • onCancel(item: FileUploadItem):单文件被取消上传时触发
  • onMerge(item: FileUploadItem):所有切片上传完成,正式发起合并请求时触发
  • onComplete(item: FileUploadItem):单文件整体完成(包含秒传场景)时触发
  • onError(item: FileUploadItem, error: unknown):单文件上传流程出现异常时触发

说明:FileUploadItem 与组件内部状态结构一致,可通过 UploadExpose.fileList 或回调参数中的 item 获取该文件的 Hash、进度、切片列表等完整信息。

Emits 事件(事件名与参数)

  • start(item: FileUploadItem)
  • hash-progress(item: FileUploadItem, percentage: number)
  • verified(item: FileUploadItem, shouldUpload: boolean, uploadedChunks: string[])
  • chunk-progress(item: FileUploadItem, chunkIndex: number, percentage: number)
  • chunk-success(item: FileUploadItem, chunkIndex: number)
  • chunk-error(item: FileUploadItem, chunkIndex: number, error: unknown)
  • paused(item: FileUploadItem)
  • resumed(item: FileUploadItem)
  • cancel(item: FileUploadItem)
  • merge(item: FileUploadItem)
  • complete(item: FileUploadItem)
  • error(item: FileUploadItem, error: unknown)

6. Props 说明

  • uploadUrl:上传服务基础地址(baseURL)
  • checkUrl:校验接口地址,默认 /check
  • uploadActionUrl:上传分片接口地址,默认 /upload
  • mergeUrl:合并接口地址,默认 /merge
  • cancelUrl:取消接口地址,默认 /cancel
  • sseUrl:SSE 地址,用于监听合并完成
  • headers:请求头,支持鉴权
  • chunkSize:切片大小,默认 5MB
  • maxConcurrency:最大并发数,默认 4
  • chunkRequestTimeout:单个切片请求超时时间(毫秒),默认 5000
  • chunkRetryCount:单个切片最大重试次数,默认 3
  • showUI:是否展示内置 UI,默认 true

7. Slot 说明

  • trigger:自定义上传入口,提供 open 与 upload 两个方法

8. 数据结构说明

  • fileList:所有文件的上传状态列表
  • getFileState:获取单文件状态(含 hash、进度、切片)
  • getChunkState:获取单切片状态

9. 后端接口对接文档

后端需要实现以下 4 个接口(路径可通过 Props 自定义),并遵循约定的参数和返回格式。

1. 校验接口 (Check)

  • Method: GET

  • URL: {uploadUrl}{checkUrl} (默认 /check)

  • Query Parameters: | 参数名 | 类型 | 说明 | | :--- | :--- | :--- | | filename | string | 原始文件名 | | fileHash | string | 文件完整 MD5 值 | | ext | string | 文件后缀名 (不含点) |

  • Response (JSON):

    {
      "shouldUpload": boolean,      // 是否需要上传(true: 需要上传/续传; false: 秒传完成)
      "uploadedChunks": string[]    // 已存在的切片Hash列表(用于断点续传)
    }

    兼容格式:也可以返回 { data: { shouldUpload, uploadedChunks } }

2. 切片上传接口 (Upload Chunk)

  • Method: POST

  • URL: {uploadUrl}{uploadActionUrl} (默认 /upload)

  • Content-Type: multipart/form-data

  • Body Parameters: | 参数名 | 类型 | 说明 | | :--- | :--- | :--- | | chunk | Blob | 切片二进制数据 | | chunkHash | string | 切片唯一标识 (目前使用切片索引) | | fileHash | string | 文件完整 MD5 值 | | index | string | 切片索引 (0, 1, 2...) |

  • Response:

    • HTTP Status 200 表示成功,Body 内容不限。

3. 合并接口 (Merge)

  • Method: POST

  • URL: {uploadUrl}{mergeUrl} (默认 /merge)

  • Content-Type: application/json

  • Body:

    • fileHash: string,文件完整 MD5 值
    • ext: string,文件后缀名
    • chunkSize: number,切片大小(字节)
  • Response:

    • 若不使用 SSE:HTTP 200 表示合并成功。
    • 若使用 SSE:HTTP 200 仅表示请求已接收,合并结果通过 SSE 推送。

4. SSE 监听接口 (Server-Sent Events)

  • Method: GET
  • URL: {sseUrl}?file_hash=<文件完整 MD5>
  • 说明: 用于耗时合并任务的异步通知,前端在建立 SSE 时会自动在 URL 上附加 file_hash 查询参数,后端需从该参数中获取文件标识。
  • Event Format(后端推送的数据结构):
    {
      "meta": {
        "type": "notify",
        "biz": "upload",
        "request_id": "",
        "session_id": "",
        "timestamp": 1234567890
      },
      "data": {
        "event": "upload_complete",
        "file_id": "任务唯一标识(UUID)",
        "file_hash": "文件完整MD5",
        "url": "文件访问地址",
        "status": "completed" // 或 "failed"
      }
    }

5. 取消接口 (Cancel)

  • Method: POST

  • URL: {uploadUrl}{cancelUrl} (默认 /cancel)

  • Content-Type: application/json

  • Body Parameters: | 参数名 | 类型 | 说明 | | :--- | :--- | :--- | | fileHash | string | 文件完整 MD5 值 | | filename | string | 原始文件名 |

  • Response:

    • HTTP 200 表示取消请求已接收(无论后端是否真实存在该任务,均应返回成功以保证前端流程不中断)。