Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't warn about reloading handlers when initiated by figwheel #204

Closed
danielcompton opened this issue Aug 23, 2016 · 14 comments
Closed

Don't warn about reloading handlers when initiated by figwheel #204

danielcompton opened this issue Aug 23, 2016 · 14 comments
Assignees

Comments

@danielcompton
Copy link
Contributor

danielcompton commented Aug 23, 2016

There may be a way to tell re-frame when figwheel is reloading code so that we can ignore the warnings for overwriting handlers. This would reduce the noise in the console, and make it more likely we notice actual cases of this happening.

@smahood
Copy link
Contributor

smahood commented Aug 26, 2016

As far as implementation goes, would it be possible to do an (optional) equality check when overwriting handlers?

@mike-thompson-day8
Copy link
Contributor

@smahood Sadly, it won't work. When figwheel triggers the reload of a namespace, it will create all new functions and they won't test = to the previous.

@mattly
Copy link

mattly commented Sep 29, 2016

I have this setup for development:

(require '[re-frame.loggers :as rf.log])
(def warn (js/console.warn.bind js/console))
(rf.log/set-loggers!
 {:warn (fn [& args]
          (cond
            (= "re-frame: overwriting " (first args)) nil
            :else (apply warn args)))})

I want to leave the normal logger operational so that any other warnings that pop up during reload (such as deprecation notices) don't get swallowed.

danielcompton added a commit that referenced this issue Oct 17, 2016
When figwheel reloads code, it causes handlers to be re-registered
which leads to a warning for each handler. This leads to noisy logs.
Figwheel has a :before-jsload key which can be called before it reloads
application code.

This patch adds a *warn-on-overwrite* dynamic var, and shows how to use
it in the example project.

One side effect of using this is that you will never get a warning
for duplicate handlers when Figwheel is reloading. It may be possible
to track how many handlers were reloaded in a particular Figwheel
reload, but this would get very complex. In any case, you will still
get warnings every time you refresh the browser, which should be good
enough for the relatively rare case of creating duplicate handlers.

Fixes #204
danielcompton added a commit that referenced this issue Nov 6, 2016
When figwheel reloads code, it causes handlers to be re-registered
which leads to a warning for each handler. This leads to noisy logs.
Figwheel has a :before-jsload key which can be called before it reloads
application code.

This patch adds a *warn-on-overwrite* dynamic var, and shows how to use
it in the example project.

One side effect of using this is that you will never get a warning
for duplicate handlers when Figwheel is reloading. It may be possible
to track how many handlers were reloaded in a particular Figwheel
reload, but this would get very complex. In any case, you will still
get warnings every time you refresh the browser, which should be good
enough for the relatively rare case of creating duplicate handlers.

Fixes #204
@pesterhazy
Copy link
Contributor

@mattly your snippet works well, thanks. AFAIK you don't need the bind trick - you can just (apply js/console.warn ...). But not sure if that works in all environments.

@danielcompton
Copy link
Contributor Author

danielcompton commented Dec 20, 2017

@teodorlu
Copy link

I just got around this. Solution: clear handlers before Figwheel reloads.

(ns ^:figwheel-hooks cat.core  ; Tell Figwheel to look for hooks in this ns
  (:require
   ;; ...
   [re-frame.registrar]
   ))

;; Then, remove all registered handlers before loading code
(defn ^:before-load cleanup []
  (re-frame.registrar/clear-handlers))

I like this solution because it will notify me if I remove code generating a handler and depend on it, in addition to notifying me on actual duplicate handlers.

@pesterhazy
Copy link
Contributor

pesterhazy commented Oct 10, 2018 via email

@teodorlu
Copy link

No, as of com.bhauman/figwheel-main {:mvn/version "0.1.9"}, my core namespace is reloaded when I change a different namespace. Trailing part of my core.cljs:

(defn mount []
  (reagent/render [category-view]
                  (js/document.getElementById "app")))

(defn ^:before-load cleanup []
  (re-frame.registrar/clear-handlers))

(defn ^:after-load re-render []
  (mount))

(defonce start-up (do
                    (rf/dispatch [:initialize-db])
                    (mount)
                    true))

@pesterhazy
Copy link
Contributor

As explained above, this is adding a lot of noise for every reload. This is significant in reload-heavy workflows.

Arguably warning about reloads is not a good default. After all, registering a subscription is much like defining a function (or a defmethod). In Clojure, redefining a function is something you're expected to do, and won't issue a warning.

Clearing the registry is not a good option for the same reason that the defmulti registry is not cleared when you re-run defmulti: if subscriptions are defined in multiple namespaces and you only reload one of them, the other subscriptions would be lost. This is typical when using Figwheel.

If there's interest in changing the behavior, I'm happy to prepare a patch @mike-thompson-day8

For the moment, I'm using this hackity hack to monkey-patch the warning away:

(set! (.-re_frame.registrar.register_handler js/window)
      (fn register-handler
        [kind id handler-fn]
        (swap! re-frame.registrar/kind->id->handler assoc-in [kind id] handler-fn)
        handler-fn) )

@danielcompton
Copy link
Contributor Author

danielcompton commented Apr 22, 2019

@pesterhazy I've looked at this a bit at #413 and was never totally happy with the approach, as it requires everybody to add more config to their project. Before opening up a PR, would you be able to describe your approach? I haven't talked to Mike about this recently, but last time we talked he was keen for there to be a way to catch multiple handlers on the initial page load.

Here are a few of my ideas on how you could do this, though none of them feel elegant:

  • Add a new function in re-frame that the user calls to indicate when their app is "ready", and then don't warn after that point.
  • Add a config option to enable/disable the warnings. Maybe you'd keep the warnings on in production, but turn them off in dev?
  • Infer that once a dispatch has been made that the app is ready, and stop warning after that point. This would have some false negatives if people were defining dispatches that happened as part of namespace evaluation, but I'm not sure if that's worth worrying about.

Interested to hear your thoughts 🤔.

@pesterhazy
Copy link
Contributor

@danielcompton, thanks for the thoughtful response

AIUI the requirements as explained by you and @mike-thompson-day8 are:

  • only show warnings in dev builds (production builds are today guarded by (when debug))
  • on initial load, if there's a duplicate subscription, show warning on second reg-sub
  • once figwheel kicks in (after you touch a file), no warnings should be shown anymore, as there's no reliable way to distinguish re-definitions due to repetition and re-definitions due to reload

My approach would be

  • add a new public API, re-frame.registrar/set-hide-warnings (not sure about the name) that sets a flag (which defaults to false)
  • in the app code, call this function in the figwheel "before-load" hook

I've created a demo repo with inlined re-frame source code for simpler modifiction. master in the repo exhibits the spurious warnings, the fix branch doesn't: https://github.com/pesterhazy/reframe-reloading/pull/1/files

Let me know what you think

@pesterhazy
Copy link
Contributor

Add a new function in re-frame that the user calls to indicate when their app is "ready", and then don't warn after that point.

That's basically the approach taken above

Add a config option to enable/disable the warnings. Maybe you'd keep the warnings on in production, but turn them off in dev?

I think you usually want asserts and warnings off in prod (that's how it is today). Config options are always a bit clunky. I also think that approach 1 is a bit better because it still gives you warnings on initial load.

Infer that once a dispatch has been made that the app is ready, and stop warning after that point. This would have some false negatives if people were defining dispatches that happened as part of namespace evaluation, but I'm not sure if that's worth worrying about.

That seems fragile and too magical to me

@superstructor
Copy link
Contributor

superstructor commented May 6, 2020

We considered:

  • Need to have a solution for shadow-cljs as well, because that is what we and re-frame-template now use.
  • So, on startup we do want to report any duplicates because they will be a real problem.
  • But, once the application has started up, and we're just doing hot reloading, we don't want to report duplicates.
  • Simplest solution: have a function you call in your "main" which turns this warning off. That way, all the initial loading would have already happened and any upfront problems would have been reported. Then in main you turn off this warning feature and noone would hear from it again.
  • Or alternatively, we could have a way to turn this check on and off. And in the reload handlers supplied by shadow-cljs and figwheel we turn it off and then back on again. To detect real duplicates on reload would require some specialized registrar prior-state tracking for comparison.
  • Or alternatively, we could turn it off on page load automatically. In that way, programmers don't have to remember to turn it off themselves in main as it seems like an impl detail.

Outcome

I have changed re-frame so that it will no longer warn about duplicates after initial page load. This happens automatically without calling any function in main.

  • re-frame will warn on duplicate registrations up until the moment of the window "load" event being received. So, no change in behavior up to this point. This will catch any duplicates during program localisation - a check which I believe is useful for developers.
  • However, after that point, no further checking/warning will be performed. This means that hot reloading caused by figwheel or shadow-cljs will no longer be noisy.

@superstructor superstructor self-assigned this May 6, 2020
@hkjels
Copy link

hkjels commented May 28, 2021

These warnings still occur on react-native when using krell

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants