♻️ 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"
},
"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": {
"build:app:assets": "node ./scripts/build-app-assets.js",
@ -108,11 +109,11 @@
"@penpot/svgo": "penpot/svgo#v3.1",
"@penpot/text-editor": "portal:./text-editor",
"@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",
"date-fns": "^4.1.0",
"eventsource-parser": "^3.0.1",
"js-beautify": "^1.15.4",
"jszip": "^3.10.1",
"lodash": "^4.17.21",
"lodash.debounce": "^4.0.8",
"luxon": "^3.6.1",

View file

@ -5,32 +5,82 @@
;; Copyright (c) KALEIDOS INC
(ns app.util.zip
"Helpers for make zip file (using jszip)."
"Helpers for make zip file."
(:require
["jszip" :as zip]
["@zip.js/zip.js" :as zip]
[app.util.array :as array]
[promesa.core :as p]))
(defn load
[data]
(zip/loadAsync data))
(defn reader
[blob]
(cond
(instance? js/Blob blob)
(let [breader (new zip/BlobReader blob)]
(new zip/ZipReader breader))
(defn get-file
"Gets a single file from the zip archive"
([zip path]
(get-file zip path "text"))
(instance? js/Uint8Array blob)
(let [breader (new zip/Uint8ArrayReader blob)
zreader (new zip/ZipReader breader #js {:useWebWorkers false})]
zreader)
([zip path type]
(let [entry (.file zip path)]
(cond
(nil? entry)
(p/rejected (str "File not found: " path))
(instance? js/ArrayBuffer blob)
(reader (js/Uint8Array. blob))
(.-dir ^js entry)
(p/resolved {:dir path})
:else
(throw (ex-info "invalid arguments"
{:type :internal
:code :invalid-type}))))
:else
(->> (.async ^js entry type)
(p/fmap (fn [content]
;; (js/console.log "zip:process-file" 2 content)
{:path path
:content content})))))))
(defn blob-writer
[& {:keys [mtype]}]
(new zip/BlobWriter (or mtype "application/octet-stream")))
(defn bytes-writer
[]
(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 []))
(defn- read-zip-manifest
[zipfile]
(->> (rx/from (uz/get-file zipfile "manifest.json"))
(rx/map :content)
[zip-reader]
(->> (rx/from (uz/get-entry zip-reader "manifest.json"))
(rx/mapcat uz/read-as-text)
(rx/map json/decode)))
(defn slurp-uri
@ -121,14 +121,15 @@
(let [mtype (parse-mtype body)]
(cond
(= "application/zip" mtype)
(->> (rx/from (uz/load body))
(rx/merge-map read-zip-manifest)
(rx/map
(fn [manifest]
(if (= (:type manifest) "penpot/export-files")
(let [manifest (decode-manifest manifest)]
(assoc file :type :binfile-v3 :files (:files manifest)))
(assoc file :type :legacy-zip :body body)))))
(let [zip-reader (uz/reader body)]
(->> (read-zip-manifest zip-reader)
(rx/map
(fn [manifest]
(if (= (:type manifest) "penpot/export-files")
(let [manifest (decode-manifest manifest)]
(assoc file :type :binfile-v3 :files (:files manifest)))
(assoc file :type :legacy-zip :body body))))
(rx/finalize (partial uz/close zip-reader))))
(= "application/octet-stream" mtype)
(rx/of (assoc file :type :binfile-v1))

View file

@ -2881,10 +2881,17 @@ __metadata:
languageName: node
linkType: hard
"@zip.js/zip.js@npm:^2.7.44":
version: 2.7.53
resolution: "@zip.js/zip.js@npm:2.7.53"
checksum: 10c0/883527bf09ce7c312117536c79d5f07e736d87de802a6c19e39ba2e18027499dcb9359df94dfde13c9bcf6118a20b4f26a40f9892ee82d7cac3124d6986b15c8
"@zip.js/zip.js@npm:2.7.60":
version: 2.7.60
resolution: "@zip.js/zip.js@npm:2.7.60"
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
linkType: hard
@ -5705,6 +5712,7 @@ __metadata:
"@storybook/test-runner": "npm:^0.21.0"
"@tokens-studio/sd-transforms": "npm:1.2.11"
"@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"
compression: "npm:^1.7.5"
concurrently: "npm:^9.1.2"
@ -5724,7 +5732,6 @@ __metadata:
gulp-svg-sprite: "npm:^2.0.3"
js-beautify: "npm:^1.15.4"
jsdom: "npm:^26.1.0"
jszip: "npm:^3.10.1"
lodash: "npm:^4.17.21"
lodash.debounce: "npm:^4.0.8"
luxon: "npm:^3.6.1"
@ -6386,13 +6393,6 @@ __metadata:
languageName: node
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":
version: 5.0.3
resolution: "immutable@npm:5.0.3"
@ -7686,18 +7686,6 @@ __metadata:
languageName: node
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":
version: 6.0.0
resolution: "klaw-sync@npm:6.0.0"
@ -7728,15 +7716,6 @@ __metadata:
languageName: node
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":
version: 3.1.2
resolution: "lilconfig@npm:3.1.2"
@ -8812,13 +8791,6 @@ __metadata:
languageName: node
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":
version: 4.0.0
resolution: "parse-json@npm:4.0.0"