diff --git a/frontend/package.json b/frontend/package.json index 9ac5975668..e50b10d403 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -45,9 +45,9 @@ "translations": "node ./scripts/translations.js", "watch:app:assets": "node ./scripts/watch.js", "watch:app:libs": "node ./scripts/build-libs.js --watch", - "watch:app:main": "clojure -M:dev:shadow-cljs watch main storybook", + "watch:app:main": "clojure -M:dev:shadow-cljs watch main worker storybook", "clear:shadow-cache": "rm -rf .shadow-cljs", - "watch:app": "yarn run clear:shadow-cache && yarn run build:app:worker && concurrently \"yarn run watch:app:main\" \"yarn run watch:app:libs\"", + "watch:app": "yarn run clear:shadow-cache && concurrently \"yarn run watch:app:main\" \"yarn run watch:app:libs\"", "watch": "yarn run watch:app:assets", "watch:storybook": "yarn run build:storybook:assets && concurrently \"storybook dev -p 6006 --no-open\" \"yarn run watch:storybook:assets\"", "watch:storybook:assets": "node ./scripts/watch-storybook.js" diff --git a/frontend/scripts/_helpers.js b/frontend/scripts/_helpers.js index 3183d060c3..21393ef464 100644 --- a/frontend/scripts/_helpers.js +++ b/frontend/scripts/_helpers.js @@ -180,8 +180,8 @@ export async function watch(baseDir, predicate, callback) { }); } -async function readManifestFile() { - const manifestPath = "resources/public/js/manifest.json"; +async function readManifestFile(resource) { + const manifestPath = "resources/public/" + resource; let content = await fs.readFile(manifestPath, { encoding: "utf8" }); return JSON.parse(content); } @@ -189,19 +189,23 @@ async function readManifestFile() { async function readShadowManifest() { const ts = Date.now(); try { - const content = await readManifestFile(); + const content = await readManifestFile("js/manifest.json"); const index = { ts: ts, config: "js/config.js?ts=" + ts, polyfills: "js/polyfills.js?ts=" + ts, - worker_main: "js/worker/main.js?ts=" + ts, }; for (let item of content) { index[item.name] = "js/" + item["output-name"]; } + const content2 = await readManifestFile("js/worker/manifest.json"); + for (let item of content2) { + index["worker_" + item.name] = "js/worker/" + item["output-name"]; + } + return index; } catch (cause) { return { diff --git a/frontend/scripts/build b/frontend/scripts/build index 71ff300451..97d8cc856b 100755 --- a/frontend/scripts/build +++ b/frontend/scripts/build @@ -26,7 +26,7 @@ yarn install || exit 1; rm -rf resources/public; rm -rf target/dist; -yarn run build:app:main --config-merge "{:release-version \"${CURRENT_HASH}-${TS}\"}" $EXTRA_PARAMS || exit 1 +yarn run build:app:main --config-merge "{:release-version \"${CURRENT_HASH}-${TS}\"}" $EXTRA_PARAMS; if [ "$INCLUDE_WASM" = "yes" ]; then yarn run build:wasm || exit 1; @@ -44,10 +44,6 @@ sed -i -re "s/\%version\%/$CURRENT_VERSION/g" ./target/dist/rasterizer.html; sed -i -re "s/\%buildDate\%/$BUILD_DATE/g" ./target/dist/index.html; sed -i -re "s/\%buildDate\%/$BUILD_DATE/g" ./target/dist/rasterizer.html; -if [ "$INCLUDE_WASM" = "yes" ]; then - sed -i "s/version=develop/version=$CURRENT_VERSION/g" ./target/dist/js/render_wasm.js; -fi - if [ "$INCLUDE_STORYBOOK" = "yes" ]; then # build storybook yarn run build:storybook || exit 1; diff --git a/frontend/shadow-cljs.edn b/frontend/shadow-cljs.edn index dab57241a8..ac9b01366f 100644 --- a/frontend/shadow-cljs.edn +++ b/frontend/shadow-cljs.edn @@ -83,7 +83,7 @@ :source-map-detail-level :all}}} :worker - {:target :esm + {:target :browser :output-dir "resources/public/js/worker/" :asset-path "/js/worker" :devtools {:browser-inject :main @@ -94,6 +94,7 @@ {:main {:entries [app.worker] :web-worker true + :prepend-js "importScripts('/js/worker/render.js');" :depends-on #{}}} :js-options diff --git a/frontend/src/app/config.cljs b/frontend/src/app/config.cljs index 76879756c7..92562a7c7d 100644 --- a/frontend/src/app/config.cljs +++ b/frontend/src/app/config.cljs @@ -127,7 +127,7 @@ public-uri)) (def worker-uri - (obj/get global "penpotWorkerURI" "/js/worker.js")) + (obj/get global "penpotWorkerURI" "/js/worker/main.js")) (defn external-feature-flag [flag value] @@ -189,7 +189,11 @@ (true? thumbnail?) (u/join (dm/str id "/thumbnail")) (false? thumbnail?) (u/join (dm/str id))))))) -(defn resolve-static-asset - [path] - (let [uri (u/join public-uri path)] - (assoc uri :query (dm/str "version=" (:full version))))) +(defn resolve-href + [resource] + (let [version (get version :full) + href (-> public-uri + (u/ensure-path-slash) + (u/join resource) + (get :path))] + (str href "?version=" version))) diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index be85dc1fd7..a56b43ad33 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -1316,51 +1316,16 @@ (mem/free) content))) - (defn init-wasm-module [module] (let [default-fn (unchecked-get module "default") - serializers - #js - {:blur-type (unchecked-get module "RawBlurType") - :blend-mode (unchecked-get module "RawBlendMode") - :bool-type (unchecked-get module "RawBoolType") - :font-style (unchecked-get module "RawFontStyle") - :flex-direction (unchecked-get module "RawFlexDirection") - :grid-direction (unchecked-get module "RawGridDirection") - :grow-type (unchecked-get module "RawGrowType") - :align-items (unchecked-get module "RawAlignItems") - :align-self (unchecked-get module "RawAlignSelf") - :align-content (unchecked-get module "RawAlignContent") - :justify-items (unchecked-get module "RawJustifyItems") - :justify-content (unchecked-get module "RawJustifyContent") - :justify-self (unchecked-get module "RawJustifySelf") - :wrap-type (unchecked-get module "RawWrapType") - :grid-track-type (unchecked-get module "RawGridTrackType") - :shadow-style (unchecked-get module "RawShadowStyle") - :stroke-style (unchecked-get module "RawStrokeStyle") - :stroke-cap (unchecked-get module "RawStrokeCap") - :shape-type (unchecked-get module "RawShapeType") - :constraint-h (unchecked-get module "RawConstraintH") - :constraint-v (unchecked-get module "RawConstraintV") - :sizing (unchecked-get module "RawSizing") - :vertical-align (unchecked-get module "RawVerticalAlign") - :fill-data (unchecked-get module "RawFillData") - :text-align (unchecked-get module "RawTextAlign") - :text-direction (unchecked-get module "RawTextDirection") - :text-decoration (unchecked-get module "RawTextDecoration") - :text-transform (unchecked-get module "RawTextTransform") - :segment-data (unchecked-get module "RawSegmentData") - :stroke-linecap (unchecked-get module "RawStrokeLineCap") - :stroke-linejoin (unchecked-get module "RawStrokeLineJoin") - :fill-rule (unchecked-get module "RawFillRule")}] - (set! wasm/serializers serializers) - (default-fn))) + href (cf/resolve-href "js/render-wasm.wasm")] + (default-fn #js {:locateFile (constantly href)}))) (defonce module (delay (if (exists? js/dynamicImport) - (let [uri (cf/resolve-static-asset "js/render_wasm.js")] + (let [uri (cf/resolve-href "js/render-wasm.js")] (->> (js/dynamicImport (str uri)) (p/mcat init-wasm-module) (p/fmap diff --git a/frontend/src/app/render_wasm/api/shared.js b/frontend/src/app/render_wasm/api/shared.js new file mode 100644 index 0000000000..172cb2a97d --- /dev/null +++ b/frontend/src/app/render_wasm/api/shared.js @@ -0,0 +1,242 @@ +export const GrowType = { + "fixed": 0, + "auto-width": 1, + "auto-height": 2, +}; + +export const RawBlendMode = { + "normal": 3, + "screen": 14, + "overlay": 15, + "darken": 16, + "lighten": 17, + "color-dodge": 18, + "color-burn": 19, + "hard-light": 20, + "soft-light": 21, + "difference": 22, + "exclusion": 23, + "multiply": 24, + "hue": 25, + "saturation": 26, + "color": 27, + "luminosity": 28, +}; + +export const RawBlurType = { + "layer-blur": 0, +}; + +export const RawFillData = { + "solid": 0, + "linear": 1, + "radial": 2, + "image": 3, +}; + +export const RawFontStyle = { + "normal": 0, + "italic": 1, +}; + +export const RawAlignItems = { + "start": 0, + "end": 1, + "center": 2, + "stretch": 3, +}; + +export const RawAlignContent = { + "start": 0, + "end": 1, + "center": 2, + "space-between": 3, + "space-around": 4, + "space-evenly": 5, + "stretch": 6, +}; + +export const RawJustifyItems = { + "start": 0, + "end": 1, + "center": 2, + "stretch": 3, +}; + +export const RawJustifyContent = { + "start": 0, + "end": 1, + "center": 2, + "space-between": 3, + "space-around": 4, + "space-evenly": 5, + "stretch": 6, +}; + +export const RawJustifySelf = { + "none": 0, + "auto": 1, + "start": 2, + "end": 3, + "center": 4, + "stretch": 5, +}; + +export const RawAlignSelf = { + "none": 0, + "auto": 1, + "start": 2, + "end": 3, + "center": 4, + "stretch": 5, +}; + +export const RawVerticalAlign = { + "top": 0, + "center": 1, + "bottom": 2, +}; + +export const RawConstraintH = { + "left": 0, + "right": 1, + "leftright": 2, + "center": 3, + "scale": 4, +}; + +export const RawConstraintV = { + "top": 0, + "bottom": 1, + "topbottom": 2, + "center": 3, + "scale": 4, +}; + +export const RawFlexDirection = { + "row": 0, + "row-reverse": 1, + "column": 2, + "column-reverse": 3, +}; + +export const RawWrapType = { + "wrap": 0, + "nowrap": 1, +}; + +export const RawGridDirection = { + "row": 0, + "column": 1, +}; + +export const RawGridTrackType = { + "percent": 0, + "flex": 1, + "auto": 2, + "fixed": 3, +}; + +export const RawSizing = { + "fill": 0, + "fix": 1, + "auto": 2, +}; + +export const RawBoolType = { + "union": 0, + "difference": 1, + "intersection": 2, + "exclusion": 3, +}; + +export const RawSegmentData = { + "move-to": 1, + "line-to": 2, + "curve-to": 3, + "close": 4, +}; + +export const RawShadowStyle = { + "drop-shadow": 0, + "inner-shadow": 1, +}; + +export const RawShapeType = { + "frame": 0, + "group": 1, + "bool": 2, + "rect": 3, + "path": 4, + "text": 5, + "circle": 6, + "svg-raw": 7, +}; + +export const RawStrokeStyle = { + "solid": 0, + "dotted": 1, + "dashed": 2, + "mixed": 3, +}; + +export const RawStrokeCap = { + "none": 0, + "line-arrow": 1, + "triangle-arrow": 2, + "square-marker": 3, + "circle-marker": 4, + "diamond-marker": 5, + "round": 6, + "square": 7, +}; + +export const RawFillRule = { + "nonzero": 0, + "evenodd": 1, +}; + +export const RawStrokeLineCap = { + "butt": 0, + "round": 1, + "square": 2, +}; + +export const RawStrokeLineJoin = { + "miter": 0, + "round": 1, + "bevel": 2, +}; + +export const RawTextAlign = { + "left": 0, + "center": 1, + "right": 2, + "justify": 3, +}; + +export const RawTextDirection = { + "ltr": 0, + "rtl": 1, +}; + +export const RawTextDecoration = { + "none": 0, + "underline": 1, + "line-through": 2, + "overline": 3, +}; + +export const RawTextTransform = { + "none": 0, + "uppercase": 1, + "lowercase": 2, + "capitalize": 3, +}; + +export const RawGrowType = { + "fixed": 0, + "auto-width": 1, + "auto-height": 2, +}; + diff --git a/frontend/src/app/render_wasm/wasm.cljs b/frontend/src/app/render_wasm/wasm.cljs index 7fb59bfebc..3901dc975f 100644 --- a/frontend/src/app/render_wasm/wasm.cljs +++ b/frontend/src/app/render_wasm/wasm.cljs @@ -4,9 +4,43 @@ ;; ;; Copyright (c) KALEIDOS INC -(ns app.render-wasm.wasm) +(ns app.render-wasm.wasm + (:require ["./api/shared.js" :as shared])) (defonce internal-frame-id nil) (defonce internal-module #js {}) -(defonce serializers #js {}) +(defonce serializers + #js {:blur-type shared/RawBlurType + :blend-mode shared/RawBlendMode + :bool-type shared/RawBoolType + :font-style shared/RawFontStyle + :flex-direction shared/RawFlexDirection + :grid-direction shared/RawGridDirection + :grow-type shared/RawGrowType + :align-items shared/RawAlignItems + :align-self shared/RawAlignSelf + :align-content shared/RawAlignContent + :justify-items shared/RawJustifyItems + :justify-content shared/RawJustifyContent + :justify-self shared/RawJustifySelf + :wrap-type shared/RawWrapType + :grid-track-type shared/RawGridTrackType + :shadow-style shared/RawShadowStyle + :stroke-style shared/RawStrokeStyle + :stroke-cap shared/RawStrokeCap + :shape-type shared/RawShapeType + :constraint-h shared/RawConstraintH + :constraint-v shared/RawConstraintV + :sizing shared/RawSizing + :vertical-align shared/RawVerticalAlign + :fill-data shared/RawFillData + :text-align shared/RawTextAlign + :text-direction shared/RawTextDirection + :text-decoration shared/RawTextDecoration + :text-transform shared/RawTextTransform + :segment-data shared/RawSegmentData + :stroke-linecap shared/RawStrokeLineCap + :stroke-linejoin shared/RawStrokeLineJoin + :fill-rule shared/RawFillRule}) + (defonce context-initialized? false) diff --git a/frontend/src/app/util/worker.cljs b/frontend/src/app/util/worker.cljs index cf3260ad30..bf1b44c30b 100644 --- a/frontend/src/app/util/worker.cljs +++ b/frontend/src/app/util/worker.cljs @@ -89,7 +89,7 @@ (defn init "Return a initialized webworker instance." [path on-error] - (let [instance (js/Worker. path #js {:type "module"}) + (let [instance (js/Worker. path) bus (rx/subject) worker (Worker. instance (rx/to-observable bus)) diff --git a/frontend/src/app/worker/thumbnails.cljs b/frontend/src/app/worker/thumbnails.cljs index 517d7895a4..9f757f037d 100644 --- a/frontend/src/app/worker/thumbnails.cljs +++ b/frontend/src/app/worker/thumbnails.cljs @@ -24,11 +24,12 @@ [beicon.v2.core :as rx] [okulary.core :as l] [promesa.core :as p] - [rumext.v2 :as mf] - [shadow.esm :refer (dynamic-import)])) + [rumext.v2 :as mf])) (log/set-level! :trace) +(def ^:private ^:const thumbnail-aspect-ratio (/ 2 3)) + (defn- handle-response [{:keys [body status] :as response}] (cond @@ -64,6 +65,10 @@ (rx/map http/conditional-decode-transit) (rx/mapcat handle-response)))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; SVG RENDERING (LEGACY RENDER) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (defn- render-thumbnail [{:keys [page file-id revn] :as params}] (try @@ -98,15 +103,13 @@ (->> (request-data-for-thumbnail file-id revn true) (rx/map render-thumbnail))) -(def init-wasm - (delay - (let [uri (cf/resolve-static-asset "js/render_wasm.js")] - (-> (dynamic-import (str uri)) - (p/then #(wasm.api/init-wasm-module %)) - (p/then #(set! wasm/internal-module %)))))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; WASM RENDERING +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(mf/defc svg-wrapper - [{:keys [data-uri background width height]}] +(mf/defc svg-wrapper* + {::mf/private true} + [{:keys [uri background width height]}] [:svg {:version "1.1" :xmlns "http://www.w3.org/2000/svg" :xmlnsXlink "http://www.w3.org/1999/xlink" @@ -116,85 +119,97 @@ :background background} :fill "none" :viewBox (dm/str "0 0 " width " " height)} - [:image {:xlinkHref data-uri + [:image {:xlinkHref uri :width width :height height}]]) -(defn blob->uri +(defn- blob->uri [blob] (.readAsDataURL (js/FileReaderSync.) blob)) -(def thumbnail-aspect-ratio (/ 2 3)) +(defn- render-canvas-blob + [canvas width height background] + (->> (.convertToBlob ^js canvas) + (p/fmap (fn [blob] + (rds/renderToStaticMarkup + (mf/element svg-wrapper* + #js {:uri (blob->uri blob) + :width width + :height height + :background background})))))) -(defn render-canvas-blob - [canvas width height background-color] - (-> (.convertToBlob canvas) - (p/then - (fn [blob] - (rds/renderToStaticMarkup - (mf/element - svg-wrapper - #js {:data-uri (blob->uri blob) - :width width - :height height - :background background-color})))))) +(defonce ^:private wasm-module + (delay + (let [module (unchecked-get js/globalThis "WasmModule") + init-fn (unchecked-get module "default") + href (cf/resolve-href "js/render-wasm.wasm")] + (->> (init-fn #js {:locateFile (constantly href)}) + (p/fnly (fn [module cause] + (if cause + (js/console.error cause) + (set! wasm/internal-module module)))))))) -(defn process-wasm-thumbnail +(defn- render-thumbnail-with-wasm [{:keys [id file-id revn width] :as message}] - (->> (rx/from @init-wasm) + (->> (rx/from @wasm-module) (rx/mapcat #(request-data-for-thumbnail file-id revn false)) (rx/mapcat (fn [{:keys [page] :as file}] (rx/create (fn [subs] - (let [background-color (or (:background page) cc/canvas) - height (* width thumbnail-aspect-ratio) - canvas (js/OffscreenCanvas. width height) - init? (wasm.api/init-canvas-context canvas)] + (let [bgcolor (or (:background page) cc/canvas) + height (* width thumbnail-aspect-ratio) + canvas (js/OffscreenCanvas. width height) + init? (wasm.api/init-canvas-context canvas)] (if init? (let [objects (:objects page) - frame (some->> page :thumbnail-frame-id (get objects)) - vbox (if frame - (-> (gsb/get-object-bounds objects frame) - (grc/fix-aspect-ratio thumbnail-aspect-ratio)) - (render/calculate-dimensions objects thumbnail-aspect-ratio)) - zoom (/ width (:width vbox))] + frame (some->> page :thumbnail-frame-id (get objects)) + vbox (if frame + (-> (gsb/get-object-bounds objects frame) + (grc/fix-aspect-ratio thumbnail-aspect-ratio)) + (render/calculate-dimensions objects thumbnail-aspect-ratio)) + zoom (/ width (:width vbox))] (wasm.api/initialize-viewport - objects zoom vbox background-color + objects zoom vbox bgcolor (fn [] (if frame (wasm.api/render-sync-shape (:id frame)) (wasm.api/render-sync)) - (-> (render-canvas-blob canvas width height background-color) - (p/then #(rx/push! subs {:id id :data % :file-id file-id :revn revn})) - (p/catch #(rx/error! subs %)) - (p/finally #(rx/end! subs)))))) - + (->> (render-canvas-blob canvas width height bgcolor) + (p/fnly (fn [data cause] + (if cause + (rx/error! subs cause) + (rx/push! subs + {:id id + :data data + :file-id file-id + :revn revn})) + (rx/end! subs))))))) (rx/end! subs)) - nil))))))) -(defonce thumbs-subject (rx/subject)) +(defonce ^:private + thumbnails-queue + (rx/subject)) -(defonce thumbs-stream - (->> thumbs-subject - (rx/mapcat process-wasm-thumbnail) +(defonce ^:private + thumbnails-stream + (->> thumbnails-queue + (rx/mapcat render-thumbnail-with-wasm) (rx/share))) (defmethod impl/handler :thumbnails/generate-for-file-wasm [message _] (rx/create (fn [subs] - (let [id (uuid/next) - sid - (->> thumbs-stream - (rx/filter #(= id (:id %))) - (rx/subs! - #(do - (rx/push! subs %) - (rx/end! subs))))] - (rx/push! thumbs-subject (assoc message :id id)) - + (let [id (uuid/next) + sid (->> thumbnails-stream + (rx/filter #(= id (:id %))) + (rx/subs! + (fn [result] + (rx/push! subs result) + (rx/end! subs))))] + (rx/push! thumbnails-queue (assoc message :id id)) #(rx/dispose! sid))))) diff --git a/package.json b/package.json index f6a6717e32..22e4bb4a0f 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "license": "MPL-2.0", "author": "Kaleidos INC", "private": true, - "packageManager": "yarn@4.9.1+sha512.f95ce356460e05be48d66401c1ae64ef84d163dd689964962c6888a9810865e39097a5e9de748876c2e0bf89b232d583c33982773e9903ae7a76257270986538", + "packageManager": "yarn@4.12.0+sha512.f45ab632439a67f8bc759bf32ead036a1f413287b9042726b7cc4818b7b49e14e9423ba49b18f9e06ea4941c1ad062385b1d8760a8d5091a1a31e5f6219afca8", "repository": { "type": "git", "url": "https://github.com/penpot/penpot" @@ -15,6 +15,7 @@ "fmt": "./scripts/fmt" }, "devDependencies": { - "@types/node": "^20.12.7" + "@types/node": "^20.12.7", + "esbuild": "^0.25.9" } } diff --git a/render-wasm/_build_env b/render-wasm/_build_env index ec5e070abb..3be4d13957 100644 --- a/render-wasm/_build_env +++ b/render-wasm/_build_env @@ -1,17 +1,23 @@ #!/usr/bin/env bash +export CURRENT_VERSION=${CURRENT_VERSION:-develop}; + if [ "$NODE_ENV" = "production" ]; then - export _BUILD_MODE="release"; + export BUILD_MODE="release"; else - export _BUILD_MODE=${1:-debug}; + export BUILD_MODE=${1:-debug}; fi +export BUILD_NAME="${BUILD_NAME:-render-wasm}" +export CARGO_BUILD_TARGET=${CARGO_BUILD_TARGET:-"wasm32-unknown-emscripten"}; +export SKIA_BINARIES_URL=${SKIA_BINARIES_URL:-"https://github.com/penpot/skia-binaries/releases/download/0.87.0/skia-binaries-e551f334ad5cbdf43abf-wasm32-unknown-emscripten-gl-svg-textlayout-binary-cache-webp.tar.gz"} + # 256 MB of initial heap to perform less # initial calls to memory grow. -EM_INITIAL_HEAP=$((256 * 1024 * 1024)) +export EM_INITIAL_HEAP=$((256 * 1024 * 1024)) # 1.0 doubles the heap on every growth. -EM_MEMORY_GROWTH_GEOMETRIC_STEP="0.8" +export EM_MEMORY_GROWTH_GEOMETRIC_STEP="0.8" # Malloc implementation to use. # - dlmalloc: a powerful general-purpose malloc. @@ -21,38 +27,63 @@ EM_MEMORY_GROWTH_GEOMETRIC_STEP="0.8" # - emmalloc-verbose: use emmalloc with assertions + verbose logging. # - emmalloc-memvalidate-verbose: use emmalloc with assertions + heap consistency checking + verbose logging. # Default: dlmalloc -EM_MALLOC="dlmalloc" +export EM_MALLOC="dlmalloc" -EMCC_CFLAGS="--no-entry \ +export EMCC_CFLAGS="--no-entry \ --js-library src/js/wapi.js \ -sASSERTIONS=1 \ -sALLOW_TABLE_GROWTH=1 \ -sALLOW_MEMORY_GROWTH=1 \ -sINITIAL_HEAP=$EM_INITIAL_HEAP \ -sMEMORY_GROWTH_GEOMETRIC_STEP=$EM_MEMORY_GROWTH_GEOMETRIC_STEP \ - -sENVIRONMENT=web \ -sERROR_ON_UNDEFINED_SYMBOLS=0 \ -sMAX_WEBGL_VERSION=2 \ - -sMODULARIZE=1 \ -sEXPORT_NAME=createRustSkiaModule \ -sEXPORTED_RUNTIME_METHODS=GL,stringToUTF8,HEAPU8,HEAP32,HEAPU32,HEAPF32 \ - -sEXPORT_ES6=1" + -sENVIRONMENT=web \ + -sMODULARIZE=1 \ + -sEXPORT_ES6=1"; export EM_CACHE="/tmp/emsdk_cache"; -_CARGO_PARAMS="${@:2}"; +export CARGO_PARAMS="${@:2}"; -if [ "$_BUILD_MODE" = "release" ]; then - _CARGO_PARAMS="--release $_CARGO_PARAMS" - EMCC_CFLAGS="-Os $EMCC_CFLAGS" +if [ "$BUILD_MODE" = "release" ]; then + export CARGO_PARAMS="--release $CARGO_PARAMS" + export EMCC_CFLAGS="-Os $EMCC_CFLAGS" else # TODO: Extra parameters that could be good to look into: # -gseparate-dwarf # -gsplit-dwarf # -gsource-map - EMCC_CFLAGS="-g $EMCC_CFLAGS -sVERBOSE=1 -sMALLOC=$EM_MALLOC" + export EMCC_CFLAGS="-g $EMCC_CFLAGS -sVERBOSE=1 -sMALLOC=$EM_MALLOC" fi -export EMCC_CFLAGS; -export _CARGO_PARAMS; +function clean { + cargo clean; +} +function build { + cargo build $CARGO_PARAMS; +} + +function copy_artifacts { + DEST=$1; + + cp target/wasm32-unknown-emscripten/$BUILD_MODE/render_wasm.js $DEST/$BUILD_NAME.js; + cp target/wasm32-unknown-emscripten/$BUILD_MODE/render_wasm.wasm $DEST/$BUILD_NAME.wasm; + + sed -i "s/render_wasm.wasm/$BUILD_NAME.wasm?version=$CURRENT_VERSION/g" $DEST/$BUILD_NAME.js; + + npx esbuild target/wasm32-unknown-emscripten/$BUILD_MODE/render_wasm.js \ + --log-level=error \ + --outfile=$DEST/worker/render.js \ + --platform=neutral \ + --format=iife \ + --global-name=WasmModule; +} + +function copy_shared_artifact { + SHARED_FILE=$(find target/wasm32-unknown-emscripten -name render_wasm_shared.js | head -n 1); + cp $SHARED_FILE ../frontend/src/app/render_wasm/api/shared.js; +} diff --git a/render-wasm/build b/render-wasm/build index 3551557ca9..44ee13abb5 100755 --- a/render-wasm/build +++ b/render-wasm/build @@ -11,18 +11,12 @@ pushd $_SCRIPT_DIR; . ./_build_env -export CARGO_BUILD_TARGET=${CARGO_BUILD_TARGET:-"wasm32-unknown-emscripten"}; -export SKIA_BINARIES_URL=${SKIA_BINARIES_URL:-"https://github.com/penpot/skia-binaries/releases/download/0.87.0/skia-binaries-e551f334ad5cbdf43abf-wasm32-unknown-emscripten-gl-svg-textlayout-binary-cache-webp.tar.gz"} +set -x; -cargo build $_CARGO_PARAMS +build; +copy_artifacts "../frontend/resources/public/js"; +copy_shared_artifact; -_SHARED_FILE=$(find target/wasm32-unknown-emscripten -name render_wasm_shared.js | head -n 1); - -cat target/wasm32-unknown-emscripten/$_BUILD_MODE/render_wasm.js "$_SHARED_FILE" > ../frontend/resources/public/js/$_BUILD_NAME.js -cp target/wasm32-unknown-emscripten/$_BUILD_MODE/render_wasm.wasm ../frontend/resources/public/js/$_BUILD_NAME.wasm - -sed -i "s/render_wasm.wasm/$_BUILD_NAME.wasm?version=develop/g" ../frontend/resources/public/js/$_BUILD_NAME.js; - -exit $? +exit $?; popd diff --git a/render-wasm/test b/render-wasm/test index 2e9eb8d341..85d5547d4a 100755 --- a/render-wasm/test +++ b/render-wasm/test @@ -1,14 +1,14 @@ #!/usr/bin/env bash set -x +export SKIA_BINARIES_URL=${SKIA_BINARIES_URL:-"https://github.com/penpot/skia-binaries/releases/download/0.87.0/skia-binaries-e551f334ad5cbdf43abf-x86_64-unknown-linux-gnu-gl-svg-textlayout-binary-cache-webp.tar.gz"} +export CARGO_BUILD_TARGET=${CARGO_BUILD_TARGET:-"x86_64-unknown-linux-gnu"}; + _SCRIPT_DIR=$(dirname $0); pushd $_SCRIPT_DIR; . ./_build_env -export SKIA_BINARIES_URL=${SKIA_BINARIES_URL:-"https://github.com/penpot/skia-binaries/releases/download/0.87.0/skia-binaries-e551f334ad5cbdf43abf-x86_64-unknown-linux-gnu-gl-svg-textlayout-binary-cache-webp.tar.gz"} -export CARGO_BUILD_TARGET=${CARGO_BUILD_TARGET:-"x86_64-unknown-linux-gnu"}; - cargo test --bin render_wasm -- --show-output # Exit with the same status code as cargo test diff --git a/render-wasm/watch b/render-wasm/watch index 74a2b1974a..cfe8336aab 100755 --- a/render-wasm/watch +++ b/render-wasm/watch @@ -6,20 +6,17 @@ pushd $_SCRIPT_DIR; . ./_build_env -export CARGO_BUILD_TARGET=${CARGO_BUILD_TARGET:-"wasm32-unknown-emscripten"}; -export SKIA_BINARIES_URL=${SKIA_BINARIES_URL:-"https://github.com/penpot/skia-binaries/releases/download/0.87.0/skia-binaries-e551f334ad5cbdf43abf-wasm32-unknown-emscripten-gl-svg-textlayout-binary-cache-webp.tar.gz"} +set -x -_SHARED_FILE=$(find target/wasm32-unknown-emscripten -name render_wasm_shared.js | head -n 1); - -cat target/wasm32-unknown-emscripten/$_BUILD_MODE/render_wasm.js "$_SHARED_FILE" > ../frontend/resources/public/js/$_BUILD_NAME.js -cp target/wasm32-unknown-emscripten/$_BUILD_MODE/render_wasm.wasm ../frontend/resources/public/js/$_BUILD_NAME.wasm +build; +copy_artifacts "../frontend/resources/public/js"; +copy_shared_artifact; pushd $_SCRIPT_DIR; + cargo watch \ - -x "build $_CARGO_PARAMS" \ - -s "cat target/wasm32-unknown-emscripten/$_BUILD_MODE/render_wasm.js \"$_SHARED_FILE\" > ../frontend/resources/public/js/$_BUILD_NAME.js" \ - -s "cp target/wasm32-unknown-emscripten/$_BUILD_MODE/render_wasm.wasm ../frontend/resources/public/js/" \ - -s "sed -i 's/render_wasm.wasm/render_wasm.wasm?version=develop/g' ../frontend/resources/public/js/render_wasm.js" \ + -x "build $CARGO_PARAMS" \ + -s "./build" \ -s "echo 'DONE\n'"; popd diff --git a/yarn.lock b/yarn.lock index 7c3964d261..19eba5a5a6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,6 +5,188 @@ __metadata: version: 8 cacheKey: 10c0 +"@esbuild/aix-ppc64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/aix-ppc64@npm:0.25.12" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/android-arm64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/android-arm64@npm:0.25.12" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/android-arm@npm:0.25.12" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-x64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/android-x64@npm:0.25.12" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/darwin-arm64@npm:0.25.12" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-x64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/darwin-x64@npm:0.25.12" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/freebsd-arm64@npm:0.25.12" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-x64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/freebsd-x64@npm:0.25.12" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-arm64@npm:0.25.12" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-arm@npm:0.25.12" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-ia32@npm:0.25.12" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-loong64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-loong64@npm:0.25.12" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-mips64el@npm:0.25.12" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-ppc64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-ppc64@npm:0.25.12" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-riscv64@npm:0.25.12" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-s390x@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-s390x@npm:0.25.12" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-x64@npm:0.25.12" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/netbsd-arm64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/netbsd-arm64@npm:0.25.12" + conditions: os=netbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/netbsd-x64@npm:0.25.12" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-arm64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/openbsd-arm64@npm:0.25.12" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/openbsd-x64@npm:0.25.12" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openharmony-arm64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/openharmony-arm64@npm:0.25.12" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/sunos-x64@npm:0.25.12" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-arm64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/win32-arm64@npm:0.25.12" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/win32-ia32@npm:0.25.12" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/win32-x64@npm:0.25.12" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@types/node@npm:^20.12.7": version: 20.12.12 resolution: "@types/node@npm:20.12.12" @@ -14,11 +196,101 @@ __metadata: languageName: node linkType: hard +"esbuild@npm:^0.25.9": + version: 0.25.12 + resolution: "esbuild@npm:0.25.12" + dependencies: + "@esbuild/aix-ppc64": "npm:0.25.12" + "@esbuild/android-arm": "npm:0.25.12" + "@esbuild/android-arm64": "npm:0.25.12" + "@esbuild/android-x64": "npm:0.25.12" + "@esbuild/darwin-arm64": "npm:0.25.12" + "@esbuild/darwin-x64": "npm:0.25.12" + "@esbuild/freebsd-arm64": "npm:0.25.12" + "@esbuild/freebsd-x64": "npm:0.25.12" + "@esbuild/linux-arm": "npm:0.25.12" + "@esbuild/linux-arm64": "npm:0.25.12" + "@esbuild/linux-ia32": "npm:0.25.12" + "@esbuild/linux-loong64": "npm:0.25.12" + "@esbuild/linux-mips64el": "npm:0.25.12" + "@esbuild/linux-ppc64": "npm:0.25.12" + "@esbuild/linux-riscv64": "npm:0.25.12" + "@esbuild/linux-s390x": "npm:0.25.12" + "@esbuild/linux-x64": "npm:0.25.12" + "@esbuild/netbsd-arm64": "npm:0.25.12" + "@esbuild/netbsd-x64": "npm:0.25.12" + "@esbuild/openbsd-arm64": "npm:0.25.12" + "@esbuild/openbsd-x64": "npm:0.25.12" + "@esbuild/openharmony-arm64": "npm:0.25.12" + "@esbuild/sunos-x64": "npm:0.25.12" + "@esbuild/win32-arm64": "npm:0.25.12" + "@esbuild/win32-ia32": "npm:0.25.12" + "@esbuild/win32-x64": "npm:0.25.12" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-arm64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/openharmony-arm64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10c0/c205357531423220a9de8e1e6c6514242bc9b1666e762cd67ccdf8fdfdc3f1d0bd76f8d9383958b97ad4c953efdb7b6e8c1f9ca5951cd2b7c5235e8755b34a6b + languageName: node + linkType: hard + "penpot@workspace:.": version: 0.0.0-use.local resolution: "penpot@workspace:." dependencies: "@types/node": "npm:^20.12.7" + esbuild: "npm:^0.25.9" languageName: unknown linkType: soft