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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@iimm/s3-uploader

v1.6.0

Published

s3-uploader react component

Downloads

6

Readme

@iimm/s3-uploader

NPM version NPM downloads

学习阶段自定义的尝试用来进行本地minio s3 分片(分片默认大小是为5M)上传的react组件;使用了mui ahooks tabler-icons等,支持并发分片上传和断点续传(需后端支持),为了安全起见,除了分片上传阶段,不会与s3服务器直接交互,分片上传阶段的直接交互应使用临时授权的preSignedUrl。当然可以通过传入自定义的s3PreUploadRequest、s3PartUploadRequest、s3CompleteUploadRequest等来实现自定义方式。

文件分片上传流程

默认情况下是分片上传:

文件校验(validate,使用fileCheck和isSameFile进行检查) => md5计算 => 初始化(preUpload,与后端交互) => 分片上传(partUpload,直接上传到s3服务器) => 合并文件(completeUpload,与后端交互) => 完成

预处理阶段需要后端进行检查该文件是否已上传过(根据md5和文件size),如果:

  • ①已上传过且完成了则直接返回相应信息
  • ②已上传过但未完全上传则返回各分片的上传进度信息,其中未上传完成的分片会返回直接上传到s3的url
  • ③未上传则直接创建分片上传任务,返回

注意:返回的分片任务是完整的PartNumber从1到Math.ceil(size/chunkSize)的任务信息

分片上传阶段会并发(默认为3)发起分片上传(允许暂停),全部完成后通知后端,后端会通知s3服务器合并,完成后后端返回url等信息

文件直接上传

directUpload=true时,在文件大小不大于directUploadMaxSize(默认值为4M)会跳过分片上传和合并文件阶段。

文件校验(validate,使用fileCheck和isSameFile进行检查) => md5计算 => 初始化(preUpload,与后端交互,同时完成文件上传) => 完成

效果图

预览图

Interface

完整类型见类型定义: src/interface/index.ts [https://github.com/liudichen/s3-uploader/blob/master/src/interface/index.ts]

单个文件条目的类型:

interface UploadFile {
  file?: File;
  /**文件名, File.name*/
  name: string;
  /**文件类型,即 File.type */
  type?: string;
  /** 文件上传或校验过程的错误文本 */
  err?: string;
  /** 错误类型,揭示哪个阶段发生了错误 */
  errType?: "validate" | "md5" | "preUpload" | "completeUpload" | "partUpload";
  /** 已上传完毕? */
  done?: boolean;
  md5?: string;
  /** 文件上传任务的数据库表id */
  id?: string;
  /** 文件上传后的归档数据库id */
  s3?: string;
  /**分片上传任务的s3 UploadId */
  uploadId?: string;
  /**文件大小,即 File.size */
  size: number;
  /**分片总数量,仅文件之前未完整上传时有(可选) */
  count?: number;
  /** 服务器中在本次上传前已存在上传完成的文件?*/
  exist?: boolean;
  /** 后端返回分片上传任务(如果有任务则会完整返回PartNumber从1到Math.ceil(size/chunkSize)所有分片的任务信息,未完成的会有直接上传的url),done=true时会被清空 */
  parts?: S3PreUploadPart[];
  /**文件是否被选择,当开启了文件选择时有意义
   * @default false
   */
  checked?: boolean;
  /**当成功时返回的存储桶名 */
  Bucket?: string;
  /**当成功时返回的实际文件路径,注意文件名可能与当前文件名不一致 */
  Key?: string;
  /**当成功时返回的版本id */
  VersionId?: string;
  /** 当成功时返回的在s3中的临时访问url */
  url?: string;
}

组件与子组件(每个文件)公用的部分props:

interface S3RelateItemProps {
  /** 启用直接上传?(file.szie小于等于directUploadMaxSize)
   * @default false
   */
  directUpload?: boolean;
  /**
   * 直接上传最大文件大小
   * @default 1194304='4M'
   */
  directUploadMaxSize?: number;
  /**分片上传的分片大小,minio默认为5M
   * @default 5242880='5M'
   */
  chunkSize?: number;
  /** 文件可预览? */
  preview?: boolean;
  /**预览文件的组件(推荐是弹窗之类不占用文档流) */
  PreviewRender?: FilePreviewComponent;

  /**显示文件可选择项 */
  selectable?: boolean;
  /**文件多选还是单选
   * @default 'multiple'
   */
  selectType?: "single" | "multiple";
  /** 上传文件来源平台*/
  platform: string;
  /** 平台上的某一应用 */
  app?: string;
  /**手动指定桶名,实际并不一定会使用(如果其它桶中已上传的情况下) */
  bucket?: string;
  /**文件在桶中的存储路径 */
  filePrefix?: string;
  /**文件上传前检查文件在服务器中状态或任务的url */
  s3PreUploadUrl: string;
  /**文件分片全部上传后通知合并的url */
  s3CompleteUploadUrl: string;
  /**取消分片任务的url */
  s3AbortUploadUrl?: string;
  /**文件上传前的请求,检查服务器是否已存在文件,如果存在直接返回结果,不存在则返回创建的分片上传任务,有内置的,需要自定替换 */
  s3PreUploadRequest?: S3PreUploadRequestFn;
  /**向s3生成的单个分片上传任务上传文件的请求,按api这应该是个PUT请求,url是s3PreUploadRequest返回的parts中携带的 */
  s3PartUploadRequest?: S3PartUploadRequestFn;
  /** 当所有分片上传后通知服务进行分片合并的请求 */
  s3CompleteUploadRequest?: S3CompleteUploadRequestFn;
  /** 取消分片上传任务的请求,当前并没有去实现,采用的是任务设置失效时间的方式 */
  s3AbortUploadRequest?: S3AbortUploadRequestFn;

  /**当返回0时表示md5在计算过程中手动终止,false表示出错了 */
  md5Getter?: Md5GetterFn;

  /**axios baseURL */
  baseURL?: string;
  /**axios请求的超时时间(ms)
   * @default 15000 = 15s
   */
  timeout?: number;

  /** 渲染文档图标的组件,可选,有内置的默认组件*/
  FileIconRender?: ComponentType<FileIconRenderProps>;

  /**分片上传并发数量限制
   * @default 3
   */
  limit?: number;
  /** 请求及请求返回的url地址在请求前或存进value前的转换函数,如果不传或没有返回值,则使用原始值 */
  urlConvert?: UrlConvertFn;
  /**达到并发限制时,等待多少ms再次进行检查是否达到并发数量限制
   * @default 1000
   */
  chunkWaitTime?: number;
  /**文件上传的额外的s3 MetaData */
  meta?: Record<string, number | string>;
  uploader?: string;
  uploaderName?: string;
}

父组件props:

interface S3UploaderProps
  extends Partial<Omit<DropzoneOptions, "onDropAccepted" | "multiple">>,
    S3RelateItemProps {
  value?: UploadFile[];
  onChange?: (v: UploadFile[]) => void;
  defaultValue?: UploadFile[];
  error?: boolean;
  readOnly?: boolean;

  /**返回候选可以上传的文件数组 */
  onDropAccepted?:
    | (<T extends File>(files: T[], event: DropEvent) => Promise<File[]>)
    | (<T extends File>(files: T[], event: DropEvent) => File[]);

  /**应用于根组件 Stack */
  className?: string;

  /**应用于上传或拖拽区根div组件 */
  uploadZoneClassName?: string;

  /** 应用于每个子文件组件的根Box组件 */
  uploadItemClassName?: string;

  /** 判断是否是同一文件的方法,如果返回true则该文件与已有文件相同,不能添加 */
  isSameFile?: IsSameFileFn;

  /**触发DropZone的元素节点 */
  dropZoneTrigger?: ReactNode;

  /**校验文件本身是否满足要求,如果不满足返回不满足的字符串否则返回空字符串或无返回值,不满足要求的 */
  fileChecker?: ((file: File) => string | undefined) | ((file: File) => Promise<string | undefined>);
}

LICENSE

MIT