Front‑End Large File Upload: Principles, Key Features, and Using the enlarge‑file‑upload Library
This article explains the concept of large file upload in front‑end development, outlines the problems it solves, compares it with ordinary uploads, details essential implementation steps such as chunking, parallelism, resume, and integrity checks, and demonstrates practical usage of the enlarge‑file‑upload library across vanilla JavaScript, Vue2, Vue3, and React.
1. What Is Large File Upload?
(1) Definition
Large file upload means transferring very large files (tens of megabytes to gigabytes) from the client browser to a server, which traditional single‑request uploads cannot handle reliably because of network instability, time‑outs, and heavy server resource consumption.
(2) Problems Solved by Large File Upload
Unstable network: Chunked or resumable uploads can survive temporary disconnections and continue where they left off.
Server resource limits: By sending small pieces, memory and CPU usage on the server stay low, preventing crashes.
User experience: Progress bars, speed indicators, and resumable uploads keep users informed and avoid re‑uploading the whole file after an interruption.
File integrity verification: Hash checks ensure the uploaded file matches the original data.
(3) Advantages Over Ordinary Uploads
Can handle GB‑scale files through slicing.
Supports breakpoint resume, saving time and bandwidth.
Parallel uploading of multiple slices speeds up transfer.
Optimises server resource usage by processing small chunks.
Provides precise progress monitoring.
2. Key Front‑End Implementation Points
To implement large file upload on the front end you need to address the following features:
(1) File Chunking
Split the file into fixed‑size pieces (e.g., 1 MB or 5 MB) using File.slice() from the File API.
(2) Chunk Upload
Send each slice to the server via XMLHttpRequest or the Fetch API. Multiple slices can be uploaded concurrently for higher throughput.
(3) Resumable Upload
Persist the list of already‑uploaded chunks (e.g., via a hash or index) so that after a network break the client can continue uploading the remaining pieces.
(4) Progress Monitoring
Use the progress event of XMLHttpRequest or a ReadableStream with Fetch to calculate and display the overall percentage.
(5) File Integrity Check
After the whole file is uploaded, compute a hash (MD5, SHA‑256, etc.) on the client with FileReader and compare it with the server‑side hash.
(6) Error Handling & Retry
Implement per‑chunk retry logic and global error handling to recover from network or server errors.
(7) Concurrency Control
Limit the number of simultaneous requests (e.g., a pool of 5) to avoid saturating bandwidth or overloading the server.
(8) UX Optimisation
Show progress bars, upload speed, remaining time, and support drag‑and‑drop, multi‑file selection, and batch uploads.
(9) Security Considerations
Validate file type and size on the client, enforce HTTPS, and perform server‑side checks to prevent malicious uploads.
3. Recommended Library – enlarge-file-upload
Writing a full uploader from scratch is time‑consuming. The enlarge-file-upload package implements all the above features and works out‑of‑the‑box with Vue 2, Vue 3, React, or plain JavaScript.
Installation
npm install enlarge-file-uploadRun the command in your project directory; the library will be added to package.json.
Common Parameters
file: the File object to upload (required). serverUrl: endpoint that receives the chunk data. onProgress: callback receiving the overall progress percentage. onSuccess: called when the whole file finishes uploading. onError: receives error information for debugging.
Usage Examples
Vanilla JavaScript (jQuery) Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>File Upload</title>
</head>
<body>
<input type="file" id="fileInput" />
<button id="pauseButton">暂停上传</button>
<button id="resumeButton">继续上传</button>
<div id="progress">上传进度:0%</div>
<div id="speed">上传速度:0 MB/s</div>
<script src="https://cdn.jsdelivr.net/npm/enlarge-file-upload/dist/upload.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios"></script>
<script>
async function uploadFunction({ chunk, index, hash, cancelToken }) {
const formData = new FormData();
formData.append('chunk', chunk);
formData.append('hash', hash);
formData.append('index', index);
await axios.post('http://localhost:3000/api/users', formData, { cancelToken });
}
const config = {
chunkSize: 5 * 1024 * 1024, // 5 MB
concurrency: 5,
maxRetries: 3,
uploadFunction,
onProgress: (progress) => {
document.getElementById('progress').innerText = `上传进度:${progress.toFixed(2)}%`;
},
onSuccess: () => { console.log('上传完毕'); },
onSpeed: (speed) => { document.getElementById('speed').innerText = `上传速度:${speed}`; },
};
const { upload, pause, resume, state } = createUploader(config);
const fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', () => {
const file = fileInput.files[0];
upload(file);
});
document.getElementById('pauseButton').addEventListener('click', pause);
document.getElementById('resumeButton').addEventListener('click', resume);
</script>
</body>
</html>Vue 3 Example
<template>
<div>
<input type="file" @change="handleFileChange" />
<button @click="uploadFile">上传文件</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
import EnlargeFileUpload from 'enlarge-file-upload';
const fileRef = ref(null);
const handleFileChange = (e) => { fileRef.value = e.target.files[0]; };
const uploadFile = () => {
if (fileRef.value) {
const uploader = new EnlargeFileUpload({
file: fileRef.value,
serverUrl: 'http://your-server-url.com/upload',
onProgress: (p) => console.log(`上传进度: ${p}%`),
onSuccess: () => console.log('文件上传成功'),
onError: (e) => console.error('文件上传失败', e),
});
uploader.start();
}
};
</script>Vue 2 Example
<template>
<div>
<input type="file" @change="handleFileChange" />
<button @click="handlePause">暂停上传</button>
<button @click="handleResume">继续上传</button>
<div>上传进度:{{ progress.toFixed(2) }}%</div>
<div>上传速度:{{ speed }}</div>
</div>
</template>
<script>
import Vue from 'vue';
import { createUploader } from 'enlarge-file-upload';
import axios from 'axios';
export default Vue.extend({
data() {
return { progress: 0, speed: '0 MB/s', uploader: null };
},
methods: {
async uploadFunction({ chunk, index, hash, cancelToken }) {
const formData = new FormData();
formData.append('chunk', chunk);
formData.append('hash', hash);
formData.append('index', index.toString());
await axios.post('http://localhost:3000/api/users', formData, { cancelToken });
},
handleFileChange(e) {
const file = e.target.files?.[0];
if (file && this.uploader) this.uploader.upload(file);
},
handlePause() { if (this.uploader) this.uploader.pause(); },
handleResume() { if (this.uploader) this.uploader.resume(); },
},
created() {
const uploaderConfig = {
chunkSize: 5 * 1024 * 1024,
concurrency: 5,
maxRetries: 3,
uploadFunction: this.uploadFunction,
onProgress: (v) => { this.progress = v; },
onSuccess: () => console.log('上传完毕'),
onSpeed: (s) => { this.speed = s; },
};
this.uploader = createUploader(uploaderConfig);
},
});
</script>React Example
import React, { useRef, useMemo } from 'react';
import EnlargeFileUpload from 'enlarge-file-upload';
const FileUploadComponent = () => {
const fileInputRef = useRef(null);
const uploadFile = () => {
const file = fileInputRef.current.files[0];
if (file) {
const uploader = useMemo(() => new EnlargeFileUpload({
file,
serverUrl: 'http://your-server-url.com/upload',
onProgress: (p) => console.log(`上传进度: ${p}%`),
onSuccess: () => console.log('文件上传成功'),
onError: (e) => console.error('文件上传失败', e),
}), [file]);
uploader.start();
}
};
return (
<div>
<input type="file" ref={fileInputRef} />
<button onClick={uploadFile}>上传文件</button>
</div>
);
};
export default FileUploadComponent;React Hook Wrapper
import { useState, useCallback, useMemo } from 'react';
import { createUploader } from 'enlarge-file-upload';
import axios from 'axios';
export default function useFileUploader() {
const [progress, setProgress] = useState(0);
const [speed, setSpeed] = useState('0 MB/s');
const uploadFunction = useCallback(async ({ chunk, index, hash, cancelToken }) => {
const formData = new FormData();
formData.append('chunk', chunk);
formData.append('hash', hash);
formData.append('index', index);
await axios.post('http://localhost:3000/api/users', formData, { cancelToken });
}, []);
const uploaderConfig = useMemo(() => ({
chunkSize: 5 * 1024 * 1024,
concurrency: 5,
maxRetries: 3,
uploadFunction,
onProgress: (p) => setProgress(p),
onSuccess: () => console.log('Upload complete'),
onSpeed: (s) => setSpeed(s),
}), [uploadFunction]);
const uploader = useMemo(() => createUploader(uploaderConfig), [uploaderConfig]);
const uploadFile = useCallback((file) => uploader?.upload(file), [uploader]);
const pauseUpload = useCallback(() => uploader?.pause(), [uploader]);
const resumeUpload = useCallback(() => uploader?.resume(), [uploader]);
return { progress, speed, uploadFile, pauseUpload, resumeUpload };
}Large file upload is a crucial technique in front‑end development; understanding its principles and using a robust library like enlarge-file-upload can greatly improve user experience and reliability.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
