♻️ Replace jszip usage with zip.js library

This commit is contained in:
Andrey Antukh 2025-05-08 15:54:28 +02:00
parent 4c487834f0
commit 36b162b4fa
5 changed files with 117 additions and 75 deletions

View file

@ -0,0 +1,18 @@
diff --git a/lib/zip-fs.js b/lib/zip-fs.js
index 1444c0f00e5f1ad6c13521f90a7f3c6659d81116..90e38baef5365c2abbcb9337f7ab37f800e883a4 100644
--- a/lib/zip-fs.js
+++ b/lib/zip-fs.js
@@ -33,12 +33,7 @@ import { initShimAsyncCodec } from "./core/util/stream-codec-shim.js";
import { terminateWorkers } from "./core/codec-pool.js";
let baseURL;
-try {
- baseURL = import.meta.url;
- // eslint-disable-next-line no-unused-vars
-} catch (_) {
- // ignored
-}
+
configure({ baseURL });
configureWebWorker(configure);

View file

@ -14,7 +14,8 @@
"url": "https://github.com/penpot/penpot" "url": "https://github.com/penpot/penpot"
}, },
"resolutions": { "resolutions": {
"@vitejs/plugin-react": "^4.2.0" "@vitejs/plugin-react": "^4.2.0",
"@zip.js/zip.js@npm:^2.7.44": "patch:@zip.js/zip.js@npm%3A2.7.60#~/.yarn/patches/@zip.js-zip.js-npm-2.7.60-b6b814410b.patch"
}, },
"scripts": { "scripts": {
"build:app:assets": "node ./scripts/build-app-assets.js", "build:app:assets": "node ./scripts/build-app-assets.js",
@ -108,11 +109,11 @@
"@penpot/svgo": "penpot/svgo#v3.1", "@penpot/svgo": "penpot/svgo#v3.1",
"@penpot/text-editor": "portal:./text-editor", "@penpot/text-editor": "portal:./text-editor",
"@tokens-studio/sd-transforms": "1.2.11", "@tokens-studio/sd-transforms": "1.2.11",
"@zip.js/zip.js": "patch:@zip.js/zip.js@npm%3A2.7.60#~/.yarn/patches/@zip.js-zip.js-npm-2.7.60-b6b814410b.patch",
"compression": "^1.7.5", "compression": "^1.7.5",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"eventsource-parser": "^3.0.1", "eventsource-parser": "^3.0.1",
"js-beautify": "^1.15.4", "js-beautify": "^1.15.4",
"jszip": "^3.10.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"lodash.debounce": "^4.0.8", "lodash.debounce": "^4.0.8",
"luxon": "^3.6.1", "luxon": "^3.6.1",

View file

@ -5,32 +5,82 @@
;; Copyright (c) KALEIDOS INC ;; Copyright (c) KALEIDOS INC
(ns app.util.zip (ns app.util.zip
"Helpers for make zip file (using jszip)." "Helpers for make zip file."
(:require (:require
["jszip" :as zip] ["@zip.js/zip.js" :as zip]
[app.util.array :as array]
[promesa.core :as p])) [promesa.core :as p]))
(defn load (defn reader
[data] [blob]
(zip/loadAsync data)) (cond
(instance? js/Blob blob)
(let [breader (new zip/BlobReader blob)]
(new zip/ZipReader breader))
(defn get-file (instance? js/Uint8Array blob)
"Gets a single file from the zip archive" (let [breader (new zip/Uint8ArrayReader blob)
([zip path] zreader (new zip/ZipReader breader #js {:useWebWorkers false})]
(get-file zip path "text")) zreader)
([zip path type] (instance? js/ArrayBuffer blob)
(let [entry (.file zip path)] (reader (js/Uint8Array. blob))
(cond
(nil? entry)
(p/rejected (str "File not found: " path))
(.-dir ^js entry) :else
(p/resolved {:dir path}) (throw (ex-info "invalid arguments"
{:type :internal
:code :invalid-type}))))
:else (defn blob-writer
(->> (.async ^js entry type) [& {:keys [mtype]}]
(p/fmap (fn [content] (new zip/BlobWriter (or mtype "application/octet-stream")))
;; (js/console.log "zip:process-file" 2 content)
{:path path (defn bytes-writer
:content content}))))))) []
(new zip/Uint8ArrayWriter))
(defn writer
[stream-writer]
(new zip/ZipWriter stream-writer))
(defn add
[writer path content]
(assert (instance? zip/ZipWriter writer))
(cond
(instance? js/Uint8Array content)
(.add writer path (new zip/Uint8ArrayReader content))
(instance? js/ArrayBuffer content)
(.add writer path (new zip/Uint8ArrayReader
(new js/Uint8Array content)))
(instance? js/Blob content)
(.add writer path (new zip/BlobReader content))
(string? content)
(.add writer path (new zip/TextReader content))
:else
(throw (ex-info "invalid arguments"
{:type :internal
:code :invalid-type}))))
(defn get-entry
[reader path]
(assert (instance? zip/ZipReader reader))
(->> (.getEntries ^zip/ZipReader reader)
(p/fmap (fn [entries]
(array/find #(= (.-filename ^js %) path) entries)))))
(defn read-as-text
[entry]
(let [writer (new zip/TextWriter)]
(.getData entry writer)))
(defn close
[closeable]
(assert (or (instance? zip/ZipReader closeable)
(instance? zip/ZipWriter closeable)))
(.close ^js closeable))

View file

@ -30,9 +30,9 @@
(def conjv (fnil conj [])) (def conjv (fnil conj []))
(defn- read-zip-manifest (defn- read-zip-manifest
[zipfile] [zip-reader]
(->> (rx/from (uz/get-file zipfile "manifest.json")) (->> (rx/from (uz/get-entry zip-reader "manifest.json"))
(rx/map :content) (rx/mapcat uz/read-as-text)
(rx/map json/decode))) (rx/map json/decode)))
(defn slurp-uri (defn slurp-uri
@ -121,14 +121,15 @@
(let [mtype (parse-mtype body)] (let [mtype (parse-mtype body)]
(cond (cond
(= "application/zip" mtype) (= "application/zip" mtype)
(->> (rx/from (uz/load body)) (let [zip-reader (uz/reader body)]
(rx/merge-map read-zip-manifest) (->> (read-zip-manifest zip-reader)
(rx/map (rx/map
(fn [manifest] (fn [manifest]
(if (= (:type manifest) "penpot/export-files") (if (= (:type manifest) "penpot/export-files")
(let [manifest (decode-manifest manifest)] (let [manifest (decode-manifest manifest)]
(assoc file :type :binfile-v3 :files (:files manifest))) (assoc file :type :binfile-v3 :files (:files manifest)))
(assoc file :type :legacy-zip :body body))))) (assoc file :type :legacy-zip :body body))))
(rx/finalize (partial uz/close zip-reader))))
(= "application/octet-stream" mtype) (= "application/octet-stream" mtype)
(rx/of (assoc file :type :binfile-v1)) (rx/of (assoc file :type :binfile-v1))

View file

@ -2881,10 +2881,17 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@zip.js/zip.js@npm:^2.7.44": "@zip.js/zip.js@npm:2.7.60":
version: 2.7.53 version: 2.7.60
resolution: "@zip.js/zip.js@npm:2.7.53" resolution: "@zip.js/zip.js@npm:2.7.60"
checksum: 10c0/883527bf09ce7c312117536c79d5f07e736d87de802a6c19e39ba2e18027499dcb9359df94dfde13c9bcf6118a20b4f26a40f9892ee82d7cac3124d6986b15c8 checksum: 10c0/466ff1729e36d9f500011475e230f2edb9c0e6e10f64d542e6ebc006dc70885bc909d69fd0c7b10126bdf722c761359ad1edfe295b6c7fed3169f0f63012a1cd
languageName: node
linkType: hard
"@zip.js/zip.js@patch:@zip.js/zip.js@npm%3A2.7.60#~/.yarn/patches/@zip.js-zip.js-npm-2.7.60-b6b814410b.patch":
version: 2.7.60
resolution: "@zip.js/zip.js@patch:@zip.js/zip.js@npm%3A2.7.60#~/.yarn/patches/@zip.js-zip.js-npm-2.7.60-b6b814410b.patch::version=2.7.60&hash=4a67b2"
checksum: 10c0/37e9a5dd708fd81b08d64b75ea44d70c903071165bbbc571fca7a1cb93f214fab6f63ed3c837a87a0205a6301bc78790c1505197570f112afa5311e3a16d2368
languageName: node languageName: node
linkType: hard linkType: hard
@ -5705,6 +5712,7 @@ __metadata:
"@storybook/test-runner": "npm:^0.21.0" "@storybook/test-runner": "npm:^0.21.0"
"@tokens-studio/sd-transforms": "npm:1.2.11" "@tokens-studio/sd-transforms": "npm:1.2.11"
"@types/node": "npm:^22.12.0" "@types/node": "npm:^22.12.0"
"@zip.js/zip.js": "patch:@zip.js/zip.js@npm%3A2.7.60#~/.yarn/patches/@zip.js-zip.js-npm-2.7.60-b6b814410b.patch"
autoprefixer: "npm:^10.4.20" autoprefixer: "npm:^10.4.20"
compression: "npm:^1.7.5" compression: "npm:^1.7.5"
concurrently: "npm:^9.1.2" concurrently: "npm:^9.1.2"
@ -5724,7 +5732,6 @@ __metadata:
gulp-svg-sprite: "npm:^2.0.3" gulp-svg-sprite: "npm:^2.0.3"
js-beautify: "npm:^1.15.4" js-beautify: "npm:^1.15.4"
jsdom: "npm:^26.1.0" jsdom: "npm:^26.1.0"
jszip: "npm:^3.10.1"
lodash: "npm:^4.17.21" lodash: "npm:^4.17.21"
lodash.debounce: "npm:^4.0.8" lodash.debounce: "npm:^4.0.8"
luxon: "npm:^3.6.1" luxon: "npm:^3.6.1"
@ -6386,13 +6393,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"immediate@npm:~3.0.5":
version: 3.0.6
resolution: "immediate@npm:3.0.6"
checksum: 10c0/f8ba7ede69bee9260241ad078d2d535848745ff5f6995c7c7cb41cfdc9ccc213f66e10fa5afb881f90298b24a3f7344b637b592beb4f54e582770cdce3f1f039
languageName: node
linkType: hard
"immutable@npm:^5.0.2": "immutable@npm:^5.0.2":
version: 5.0.3 version: 5.0.3
resolution: "immutable@npm:5.0.3" resolution: "immutable@npm:5.0.3"
@ -7686,18 +7686,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"jszip@npm:^3.10.1":
version: 3.10.1
resolution: "jszip@npm:3.10.1"
dependencies:
lie: "npm:~3.3.0"
pako: "npm:~1.0.2"
readable-stream: "npm:~2.3.6"
setimmediate: "npm:^1.0.5"
checksum: 10c0/58e01ec9c4960383fb8b38dd5f67b83ccc1ec215bf74c8a5b32f42b6e5fb79fada5176842a11409c4051b5b94275044851814a31076bf49e1be218d3ef57c863
languageName: node
linkType: hard
"klaw-sync@npm:^6.0.0": "klaw-sync@npm:^6.0.0":
version: 6.0.0 version: 6.0.0
resolution: "klaw-sync@npm:6.0.0" resolution: "klaw-sync@npm:6.0.0"
@ -7728,15 +7716,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"lie@npm:~3.3.0":
version: 3.3.0
resolution: "lie@npm:3.3.0"
dependencies:
immediate: "npm:~3.0.5"
checksum: 10c0/56dd113091978f82f9dc5081769c6f3b947852ecf9feccaf83e14a123bc630c2301439ce6182521e5fbafbde88e88ac38314327a4e0493a1bea7e0699a7af808
languageName: node
linkType: hard
"lilconfig@npm:^3.1.1": "lilconfig@npm:^3.1.1":
version: 3.1.2 version: 3.1.2
resolution: "lilconfig@npm:3.1.2" resolution: "lilconfig@npm:3.1.2"
@ -8812,13 +8791,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"pako@npm:~1.0.2":
version: 1.0.11
resolution: "pako@npm:1.0.11"
checksum: 10c0/86dd99d8b34c3930345b8bbeb5e1cd8a05f608eeb40967b293f72fe469d0e9c88b783a8777e4cc7dc7c91ce54c5e93d88ff4b4f060e6ff18408fd21030d9ffbe
languageName: node
linkType: hard
"parse-json@npm:^4.0.0": "parse-json@npm:^4.0.0":
version: 4.0.0 version: 4.0.0
resolution: "parse-json@npm:4.0.0" resolution: "parse-json@npm:4.0.0"