Skip to content

archive-creator ​

Packs every file of the stream into one zip, tar or tar.gz archive with archiver and emits only the archive. Entries keep their paths relative to file.base, and their modification time and mode when the files came from disk. The archive is built in memory.

sh
npm install --save-dev @zilero/gulp-archive-creator

Usage ​

js
import { dest, src } from 'gulp';
import archiveCreator from '@zilero/gulp-archive-creator';

export const release = () =>
  src('dist/**', { encoding: false })
    .pipe(archiveCreator({ name: 'site.zip' }))
    .pipe(dest('releases'));

The format comes from the name, or from format:

js
archiveCreator({ name: 'site.tar.gz' }); // tgz, from the extension
archiveCreator({ name: 'releases/site', format: 'tgz' }); // releases/site.tar.gz
archiveCreator({ name: 'site.zip', archiverOptions: { zlib: { level: 9 } } }); // passed to archiver

Options ​

OptionTypeDefaultDescription
namestring'archive'The archive's path relative to the output folder: site.zip, releases/site.tar.gz. Without an extension the format's own is added.
format'zip' | 'tar' | 'tgz'from nameInferred from the extension of name (.zip, .tar, .tgz, .tar.gz), else zip. When both are given they must agree.
archiverOptionsZipOptions & TarOptions—Passed to archiver: zlib.level or store for zip, gzipOptions for tgz. Must be an object (Expected an object).
emptyArchivebooleanfalseEmit an empty archive when the stream had no files. By default nothing is emitted.
directoriesbooleanfalseAdd an entry for each directory in the stream (src('**') without nodir).
modifiedTimeDate—The modification time of every entry, for reproducible archives. Default: each file's stat.mtime, else 1980-01-01.

All options are optional, and unknown keys are an error. name must stay inside the output folder: an absolute path or one that leaves it, such as '../site.zip', is an error (Expected a path inside the output folder). So is a format that contradicts the extension of name: { name: 'a.zip', format: 'tar' } throws a.zip is a zip name, but format is tar: change one of them or drop format. Options are checked when the plugin is created.

The package also exports the types ArchiveCreatorOptions, ArchiveFormat and ArchiverOptions.

Notes ​

  • Read files with src(…, { encoding: false }): gulp 5 reads files as UTF-8 by default, which breaks images, fonts and other binary files.
  • The archive is placed relative to the base of the first file, so dest('releases') writes releases/site.zip.
  • format is useful with a name without a known extension ({ name: 'releases/site', format: 'tgz' } writes releases/site.tar.gz); with a known extension it must agree with it. Extensions are matched case-insensitively.
  • The archive is built in memory: every entry is compressed into a Buffer that is emitted at the end of the stream, so the archive must fit in memory. Streamed contents (buffer: false) are read entry by entry, but the result is still one Buffer.
  • Files read with buffer: false are archived from their stream.
  • Files without contents that are not directories (read: false, symbolic links) are skipped. Directories are skipped too unless directories is set. With directories, the base folder itself (src('dist') matches dist with an empty relative path) gets no entry, since it has no path inside the archive.
  • An error while reading streamed contents, or an error from archiver, fails the task with a PluginError named after this plugin; it is reported on the next file or at the end of the stream, and the process does not crash. archiver's warnings (a missing file, for example) fail the archive the same way rather than being ignored. After a failure, archiver is aborted, so the remaining entries are not read.
  • An empty stream emits nothing unless emptyArchive is set; the empty archive is then named relative to the current folder.

Reproducible archives ​

The same files give the same archive on every build, byte for byte, as long as the dates are stable:

  • files read from disk keep their stat.mtime, so they change the archive only when they change;
  • files without a stat (made by other plugins, such as a concatenated bundle) get a fixed 1980-01-01, the earliest date zip can store, instead of the time of the build;
  • modifiedTime gives every entry the same date, ignoring stat.mtime, for archives that depend only on the contents (CI builds from a fresh checkout, where every mtime is the checkout time).

zip stores dates in local time, so a zip is reproducible across machines in the same time zone; tar stores UTC.

js
archiveCreator({ name: 'site.tar.gz', modifiedTime: new Date('2026-01-01T00:00:00Z') });

Migrating ​

From gulp-zip, gulp-tar and gulp-gzip ​

gulp-zip, gulp-tar + gulp-gziparchive-creator
zip('site.zip')archiveCreator({ name: 'site.zip' })
zip(name, { compress: false })archiverOptions: { store: true }
zip(name, { modifiedTime })modifiedTime
zip(name, { buffer: false })not needed: the archive is one Buffer
tar('site.tar'), then gzip()archiveCreator({ name: 'site.tar.gz' })

From 1.x ​

  • Options are flat: { name, format, archiverOptions, emptyArchive, directories } instead of format, archiveOptions and pluginOptions: { archiveName, createDirectory, createEmptyArchive }.
  • format is no longer required: it is inferred from the extension of name.
  • tar.gz (tgz) is supported.
  • archiver 8 is used, streamed contents are supported and entries keep their modification time and mode.
  • After 2.0.0: modifiedTime is new, files without a stat get a fixed date instead of the build time, and a format that contradicts the extension of name is an error (2.0.0 wrote a tar named a.zip).

See migrating from 1.x for every package.

Released under the MIT License.