Photo by Florian Steciuk on Unsplash
I am developing a new feature of DeckDeckGo for which I have to unzip a data in Firebase Functions.
It took more time than expected to code such a Node.js function, that’s why I am sharing this solution, hoping it might help you some day too 😇.
Unzipper
Node.js provides a compression module Zlib but, it does not support ZIP files. Luckily, we can use the library unzipper to handle these.
npm i unzipper --save
Unzip With Async Await
My new feature reads and writes data uploaded in Firebase Storage through streams. I also develop my code with a promises (async / await) approach. Therefore, both have to coexist.
To narrow down the following example, I replaced the cloud storage with local files handled with file system streams (fs
).
The function unzip
instantiates a stream on the zip
data which is piped with unzipper
. Each entry are iterated and piped themselves to writable outputs. Summarized: the zip is opened and each files it contains are extracted.
unzip
is called in a retro compatible top await function and, that’s basically it 🥳.
const { Parse } = require("unzipper");
const { createWriteStream, createReadStream } = require("fs");
const unzip = () => {
const stream = createReadStream("/Users/david/data.zip").pipe(Parse());
return new Promise((resolve, reject) => {
stream.on("entry", (entry) => {
const writeStream = createWriteStream(`/Users/david/${entry.path}`);
return entry.pipe(writeStream);
});
stream.on("finish", () => resolve());
stream.on("error", (error) => reject(error));
});
};
(async () => {
try {
await unzip();
} catch (err) {
console.error(err);
}
})();
Read To String With Async Await
I had to read files with streams too. Consequently and cherry on top, here is how I integrated these in my code.
const { createReadStream } = require("fs");
const read = () => {
const stream = createReadStream("/Users/david/meta.json");
return new Promise((resolve, reject) => {
let data = "";
stream.on("data", (chunk) => (data += chunk));
stream.on("end", () => resolve(data));
stream.on("error", (error) => reject(error));
});
};
(async () => {
try {
const meta = await read();
console.log({ meta });
} catch (err) {
console.error(err);
}
})();
It follows the same approach as previously and read the file content to an in memory string
.
Summary
Coding is like a box of chocolates. You never know what you’re gonna get. Sometimes it should be quick, it takes time. Sometimes it should take so much time but, it goes fast — For-dev-rest Gump
To infinity and beyond!
David