mlewis's avatar
Level 10

Large batch uploads with Livewire

I am upgrading an old system I built at the moment and have been moving pretty much all my old jQuery stuff into Livewire instead, but am bumping up against an issue when it comes to processing uploads which contain large numbers of files and was just wondering if I'm simply not going to be able to utilise Livewire for this.

So the requirement is that a user be able to upload up to 200 images at a time, and that these files in a worst case scenario may combine to weigh in at 2gb.

In an ideal scenario what I want to do is recognise that there are 200 files as they're dropped and upload them each individually to avoid timeout issues & display each file as it is processed. Unfortunately, it seems that the moment you drop them/hit submit, Livewire tries to process the entire post at once into it's temp directory. As such, with a huge overall upload it is then timing out and the component stops responding eventually - I've changed max upload time, post size etc. In order to get it to work at all (with smaller batches of say 30 files) I've had to whack the max upload limits and post size up really high on the server too which doesn't seem like the right approach... This still isn't ideal, as it is only once the whole post has processed does my upload component emit the 'uploaded' event to my listing table.

I used to handle this with Dropzone & jQuery (but then when I built this original system I also thought it was a good idea to make my own framework, so maybe Dz & jQuery was a poor choice too) - perhaps it is the case this can't be moved fully to Livewire?

Just looking for thoughts, rather than code samples - whether anyone has had this with LW and knows it is/isn't possible & a nod in the direction of where to read more.

Thanks in advance

0 likes
5 replies
bicicura's avatar

Hello there! Have you tried using Livewire + Filepond.js? Filepond is a file manager library that can be integrated with Livwire. Caleb Ponzio (One of livewire developers) has a video dedicated to this topic on his screencasts at https://laravel-livewire.com/screencasts/s5-integrating-with-filepond . Its a paid resource, yet I wanted you to know that it can be done and maybe with the customisatzion filepond provides, you can achieve what you want. Hope you can resolve it, bye!

1 like
mlewis's avatar
Level 10

@bicicura I hadn't come across filepond so far, will look into it - much appreciate the heads up. Will 'best answer' if it sorts me out & will post solution.

In meantime, any other suggestions welcome :)

1 like
bicicura's avatar

@mlewis Your welcome, if you need a hand while integrating filepond, just askkkk!

1 like
mlewis's avatar
Level 10

@bicicura So I ended up not using FilePond but I did come across what looked a very cool component as part of a large package for forms and livewire. https://randallwilk.dev/docs/laravel-form-components/v7/files/filepond

May be helpful for others in future.

The reason I opted against that was purely because from the docs I couldn't figure out how to handle errors for individual files nor how to clear files out of the Filepond list once they were processed - the uploading file by file was working fine.

As is always the case, if I had just been a bit more patient I'd have seen it was possible without further packages just by playing around a bit - Livewire references the javascript API in its docs and this was all I needed: https://laravel-livewire.com/docs/2.x/file-uploads#js-api

So to handle the huge file dumps without timeouts, I basically took the example here: https://f24aalam.medium.com/laravel-livewire-drag-n-drop-files-upload-using-alpinejs-37d5b80d3eb9

And edited the drop_file_component() function to be the following instead:

function drop_file_component() {
            return {
                droppingFile: false,
                handleFileDrop(e) {
                    if (e.dataTransfer.files.length > 0) {
                        const photos = e.dataTransfer.files;
                        ([...photos].forEach(uploadFile))

                        function uploadFile(file) {

                            const id = `${Date.now()}`
                            let listItem = document.createElement('li');
                            listItem.id = id;
                            listItem.textContent = `Uploading ${file.name}...`;
                            listItem.classList.add('bg-green-400','p-2','border','rounded','border-black',
                                'mb-2','text-white');
                            document.getElementById('fileList').appendChild(listItem);

                            @this.upload('photos', file, (uploadedFilename) => {
                                // Success callback.
                                document.getElementById(id).remove();
                            }, (error) => {
                                console.log(error);
                                // Error callback.
                            }, (event) => {
                                // Progress callback.
                                // event.detail.progress contains a number between 1 and 100 as the upload progresses.
                            })
                        }
                    }
                }
            };
        }

Also adding a fileList ul element underneath my upload form to display the queue of files remaining

<ul id="fileList" wire:ignore></ul>

In the actual Livewire component, I then validate the submission on updatedPhotos(), and have a custom rule to check mime and size, this allows me to return the file name of the files that fail rather than just photos.X.

The file handling is then standard livewire, and I simply emitUp an event to the parent photo gallery after each file is processed to push the newly stored image to the gallery.

1 like

Please or to participate in this conversation.