🐛 Fix problem with export and fonts

This commit is contained in:
alonso.torres 2026-06-16 17:49:30 +02:00
parent 7863692c98
commit 17847111cb
2 changed files with 36 additions and 3 deletions

View File

@ -48,11 +48,30 @@
(.waitForTimeout ^js page ms))
(defn wait-for-fonts
"Wait until the browser has finished loading all fonts"
"Wait until the browser has finished loading all fonts.
Checking `document.fonts.status === 'loaded'` on its own is not enough:
the render page injects its `@font-face` rules asynchronously and the
browser only loads a face lazily, when some painted text actually uses
it. A face that is declared but not yet requested stays in the `unloaded`
state, which does NOT keep `document.fonts.status` at `loading`, so the
check can pass before any real font glyphs are available. The export is
then captured with a (usually wider) fallback font, and auto-width text
laid out with the real font metrics overflows its bounds and gets clipped.
To avoid that we explicitly request every declared face and await
`document.fonts.ready` before checking the status."
([page] (wait-for-fonts page nil))
([page {:keys [timeout] :or {timeout 15000}}]
(-> (.waitForFunction ^js page
"() => document.fonts && document.fonts.status === 'loaded'"
"async () => {
if (!document.fonts) return true;
try {
await Promise.all(Array.from(document.fonts, (face) => face.load()));
} catch (e) {}
await document.fonts.ready;
return document.fonts.status === 'loaded';
}"
nil
#js {:timeout timeout})
(p/catch (fn [cause]

View File

@ -34,6 +34,7 @@
[app.common.uuid :as uuid]
[app.config :as cf]
[app.main.data.exports.wasm :as wasm.exports]
[app.main.data.persistence :as dwp]
[app.main.data.plugins :as dp]
[app.main.data.workspace :as dw]
[app.main.data.workspace.groups :as dwg]
@ -46,6 +47,7 @@
[app.main.data.workspace.texts :as dwt]
[app.main.data.workspace.tokens.application :as dwta]
[app.main.data.workspace.variants :as dwv]
[app.main.refs :as refs]
[app.main.repo :as rp]
[app.main.store :as st]
[app.plugins.fills :as fills]
@ -1264,7 +1266,19 @@
:scale (:scale value 1)}]}]
(js/Promise.
(fn [resolve reject]
(->> (rp/cmd! :export payload)
;; The exporter renders the file from its persisted
;; state, so flush pending local changes and wait until
;; they are saved before invoking it. Otherwise it may
;; export a stale/empty shape. (The wasm export above
;; renders locally and does not need this.)
(st/emit! ::dwp/force-persist)
(->> (rx/concat
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
(rx/filter #(or (nil? %) (= :saved %)))
(rx/first)
(rx/timeout 5000 (rx/empty))
(rx/ignore))
(rp/cmd! :export payload))
(rx/mapcat (fn [{:keys [uri]}]
(->> (http/send! {:method :get
:uri uri