adm-zip、archiver、jszip、node-zip、zip-a-folder、zip-lib は、すべて Node.js 環境で ZIP ファイルの作成や展開を行うためのライブラリですが、設計思想と実行モデルが大きく異なります。adm-zip は同期処理に強く、archiver はストリーミング処理に最適化されています。jszip はブラウザと Node.js の両方で動作するユニバーサルな設計です。一方、node-zip は古い実装であり、zip-a-folder と zip-lib は特定のタスクに特化したラッパーライブラリです。
サーバーサイドでのファイル処理、バックアップシステムの構築、あるいはブラウザでのデータエクスポート機能。ZIP 圧縮はウェブ開発において頻繁に登場する要件です。しかし、adm-zip、archiver、jszip などの選択肢は多く、それぞれの実装モデルは大きく異なります。間違った選択は、メモリリークやパフォーマンス低下、あるいはブラウザでの動作不良につながります。
本稿では、主要な 6 つのパッケージを技術的に深掘りし、実際のコードを通じてその違いを明確にします。
ライブラリ選定で最も重要なのは、それがどのように処理を実行するかです。
adm-zip は同期処理を基本としています。
// adm-zip: 同期処理
const AdmZip = require('adm-zip');
const zip = new AdmZip();
zip.addLocalFolder('./data');
zip.writeZip('./archive.zip'); // ブロック発生
archiver はストリーミング処理に特化しています。
stream モジュールと相性が良く、大きなファイルでも安定します。// archiver: ストリーム処理
const archiver = require('archiver');
const output = fs.createWriteStream('./archive.zip');
const archive = archiver('zip');
archive.pipe(output);
archive.directory('./data', false);
archive.finalize(); // 非同期で完了
jszip は Promise ベースの非同期処理です。
async/await と相性が良く、処理完了を待ちやすい設計です。// jszip: Promise 処理
const JSZip = require('jszip');
const zip = new JSZip();
zip.file('hello.txt', 'Hello World');
zip.generateAsync({ type: 'nodebuffer' })
.then((content) => fs.writeFile('./archive.zip', content));
node-zip は古いコールバックスタイルです。
async/await 環境では扱いにくいです。// node-zip: 古い API
const NodeZip = require('node-zip');
const zip = new NodeZip();
// 現在の環境では動作しない可能性が高い
zip-a-folder と zip-lib は高レベルなラッパーです。
archiver や jszip など)を呼び出しています。// zip-a-folder: 簡易 API
const zipFolder = require('zip-a-folder');
await zipFolder.zip('./data', './archive.zip');
// zip-lib: 簡易 API
const zipLib = require('zip-lib');
await zipLib.zip('./data', './archive.zip');
どこでコードを動かすかも重要な選定基準です。
archiver と adm-zip は Node.js 専用です。ファイルシステムへのアクセスを前提としているため、ブラウザでは動作しません。jszip はユニバーサルです。ブラウザのメモリ上で ZIP を生成できるため、クライアント側でのエクスポート機能に最適です。zip-a-folder と zip-lib は主に Node.js 環境を想定しています。// jszip: ブラウザでの利用例
// CDN で読み込み可能
const zip = new JSZip();
zip.file('test.txt', 'content');
zip.generateAsync({ type: 'blob' })
.then((blob) => saveAs(blob, 'archive.zip')); // FileSaver.js 等と連携
パッケージのメンテナンス状況は、セキュリティと長期運用に直結します。
node-zip は明確に非推奨です。npm のページやリポジトリでメンテナンス停止のアナウンスがあります。新規プロジェクトで使用すべきではありません。adm-zip は長く維持されていますが、同期処理という設計上、大規模システムでの採用は慎重になるべきです。archiver と jszip はコミュニティが活発で、信頼性が高いです。zip-a-folder と zip-lib は単機能であるため、依存元ライブラリの状況に左右されます。各パッケージがどのようにファイルを追加するか見てみましょう。
// adm-zip
zip.addLocalFolder('./source');
// archiver
archive.directory('./source', false);
// jszip
// 再帰的な読み込みは別途実装が必要(fs.walk 等)
const content = fs.readFileSync('./file');
zip.file('file', content);
// node-zip
// 非推奨のため省略
// zip-a-folder
await zipFolder.zip('./source', './out.zip');
// zip-lib
await zipLib.zip('./source', './out.zip');
エラー処理の仕組みも異なります。
archiver はイベントベースです。error イベントをリスニングします。jszip は Promise の catch で扱います。adm-zip は try-catch ブロックで同期エラーを捕捉します。// archiver: イベントベース
archive.on('error', (err) => { throw err; });
// jszip: Promise ベース
generateAsync(...).catch((err) => console.error(err));
// adm-zip: 同期例外
try {
zip.writeZip('./out.zip');
} catch (err) {
console.error(err);
}
| 機能 | adm-zip | archiver | jszip | node-zip | zip-a-folder | zip-lib |
|---|---|---|---|---|---|---|
| 実行モデル | 同期 | ストリーム | Promise | コールバック | Promise | Promise |
| 環境 | Node.js | Node.js | Universal | Node.js | Node.js | Node.js |
| 大ファイル | 不向き | 最適 | 可 | 不向き | 可 | 可 |
| 保守状況 | 安定 | 安定 | 安定 | 非推奨 | 依存による | 依存による |
| API 難易度 | 易 | 中 | 中 | 易 | 易 | 易 |
プロジェクトの要件に応じて、以下のように選定してください。
archiver — — サーバー側で大きなファイルを処理する場合の第一選択です。ストリーミングによりメモリ効率が良く、本番環境での信頼性が高いです。
jszip — — ブラウザ側で処理が必要な場合、または Node.js とブラウザでコードを共有する場合に最適です。Promise ベースで扱いやすく、機能も豊富です。
adm-zip — — 小さなスクリプトや、同期処理が許容される管理ツールなどで使用します。シンプルさが魅力ですが、ウェブサーバーのメイン処理には避けるべきです。
node-zip — — 使用しないでください。非推奨であり、代替となる優れたライブラリが存在します。
zip-a-folder / zip-lib — — 単純なディレクトリ圧縮を素早く実装したい場合に有用です。ただし、内部依存や機能制限を理解した上で採用してください。
ZIP 処理ライブラリの選択は、単に「圧縮できるか」ではなく、「どこで」「どのように」「どの規模で」処理するかによって決まります。archiver と jszip が現代の標準であり、他の選択肢は特定のニッチな要件を満たすために存在します。アーキテクチャの安定性のためにも、保守が活発で設計が明確なライブラリを選ぶことが重要です。
adm-zip は、小規模なファイル操作やスクリプト実行に適しています。同期 API を提供するため、イベントループをブロックする可能性がありますが、設定が簡単で依存関係が少ない利点があります。大規模なファイルやサーバー側のストリーミング処理には向いていません。
archiver は、サーバー側で大きなファイルを処理する際に最適です。ストリーミングインターフェースを採用しているため、メモリ使用量を抑えながらデータをパイプできます。バックエンドのアップロード機能やログ圧縮など、本番環境の信頼性が求められる場面で選択すべきです。
jszip は、ブラウザ側での処理や、ユニバーサルなコードベースが必要な場合に最適です。Promise ベースの非同期 API を提供し、ファイルシステムに依存しないため、ウェブアプリでのクライアント側圧縮に適しています。
node-zip は非推奨パッケージです。メンテナンスが停止しており、セキュリティやパフォーマンスの面で現代の基準を満たしていません。新規プロジェクトでの使用は避け、jszip や archiver への移行を検討してください。
zip-a-folder は、特定のディレクトリを素早く圧縮したい場合に便利です。他のライブラリをラップしているため機能は限定されますが、設定の手間を省きたい単純なタスクには有効です。複雑な制御が必要な場合は不向きです。
zip-lib も同様に、簡易的な圧縮・展開操作に特化しています。Promise ベースの API を提供しますが、コミュニティやメンテナンス状況を確認した上で採用してください。大規模なシステムの中核としては、より標準的なライブラリを選ぶのが安全です。
ADM-ZIP is a pure JavaScript implementation for zip data compression for NodeJS.
With npm do:
$ npm install adm-zip
Electron file system support described below.
The library allows you to:
There are no other nodeJS libraries that ADM-ZIP is dependent of
var AdmZip = require("adm-zip");
// reading archives
var zip = new AdmZip("./my_file.zip");
var password = "1234567890";
var zipEntries = zip.getEntries(); // an array of ZipEntry records - add password parameter if entries are password protected
zipEntries.forEach(function (zipEntry) {
console.log(zipEntry.toString()); // outputs zip entries information
if (zipEntry.entryName == "my_file.txt") {
console.log(zipEntry.getData().toString("utf8"));
}
});
// outputs the content of some_folder/my_file.txt
console.log(zip.readAsText("some_folder/my_file.txt"));
// extracts the specified file to the specified location
zip.extractEntryTo(/*entry name*/ "some_folder/my_file.txt", /*target path*/ "/home/me/tempfolder", /*maintainEntryPath*/ false, /*overwrite*/ true);
// extracts everything
zip.extractAllTo(/*target path*/ "/home/me/zipcontent/", /*overwrite*/ true);
// creating archives
var zip = new AdmZip();
// add file directly
var content = "inner content of the file";
zip.addFile("test.txt", Buffer.from(content, "utf8"), "entry comment goes here");
// add local file
zip.addLocalFile("/home/me/some_picture.png");
// get everything as a buffer
var willSendthis = zip.toBuffer();
// or write everything to disk
zip.writeZip(/*target file name*/ "/home/me/files.zip");
// ... more examples in the wiki
For more detailed information please check out the wiki.
ADM-ZIP has supported electron original-fs for years without any user interractions but it causes problem with bundlers like rollup etc. For continuing support original-fs or any other custom file system module. There is possible specify your module by fs option in ADM-ZIP constructor.
Example:
const AdmZip = require("adm-zip");
const OriginalFs = require("original-fs");
// reading archives
const zip = new AdmZip("./my_file.zip", { fs: OriginalFs });
.
.
.