Search code examples
javascriptnode.jsexpressdownloadadm-zip

Archive multiple files with Node and download it immediately


I'm trying to zip multiple files on a server and download it when user requests it. I am using adm-zip to zip files.

Files add perfectly fine and are zipped. zip.writeZip('') zipes files perfectly and saves them to local server. I am just unable to download them. Either way I think it would be better if I could send zip directly via buffer.

router.get(
  "/download-zip/:season_id/:club_id",
  passport.authenticate("jwt", { session: false }),
  (req, res) => {
    FileSubmission.find({
      season: req.params.season_id,
      club: req.params.club_id
    }).then(files => {

      const zip = new AdmZip();

      files.forEach(file => {
        // add local file
        zip.addLocalFile(`uploads/club-uploads/${file.club}/${file.name}`);
      });

      res.download(zip.toBuffer(), "asd.zip");
    });
  }
);

On the front I am using react with actions and js-file-download library


// Download ALL FILES by season ID and club ID
import fileDownload from "js-file-download";

export const downloadAllFiles = (season_id, club_id) => dispatch => {
  axios
    .get(`/api/files/download-zip/${season_id}/${club_id}`)
    .then(response => {
      fileDownload(response.data, `All Files- ${club_id}.zip`);
    })
    .catch(err => {
      console.log(err);
      dispatch({ type: GET_ERRORS, payload: err.response.data });
    });
};

Solution

  • Here's how I managed to create temporary archive, download it and delete it.

    Here's back-end

    // Create a ZIP of files uploaded by a club
    router.get(
      "/download-zip/",
      (req, res) => {
          zip.addLocalFile(/*ADD THE FILES TO ZIP*/);
    
          zip.writeZip(
            `temp/zips/temp-file.zip`,
            err => {
              if (err) {
                console.log(err);
              }
    
              res.download(
                `uploads/club-zips/test-file.zip`,
                function(err) {
                  if (!err) {
                    //delete file after it's been downloaded
                    fs.unlinkSync(
                      `uploads/club-zips/test-file-${req.params.club_id}.zip`
                    );
                  }
                }
              );
            }
          );
        });
      }
    );
    

    Here's what I use on front. As I said I used package called js-file-download to download blobs

    export const downloadAllFiles = () => dispatch => {
      axios
        .get(`/api/files/download-zip/`, {
          responseType: "arraybuffer"
        })
        .then(response => {
          fileDownload(response.data, `all-files.zip`);
        })
        .catch(err => {
          console.log(err);
        });
    };