I cannot find any any library that will do this inline and modify an already finalized zip. Here's a brute force approach that goes through the following steps:
- Create Temp Directory
- Extract Zip to Temp Dir
- Delete Original Zip
- Build Archive and seed with Temp Dir
- Callback to append any additional files
- Finalize Archive
- Delete Temp Directory
It uses extract-zip to unpack the zip and archiver to bundle it back up.
You can see the full source code at this repo KyleMit/append-zip
appendZip.js
// require modules
const fs = require('fs');
const fsp = fs.promises
const archiver = require('archiver');
const extract = require('extract-zip')
async function appendZip(source, callback) {
try {
let tempDir = source + "-temp"
// create temp dir (folder must exist)
await fsp.mkdir(tempDir, { recursive: true })
// extract to folder
await extract(source, { dir: tempDir })
// delete original zip
await fsp.unlink(source)
// recreate zip file to stream archive data to
const output = fs.createWriteStream(source);
const archive = archiver('zip', { zlib: { level: 9 } });
// pipe archive data to the file
archive.pipe(output);
// append files from temp directory at the root of archive
archive.directory(tempDir, false);
// callback to add extra files
callback.call(this, archive)
// finalize the archive
await archive.finalize();
// delete temp folder
fs.rmdirSync(tempDir, { recursive: true })
} catch (err) {
// handle any errors
console.log(err)
}
}
Usage
async function main() {
let source = __dirname + "/functions/func.zip"
await appendZip(source, (archive) => {
archive.file('data.json');
});
}
In the callback, you can append files to the archive using any of the methods available with node-archiver, for example:
// append a file from stream
const file1 = __dirname + '/file1.txt';
archive.append(fs.createReadStream(file1), { name: 'file1.txt' });
// append a file from string
archive.append('string cheese!', { name: 'file2.txt' });
// append a file from buffer
const buffer3 = Buffer.from('buff it!');
archive.append(buffer3, { name: 'file3.txt' });
// append a file
archive.file('file1.txt', { name: 'file4.txt' });
// append files from a sub-directory and naming it `new-subdir` within the archive
archive.directory('subdir/', 'new-subdir');
// append files from a sub-directory, putting its contents at the root of archive
archive.directory('subdir/', false);
// append files from a glob pattern
archive.glob('subdir/*.txt');
Further Reading