Мне нужны JSZip и gzip для моей веб-страницы, и JSZip содержит все ингредиенты, но скрывает их так, что я не могу взломать - PullRequest
0 голосов
/ 26 ноября 2018

Поддержка gzip в JavaScript на удивление слабая.Все браузеры реализуют его для поддержки заголовка Content-encoding: gzip, но нет стандартного доступа к функции браузера gzip / gunzip.Так что нужно использовать только JavaScript-подход.Вокруг есть несколько старых библиотек gzip-js, но они, кажется, не поддерживают потоковую передачу и не требуют обслуживания в течение 6 лет.

Затем есть пакет, более активно поддерживаемый, но он также не видит включенный потокесли вы используете собственный дистрибутив, вам нужно хранить весь двоичный массив и вывод gzip в памяти.Я могу ошибаться, но это то, что я собираю.

JSZip - это хорошо разработанный инструмент, поддерживающий потоки «Рабочие».JSZip использует Пако.Записи в формате ZIP являются DEFLATEd и имеют контрольную сумму CRC32, как и в gzip, но, разумеется, немного иначе.Просто взглянув на исходники JSZip, похоже, что было бы легко выставить опцию сжатия pzo gzip в потоковую поддержку JSZip.И если я использую как JSZip, так и мне нужен gzip, зачем мне загружать pako дважды?

Я надеялся, что смогу просто проникнуть внутрь JSZip к базовым Workers и использовать основанную на pako реализацию «Flate» (т.е. in-flate / de-flate) с опознанной опцией gzipПако.Исследовал его с помощью консоли Chrome Javascript, но я не могу дозвониться.Распространяемый загружаемый jszip.js или jszip-min.js скрывают все внутренние компоненты от доступа к сценариям.Я не могу открыть эту коробку.

Поэтому я посмотрел исходный код git hub, чтобы посмотреть, смогу ли я создать свой собственный загружаемый модуль jszip.js или jszip-min.js, куда я бы экспортировал больше внутренних ресурсов для использования на своей странице.Но, проработав 20 лет в UNIX, создаю файлы, ant, все, я чувствую себя новичком, когда дело доходит до этих трюков по упаковке модулей javascript, и я вижу bower и gruntfiles, которые, похоже, связаны с узлом..js, который мне не нужен (только клиентский браузер) и с которым никогда не работал, поэтому я понятия не имею, с чего начать.

1 Ответ

0 голосов
/ 27 ноября 2018

Как говорил Эверт, я должен был сначала проверить инструкции по сборке в документации https://stuk.github.io/jszip/documentation/contributing.html.

Из этого ясно, что сначала нужно git и сделать локальный клон.Затем необходимо настроить командную строку grunt, для которой требуется npm, поставляемый с nodejs.После запуска grunt появляются другие зависимости, которые необходимо установить npm.Это обычные мелочи, и они не работают, но достаточно Googling и грубой силы, которые пытаются это сделать.

Теперь jszip / lib / index.js содержит ресурс, который окончательно экспортируется.Это тот самый объект JSZip.Так что, просто чтобы поиграть с внутренним материалом, я мог бы добавить их к объекту JSZip, например, он уже содержит:

JSZip.external = require("./external");
module.exports = JSZip;

, и поэтому мы можем легко добавить другие ресурсы, с которыми мы хотим поиграть:

JSZip.flate = require("./flate");
JSZip.DataWorker = require('./stream/DataWorker');
JSZip.DataLengthProbe = require('./stream/DataLengthProbe');
JSZip.Crc32Probe = require('./stream/Crc32Probe');
JSZip.StreamHelper = require('./stream/StreamHelper');
JSZip.pako = require("pako");

Теперь с этим я могу создать подтверждение концепции в отладчике Chrome:

(new JSZip.StreamHelper(
   (new JSZip.DataWorker(Promise.resolve("Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!")))
      .pipe(new JSZip.DataLengthProbe("uncompressedSize"))
      .pipe(new JSZip.Crc32Probe())
      .pipe(JSZip.flate.compressWorker({}))
      .pipe(new JSZip.DataLengthProbe("compressedSize"))
      .on("end", function(event) { console.log("onEnd: ", this.streamInfo) }), 
   "uint8array", "")
).accumulate(function(data) { console.log("acc: ", data); })
 .then(function(data) { console.log("then: ", data); })

, и это работает.Я делаю себе GZipFileStream с заголовком gzip и трейлером, создавая все правильно.Я помещаю jszip / lib / generate / GZipFileWorker.js следующим образом:

'use strict';

var external = require('../external');
var utils = require('../utils');
var flate = require('../flate');
var GenericWorker = require('../stream/GenericWorker');
var DataWorker = require('../stream/DataWorker');
var StreamHelper = require('../stream/StreamHelper');
var DataLengthProbe = require('../stream/DataLengthProbe');
var Crc32Probe = require('../stream/Crc32Probe');

function GZipFileWorker() {
    GenericWorker.call(this, "GZipFileWorker");
    this.virgin = true;
}
utils.inherits(GZipFileWorker, GenericWorker);

GZipFileWorker.prototype.processChunk = function(chunk) {
    if(this.virgin) {
        this.virgin = false;
        var headerBuffer = new ArrayBuffer(10);
        var headerView = new DataView(headerBuffer);
        headerView.setUint16(0, 0x8b1f, true); // GZip magic
        headerView.setUint8(2, 0x08); // compression algorithm DEFLATE
        headerView.setUint8(3, 0x00); // flags
        // bit 0   FTEXT
        // bit 1   FHCRC
        // bit 2   FEXTRA
        // bit 3   FNAME
        // bit 4   FCOMMENT
        headerView.setUint32(4, (new Date()).getTime()/1000>>>0, true);
        headerView.setUint8(8, 0x00); // no extension headers
        headerView.setUint8(9, 0x03); // OS type UNIX
        this.push({data: new Uint8Array(headerBuffer)});
    }
    this.push(chunk);
};

GZipFileWorker.prototype.flush = function() {
    var trailerBuffer = new ArrayBuffer(8);
    var trailerView = new DataView(trailerBuffer);
    trailerView.setUint32(0, this.streamInfo["crc32"]>>>0, true);
    trailerView.setUint32(4, this.streamInfo["originalSize"]>>>0 & 0xffffffff, true);
    this.push({data: new Uint8Array(trailerBuffer)});
};

exports.gzip = function(data, inputFormat, outputFormat, compressionOptions, onUpdate) {
    var mimeType = data.contentType || data.mimeType || "";
    if(! (data instanceof GenericWorker)) {
        inputFormat = (inputFormat || "").toLowerCase();
        data = new DataWorker(
            utils.prepareContent(data.name || "gzip source",
                                 data,
                                 inputFormat !== "string",
                                 inputFormat === "binarystring",
                                 inputFormat === "base64"));
    }
    return new StreamHelper(
        data
            .pipe(new DataLengthProbe("originalSize"))
            .pipe(new Crc32Probe())
            .pipe(flate.compressWorker( compressionOptions || {} ))
            .pipe(new GZipFileWorker()),
        outputFormat.toLowerCase(), mimeType).accumulate(onUpdate);
};

и в jszip / lib / index.js мне нужно только это:

var gzip = require("./generate/GZipFileWorker");
JSZip.gzip = gzip.gzip;

и этоработает так:

JSZip.gzip("Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!", "string", "base64", {level: 3}).then(function(result) { console.log(result); })

Я могу вставить результат в конвейер UNIX следующим образом:

$ echo -n "H4sIAOyR/VsAA/NIzcnJVwjPL8pJUVTwoJADAPCORolNAAAA" |base64 -d |zcat

, и он правильно возвращает

Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!

Это также можетиспользовать с файлами:

JSZip.gzip(file, "", "Blob").then(function(blob) { 
     xhr.setRequestProperty("Content-encoding", "gzip");
     xhr.send(blob); 
  })

, и я могу отправить большой двоичный объект на мой веб-сервер.Я проверил, что действительно большой файл обрабатывается кусками.

Единственное, что мне не нравится в этом, это то, что последний BLOB-объект все еще собран как один большой BLOB-объект, поэтому я предполагаю, что он хранит все сжатые данные в памяти.Было бы лучше, если бы этот Blow был конечной точкой этого конвейера Worker, чтобы, когда xhr.send собирал данные из BLOB-объекта в виде фрагментов, только тогда он получал бы фрагменты из конвейера Worker.Тем не менее, влияние значительно уменьшается, учитывая, что он содержит только сжатый контент, и, вероятно, большие (по крайней мере, для меня) файлы будут мультимедийными, и в любом случае их не нужно будет сжать gzip.

IЯ не написал функцию gunzip, потому что, честно говоря, мне она не нужна, и я не хочу создавать такую, которая не сможет правильно анализировать заголовки расширений в заголовках gzip.Как только я загрузил сжатый контент на сервер (в моем случае S3), когда я получаю его снова, я предполагаю, что браузер выполнит распаковку для меня.Я не проверял это все же.Если это станет проблемой, я вернусь и отредактирую этот ответ подробнее.

Вот мой форк на github: https://github.com/gschadow/jszip, запрос на ввод уже введен.

...