From 954373105d614a7d1b563a3490fe3ad7fffa3de6 Mon Sep 17 00:00:00 2001 From: Lungu Cristian Date: Fri, 27 Oct 2023 13:14:01 +0300 Subject: [PATCH] Visual debugging of components (#17729) * feat: debug/show components from the REPL * ref: some renames and cleanup * chore: removed comments/imports * feat: added remount on every eval & small changes * doc: added tip to debugging doc * doc: formatting * doc: more formatting * fix: fixed docs and other review comments * fix: moved & renamed into the dev.component-preview ns * style: adjusted debugging readme spacing * fix: removed trailing line --- doc/debugging.md | 35 ++++++++++++++++++++++++++ src/dev/component_preview/events.cljs | 25 ++++++++++++++++++ src/dev/component_preview/view.cljs | 16 ++++++++++++ src/status_im2/navigation/screens.cljs | 6 +++++ src/status_im2/subs/root.cljs | 4 +++ 5 files changed, 86 insertions(+) create mode 100644 src/dev/component_preview/events.cljs create mode 100644 src/dev/component_preview/view.cljs diff --git a/doc/debugging.md b/doc/debugging.md index c8ad669244..ff8806f4b0 100644 --- a/doc/debugging.md +++ b/doc/debugging.md @@ -99,3 +99,38 @@ Also to inspect logs in a more flexible manner, instead of the strict output fro adb logcat | grep 'ReactNativeJS\|StatusModule\|GoLog' ``` +### From @clauxx (visual debugging): + +When building/fixing/refactoring components, it can be annoying to set-up the component for instant visual feedback (i.e. finding it in the UI when fixing/refactoring; finding a place for it when building from scratch). Very often if the location of the screen containing your component nested deeply in the app, you might have to do a lot of repeated navigation, nevermind logging in every time the app reloads (even with fast refresh disabled this happens quite often). + +To alleviate this discomfort and make the development cycle more *pleasant*, you can use one of the following options (*_both of which involve the ... REPL ༼ つ ╹ ╹ ༽つ, so make sure you have that set-up with your IDE/editor_*) + +#### REPL-ing to a screen + +This one is straightforward, just evaluate a navigation dispatch form from anywhere: + +```cljs +(comment (rf/dispatch [:navigate-to :your-favorite-buggy-screen])) +``` + +> TIP: you can run this from an untracked user namespace `(ns user)`, from which you can experiment or interact with the REPL. This is where I usually keep my development navigation forms. + +#### REPL-ing a component + +This is also straighforward, but there are some small differences. Just like above, we only have to evaluate a dispatch form, as follows: + +```cljs +;; example debugging a quo component, although it could be any other component e.g. from the `status-im2` ns. +(comment (re-frame/dispatch [:dev/preview-component + [quo/slide-button + {:track-icon :face-id + :track-text "preview component example" + :customization-color :blue + :on-complete identity}]])) +``` + +When evaluated, a full-screen bottom sheet will appear with your component inside. You can make changes to the props or the component internals and re-evaluate the changed forms, after which the component will be re-mounted without running a reload (unless you save the file). Other times it's quicker to just hit save and the component will be reloaded as usual (except for the props you evaluated, which have to be re-evaluated when changed). + +> TIP: You can have multiple versions of the component as separate comments to check for the component variations + +> TIP: You can leave `comment` blocks at the end of component files (other than quo, since can be previewed in other ways) with usages of components, which other developers can use for visualisation/testing. diff --git a/src/dev/component_preview/events.cljs b/src/dev/component_preview/events.cljs new file mode 100644 index 0000000000..97ccfe5826 --- /dev/null +++ b/src/dev/component_preview/events.cljs @@ -0,0 +1,25 @@ +(ns dev.component-preview.events + (:require + [quo.core :as quo] + [re-frame.core :as re-frame])) + +(def preview-screen-name :dev-component-preview) + +(when js/goog.DEBUG + (re-frame/reg-event-fx :dev/preview-component + (fn [{:keys [db]} [[component-tag props & args]]] + (let [view-id (:view-id db) + ;; NOTE: re-render on every evaluation e.g. reset component state without changes + component (into [component-tag (assoc props :key (random-uuid))] args) + navigate? (not= view-id preview-screen-name)] + (cond-> {:db (assoc db :dev/previewed-component component)} + navigate? (assoc :fx [[:dispatch [:navigate-to preview-screen-name]]])))))) + +;; Usage example +(comment + (re-frame/dispatch [:dev/preview-component + [quo/slide-button + {:track-icon :face-id + :track-text ":debug-component example" + :customization-color :blue + :on-complete identity}]])) diff --git a/src/dev/component_preview/view.cljs b/src/dev/component_preview/view.cljs new file mode 100644 index 0000000000..790f0a1dea --- /dev/null +++ b/src/dev/component_preview/view.cljs @@ -0,0 +1,16 @@ +(ns dev.component-preview.view + (:require + [react-native.core :as rn] + [utils.re-frame :as rf])) + +(def ^:private container-style + {:flex 1 + :padding-horizontal 20 + :padding-top 80 + :align-items :center}) + +(defn view + [] + (let [component (rf/sub [:dev/previewed-component])] + [rn/view {:style container-style} + (when component component)])) diff --git a/src/status_im2/navigation/screens.cljs b/src/status_im2/navigation/screens.cljs index e808835ca0..dd41448132 100644 --- a/src/status_im2/navigation/screens.cljs +++ b/src/status_im2/navigation/screens.cljs @@ -1,5 +1,6 @@ (ns status-im2.navigation.screens (:require + [dev.component-preview.view :as component-preview] [status-im.ui.screens.screens :as old-screens] [status-im2.config :as config] [status-im2.contexts.add-new-contact.views :as add-new-contact] @@ -272,6 +273,11 @@ {:modalPresentationStyle :overCurrentContext}) :component scan-address/view}] + (when js/goog.DEBUG + [{:name :dev-component-preview + :options {:sheet? true} + :component component-preview/view}]) + (when config/quo-preview-enabled? quo.preview/screens) diff --git a/src/status_im2/subs/root.cljs b/src/status_im2/subs/root.cljs index 83e30994c8..66f314383a 100644 --- a/src/status_im2/subs/root.cljs +++ b/src/status_im2/subs/root.cljs @@ -147,3 +147,7 @@ ;;wallet (reg-root-key-sub :wallet/scanned-address :wallet/scanned-address) (reg-root-key-sub :wallet/create-account :wallet/create-account) + +;;debug +(when js/goog.DEBUG + (reg-root-key-sub :dev/previewed-component :dev/previewed-component))