mirror of
https://github.com/penpot/penpot.git
synced 2025-05-21 23:46:10 +02:00
⚡ Improved first load time
This commit is contained in:
parent
32d61eaf70
commit
71bb34efc5
11 changed files with 128 additions and 65 deletions
|
@ -92,7 +92,7 @@
|
||||||
"Returns a vector of parents of the specified shape."
|
"Returns a vector of parents of the specified shape."
|
||||||
[objects shape-id]
|
[objects shape-id]
|
||||||
(loop [result [] id shape-id]
|
(loop [result [] id shape-id]
|
||||||
(if-let [parent-id (->> id (get objects) :parent-id)]
|
(if-let [parent-id (get-in objects [id :parent-id])]
|
||||||
(recur (conj result parent-id) parent-id)
|
(recur (conj result parent-id) parent-id)
|
||||||
result)))
|
result)))
|
||||||
|
|
||||||
|
|
|
@ -11,16 +11,17 @@
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[clojure.set :as set]))
|
[clojure.set :as set]))
|
||||||
|
|
||||||
(defn calculate-frame-z-index [z-index frame-id objects]
|
(defn calculate-frame-z-index
|
||||||
|
[z-index frame-id base-idx objects]
|
||||||
|
|
||||||
(let [is-frame? (fn [id] (= :frame (get-in objects [id :type])))
|
(let [is-frame? (fn [id] (= :frame (get-in objects [id :type])))
|
||||||
frame-shapes (->> objects (vals) (filterv #(= (:frame-id %) frame-id)))
|
|
||||||
children (or (get-in objects [frame-id :shapes]) [])]
|
children (or (get-in objects [frame-id :shapes]) [])]
|
||||||
|
|
||||||
(if (empty? children)
|
(if (empty? children)
|
||||||
z-index
|
z-index
|
||||||
(loop [current (peek children)
|
(loop [current (peek children)
|
||||||
pending (pop children)
|
pending (pop children)
|
||||||
current-idx (count frame-shapes)
|
current-idx base-idx
|
||||||
z-index z-index]
|
z-index z-index]
|
||||||
|
|
||||||
(let [children (get-in objects [current :shapes])
|
(let [children (get-in objects [current :shapes])
|
||||||
|
@ -46,10 +47,15 @@
|
||||||
[objects]
|
[objects]
|
||||||
|
|
||||||
(let [frames (cph/get-frames objects)
|
(let [frames (cph/get-frames objects)
|
||||||
z-index (calculate-frame-z-index {} uuid/zero objects)]
|
|
||||||
|
by-frame (cph/objects-by-frame objects)
|
||||||
|
frame-base-idx (d/update-vals by-frame count)
|
||||||
|
|
||||||
|
z-index (calculate-frame-z-index {} uuid/zero (get frame-base-idx uuid/zero) objects)]
|
||||||
(->> frames
|
(->> frames
|
||||||
(map :id)
|
(reduce
|
||||||
(reduce #(calculate-frame-z-index %1 %2 objects) z-index))))
|
(fn [z-index {:keys [id]}]
|
||||||
|
(calculate-frame-z-index z-index id (get frame-base-idx id) objects)) z-index))))
|
||||||
|
|
||||||
(defn update-z-index
|
(defn update-z-index
|
||||||
"Updates the z-index given a set of ids to change and the old and new objects
|
"Updates the z-index given a set of ids to change and the old and new objects
|
||||||
|
@ -65,10 +71,13 @@
|
||||||
(map :id)
|
(map :id)
|
||||||
(filter #(contains? changed-frames %)))
|
(filter #(contains? changed-frames %)))
|
||||||
|
|
||||||
z-index (calculate-frame-z-index z-index uuid/zero new-objects)]
|
by-frame (cph/objects-by-frame new-objects)
|
||||||
|
frame-base-idx (d/update-vals by-frame count)
|
||||||
|
z-index (calculate-frame-z-index z-index uuid/zero (get frame-base-idx uuid/zero) new-objects)]
|
||||||
|
|
||||||
(->> frames
|
(->> frames
|
||||||
(reduce #(calculate-frame-z-index %1 %2 new-objects) z-index))))
|
(reduce (fn [z-index id]
|
||||||
|
(calculate-frame-z-index z-index id (get frame-base-idx id) new-objects)) z-index))))
|
||||||
|
|
||||||
(defn generate-child-parent-index
|
(defn generate-child-parent-index
|
||||||
[objects]
|
[objects]
|
||||||
|
@ -84,10 +93,10 @@
|
||||||
(generate-child-all-parents-index objects (vals objects)))
|
(generate-child-all-parents-index objects (vals objects)))
|
||||||
|
|
||||||
([objects shapes]
|
([objects shapes]
|
||||||
(let [xf-parents (comp
|
(let [shape->entry
|
||||||
(map :id)
|
(fn [shape]
|
||||||
(map #(vector % (cph/get-parent-ids objects %))))]
|
[(:id shape) (cph/get-parent-ids objects (:id shape))])]
|
||||||
(into {} xf-parents shapes))))
|
(into {} (map shape->entry) shapes))))
|
||||||
|
|
||||||
(defn create-clip-index
|
(defn create-clip-index
|
||||||
"Retrieves the mask information for an object"
|
"Retrieves the mask information for an object"
|
||||||
|
|
|
@ -115,17 +115,24 @@
|
||||||
(rx/filter (ptk/type? ::dwp/bundle-fetched))
|
(rx/filter (ptk/type? ::dwp/bundle-fetched))
|
||||||
(rx/take 1)
|
(rx/take 1)
|
||||||
(rx/map deref)
|
(rx/map deref)
|
||||||
(rx/mapcat (fn [bundle]
|
(rx/mapcat
|
||||||
(let [team-id (-> bundle :project :team-id)]
|
(fn [bundle]
|
||||||
(rx/merge
|
(rx/merge
|
||||||
(rx/of (dwn/initialize team-id file-id)
|
(rx/of (dwc/initialize-indices bundle))
|
||||||
(dwp/initialize-file-persistence file-id)
|
|
||||||
(dwc/initialize-indices bundle))
|
|
||||||
|
|
||||||
(->> stream
|
(->> (rx/of bundle)
|
||||||
(rx/filter #(= ::dwc/index-initialized %))
|
(rx/mapcat
|
||||||
(rx/take 1)
|
(fn [bundle]
|
||||||
(rx/map #(file-initialized bundle))))))))))
|
(let [bundle (assoc bundle :file (t/decode-str (:file-raw bundle)))
|
||||||
|
team-id (dm/get-in bundle [:project :team-id])]
|
||||||
|
(rx/merge
|
||||||
|
(rx/of (dwn/initialize team-id file-id)
|
||||||
|
(dwp/initialize-file-persistence file-id))
|
||||||
|
|
||||||
|
(->> stream
|
||||||
|
(rx/filter #(= ::dwc/index-initialized %))
|
||||||
|
(rx/take 1)
|
||||||
|
(rx/map #(file-initialized bundle))))))))))))))
|
||||||
|
|
||||||
ptk/EffectEvent
|
ptk/EffectEvent
|
||||||
(effect [_ _ _]
|
(effect [_ _ _]
|
||||||
|
|
|
@ -48,13 +48,12 @@
|
||||||
;; --- Selection Index Handling
|
;; --- Selection Index Handling
|
||||||
|
|
||||||
(defn initialize-indices
|
(defn initialize-indices
|
||||||
[{:keys [file] :as bundle}]
|
[{:keys [file-raw] :as bundle}]
|
||||||
(ptk/reify ::setup-selection-index
|
(ptk/reify ::setup-selection-index
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(let [msg {:cmd :initialize-indices
|
(let [msg {:cmd :initialize-indices
|
||||||
:file-id (:id file)
|
:file-raw file-raw}]
|
||||||
:data (:data file)}]
|
|
||||||
(->> (uw/ask! msg)
|
(->> (uw/ask! msg)
|
||||||
(rx/map (constantly ::index-initialized)))))))
|
(rx/map (constantly ::index-initialized)))))))
|
||||||
|
|
||||||
|
|
|
@ -251,8 +251,8 @@
|
||||||
(rp/query :project {:id project-id})
|
(rp/query :project {:id project-id})
|
||||||
(rp/query :file-libraries {:file-id file-id}))
|
(rp/query :file-libraries {:file-id file-id}))
|
||||||
(rx/take 1)
|
(rx/take 1)
|
||||||
(rx/map (fn [[file users project libraries]]
|
(rx/map (fn [[file-raw users project libraries]]
|
||||||
{:file file
|
{:file-raw file-raw
|
||||||
:users users
|
:users users
|
||||||
:project project
|
:project project
|
||||||
:libraries libraries}))
|
:libraries libraries}))
|
||||||
|
|
|
@ -35,8 +35,7 @@
|
||||||
(rx/throw {:type :validation
|
(rx/throw {:type :validation
|
||||||
:code :request-body-too-large})
|
:code :request-body-too-large})
|
||||||
|
|
||||||
(and (>= status 400)
|
(and (>= status 400) (map? body))
|
||||||
(map? body))
|
|
||||||
(rx/throw body)
|
(rx/throw body)
|
||||||
|
|
||||||
:else
|
:else
|
||||||
|
@ -49,13 +48,19 @@
|
||||||
(defn- send-query!
|
(defn- send-query!
|
||||||
"A simple helper for send and receive transit data on the penpot
|
"A simple helper for send and receive transit data on the penpot
|
||||||
query api."
|
query api."
|
||||||
[id params]
|
([id params]
|
||||||
(->> (http/send! {:method :get
|
(send-query! id params nil))
|
||||||
:uri (u/join base-uri "api/rpc/query/" (name id))
|
|
||||||
:credentials "include"
|
([id params {:keys [raw-transit?]}]
|
||||||
:query params})
|
(let [decode-transit (if raw-transit?
|
||||||
(rx/map http/conditional-decode-transit)
|
identity
|
||||||
(rx/mapcat handle-response)))
|
(partial rx/map http/conditional-decode-transit))]
|
||||||
|
(->> (http/send! {:method :get
|
||||||
|
:uri (u/join base-uri "api/rpc/query/" (name id))
|
||||||
|
:credentials "include"
|
||||||
|
:query params})
|
||||||
|
(decode-transit)
|
||||||
|
(rx/mapcat handle-response)))))
|
||||||
|
|
||||||
(defn- send-mutation!
|
(defn- send-mutation!
|
||||||
"A simple helper for a common case of sending and receiving transit
|
"A simple helper for a common case of sending and receiving transit
|
||||||
|
@ -77,6 +82,10 @@
|
||||||
[id params]
|
[id params]
|
||||||
(send-query! id params))
|
(send-query! id params))
|
||||||
|
|
||||||
|
(defmethod query :file
|
||||||
|
[id params]
|
||||||
|
(send-query! id params {:raw-transit? true}))
|
||||||
|
|
||||||
(defmethod mutation :default
|
(defmethod mutation :default
|
||||||
[id params]
|
[id params]
|
||||||
(send-mutation! id params))
|
(send-mutation! id params))
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
(ns app.util.worker
|
(ns app.util.worker
|
||||||
"A lightweight layer on top of webworkers api."
|
"A lightweight layer on top of webworkers api."
|
||||||
(:require
|
(:require
|
||||||
[app.common.transit :as t]
|
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.util.globals :refer [global]]
|
[app.util.globals :refer [global]]
|
||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
|
[app.worker.messages :as wm]
|
||||||
[beicon.core :as rx]))
|
[beicon.core :as rx]))
|
||||||
|
|
||||||
(declare handle-response)
|
(declare handle-response)
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
(rx/take-while #(not (:completed %)) ob)
|
(rx/take-while #(not (:completed %)) ob)
|
||||||
(rx/take 1 ob)))
|
(rx/take 1 ob)))
|
||||||
|
|
||||||
data (t/encode-str message)
|
data (wm/encode message)
|
||||||
instance (:instance worker)]
|
instance (:instance worker)]
|
||||||
|
|
||||||
(if (some? instance)
|
(if (some? instance)
|
||||||
|
@ -71,11 +71,10 @@
|
||||||
|
|
||||||
handle-message
|
handle-message
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [data (.-data event)
|
(let [message (wm/decode (.-data event))]
|
||||||
data (t/decode-str data)]
|
(if (:error message)
|
||||||
(if (:error data)
|
(on-error (:error message))
|
||||||
(on-error (:error data))
|
(rx/push! bus message))))
|
||||||
(rx/push! bus data))))
|
|
||||||
|
|
||||||
handle-error
|
handle-error
|
||||||
(fn [error]
|
(fn [error]
|
||||||
|
|
|
@ -8,10 +8,10 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.logging :as log]
|
[app.common.logging :as log]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.common.transit :as t]
|
|
||||||
[app.worker.export]
|
[app.worker.export]
|
||||||
[app.worker.impl :as impl]
|
[app.worker.impl :as impl]
|
||||||
[app.worker.import]
|
[app.worker.import]
|
||||||
|
[app.worker.messages :as wm]
|
||||||
[app.worker.selection]
|
[app.worker.selection]
|
||||||
[app.worker.snaps]
|
[app.worker.snaps]
|
||||||
[app.worker.thumbnails]
|
[app.worker.thumbnails]
|
||||||
|
@ -46,7 +46,7 @@
|
||||||
[{:keys [sender-id payload] :as message}]
|
[{:keys [sender-id payload] :as message}]
|
||||||
(us/assert ::message message)
|
(us/assert ::message message)
|
||||||
(letfn [(post [msg]
|
(letfn [(post [msg]
|
||||||
(let [msg (-> msg (assoc :reply-to sender-id) (t/encode-str))]
|
(let [msg (-> msg (assoc :reply-to sender-id) (wm/encode))]
|
||||||
(.postMessage js/self msg)))
|
(.postMessage js/self msg)))
|
||||||
|
|
||||||
(reply [result]
|
(reply [result]
|
||||||
|
@ -91,8 +91,8 @@
|
||||||
"Sends to the client a notification that its messages have been dropped"
|
"Sends to the client a notification that its messages have been dropped"
|
||||||
[{:keys [sender-id] :as message}]
|
[{:keys [sender-id] :as message}]
|
||||||
(us/assert ::message message)
|
(us/assert ::message message)
|
||||||
(.postMessage js/self (t/encode-str {:reply-to sender-id
|
(.postMessage js/self (wm/encode {:reply-to sender-id
|
||||||
:dropped true})))
|
:dropped true})))
|
||||||
|
|
||||||
(defn subscribe-buffer-messages
|
(defn subscribe-buffer-messages
|
||||||
"Creates a subscription to process the buffer messages"
|
"Creates a subscription to process the buffer messages"
|
||||||
|
@ -150,7 +150,7 @@
|
||||||
[event]
|
[event]
|
||||||
(when (nil? (.-source event))
|
(when (nil? (.-source event))
|
||||||
(let [message (.-data event)
|
(let [message (.-data event)
|
||||||
message (t/decode-str message)]
|
message (wm/decode message)]
|
||||||
(if (:buffer? message)
|
(if (:buffer? message)
|
||||||
(rx/push! buffer message)
|
(rx/push! buffer message)
|
||||||
(handle-message message)))))
|
(handle-message message)))))
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
(ns app.worker.impl
|
(ns app.worker.impl
|
||||||
(:require
|
(:require
|
||||||
[app.common.pages.changes :as ch]
|
[app.common.pages.changes :as ch]
|
||||||
|
[app.common.transit :as t]
|
||||||
[app.util.globals :refer [global]]
|
[app.util.globals :refer [global]]
|
||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
[okulary.core :as l]))
|
[okulary.core :as l]))
|
||||||
|
@ -28,14 +29,15 @@
|
||||||
message)
|
message)
|
||||||
|
|
||||||
(defmethod handler :initialize-indices
|
(defmethod handler :initialize-indices
|
||||||
[{:keys [data] :as message}]
|
[{:keys [file-raw] :as message}]
|
||||||
|
|
||||||
(reset! state data)
|
(let [data (-> (t/decode-str file-raw) :data)
|
||||||
|
message (assoc message :data data)]
|
||||||
(handler (-> message
|
(reset! state data)
|
||||||
(assoc :cmd :selection/initialize-index)))
|
(handler (-> message
|
||||||
(handler (-> message
|
(assoc :cmd :selection/initialize-index)))
|
||||||
(assoc :cmd :snaps/initialize-index))))
|
(handler (-> message
|
||||||
|
(assoc :cmd :snaps/initialize-index)))))
|
||||||
|
|
||||||
(defmethod handler :update-page-indices
|
(defmethod handler :update-page-indices
|
||||||
[{:keys [page-id changes] :as message}]
|
[{:keys [page-id changes] :as message}]
|
||||||
|
|
36
frontend/src/app/worker/messages.cljs
Normal file
36
frontend/src/app/worker/messages.cljs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) UXBOX Labs SL
|
||||||
|
|
||||||
|
(ns app.worker.messages
|
||||||
|
"A lightweight layer on top of webworkers api."
|
||||||
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.transit :as t]
|
||||||
|
[app.util.object :as obj]))
|
||||||
|
|
||||||
|
(defn encode [{:keys [sender-id reply-to payload buffer?] :as message}]
|
||||||
|
#js {:cmd (d/name (:cmd payload))
|
||||||
|
:senderId (when sender-id (str sender-id))
|
||||||
|
:replyTo (when reply-to (str reply-to))
|
||||||
|
:payload (if (= :initialize-indices (:cmd payload))
|
||||||
|
(:file-raw payload)
|
||||||
|
(when (some? payload) (t/encode-str payload)))
|
||||||
|
:buffer (when (some? buffer?) buffer?)})
|
||||||
|
|
||||||
|
(defn decode [^js data]
|
||||||
|
(let [cmd (obj/get data "cmd")
|
||||||
|
sender-id (obj/get data "senderId")
|
||||||
|
reply-to (obj/get data "replyTo")
|
||||||
|
payload (obj/get data "payload")
|
||||||
|
buffer (obj/get data "buffer")]
|
||||||
|
(d/without-nils
|
||||||
|
{:sender-id (when sender-id (uuid sender-id))
|
||||||
|
:reply-to (when reply-to (uuid reply-to))
|
||||||
|
:payload (if (= cmd "initialize-indices")
|
||||||
|
{:cmd :initialize-indices
|
||||||
|
:file-raw payload}
|
||||||
|
(when (some? payload) (t/decode-str payload)))
|
||||||
|
:buffer? buffer})))
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
(defonce state (l/atom {}))
|
(defonce state (l/atom {}))
|
||||||
|
|
||||||
(defn index-shape
|
(defn make-index-shape
|
||||||
[objects parents-index clip-parents-index]
|
[objects parents-index clip-parents-index]
|
||||||
(fn [index shape]
|
(fn [index shape]
|
||||||
(let [{:keys [x y width height]}
|
(let [{:keys [x y width height]}
|
||||||
|
@ -77,13 +77,16 @@
|
||||||
(let [shapes (-> objects (dissoc uuid/zero) vals)
|
(let [shapes (-> objects (dissoc uuid/zero) vals)
|
||||||
parents-index (cp/generate-child-all-parents-index objects)
|
parents-index (cp/generate-child-all-parents-index objects)
|
||||||
clip-parents-index (cp/create-clip-index objects parents-index)
|
clip-parents-index (cp/create-clip-index objects parents-index)
|
||||||
bounds (-> objects objects-bounds add-padding-bounds)
|
|
||||||
|
|
||||||
index (reduce (index-shape objects parents-index clip-parents-index)
|
root-shapes (cph/get-immediate-children objects uuid/zero)
|
||||||
(qdt/create (clj->js bounds))
|
bounds (-> root-shapes gsh/selection-rect add-padding-bounds)
|
||||||
shapes)
|
|
||||||
|
|
||||||
z-index (cp/calculate-z-index objects)]
|
index-shape (make-index-shape objects parents-index clip-parents-index)
|
||||||
|
initial-quadtree (qdt/create (clj->js bounds))
|
||||||
|
|
||||||
|
index (reduce index-shape initial-quadtree shapes)
|
||||||
|
|
||||||
|
z-index (cp/calculate-z-index objects)]
|
||||||
|
|
||||||
{:index index :z-index z-index :bounds bounds}))
|
{:index index :z-index z-index :bounds bounds}))
|
||||||
|
|
||||||
|
@ -106,9 +109,8 @@
|
||||||
|
|
||||||
new-index (qdt/remove-all index changed-ids)
|
new-index (qdt/remove-all index changed-ids)
|
||||||
|
|
||||||
index (reduce (index-shape new-objects parents-index clip-parents-index)
|
index-shape (make-index-shape new-objects parents-index clip-parents-index)
|
||||||
new-index
|
index (reduce index-shape new-index shapes)
|
||||||
shapes)
|
|
||||||
|
|
||||||
z-index (cp/update-z-index z-index changed-ids old-objects new-objects)]
|
z-index (cp/update-z-index z-index changed-ids old-objects new-objects)]
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue