function serverlessZip(args) {
  const { artifactFilePath, directory, files } = args;

  const zip = archiver.create('zip');
  const output = fs.createWriteStream(artifactFilePath);

  return new BbPromise((resolve, reject) => {
    output.on('close', () => resolve(artifactFilePath));
    output.on('error', err => reject(err));
    zip.on('error', err => reject(err));

    output.on('open', () => {
      zip.pipe(output);

      // normalize both maps to avoid problems with e.g. Path Separators in different shells
      const normalizedFiles = _.uniq(_.map(files, file => path.normalize(file)));

      BbPromise.all(_.map(normalizedFiles, file => getFileContentAndStat.call(this, directory, file)))
        .then(contents => {
          _.forEach(
            contents.sort((content1, content2) => content1.filePath.localeCompare(content2.filePath)),
            file => {
              const name = file.filePath;
              // Ensure file is executable if it is locally executable or
              // we force it to be executable if platform is windows
              const mode = file.stat.mode & 0o100 || process.platform === 'win32' ? 0o755 : 0o644;
              zip.append(file.data, {
                name,
                mode,
                // necessary to get the same hash when zipping the same content
                // as well as `contents.sort` few lines above
                date: new Date(0)
              });
            }
          );

          return zip.finalize();
        })
        .catch(reject);
    });
  });
}
Copy pasted from Serverless

@see https://github.com/serverless/serverless/blob/63d54e1537e10ae63c171892edd886f6b81e83f6/lib/plugins/package/lib/zipService.js#L65