Fork me on GitHub
#reitit
<
2020-05-20
>
ikitommi05:05:18

@orestis the cljs-impl is not optimized for size atm. It would be easy to drop away things that are not relevant for the frontend in general or for the advanced build. Few ideas: • drop the automatic router algo selection => forcing a linear-router (could be the default) would mean dead code elimination would drop away all the other impls • have an option to remove the route conflict resolution and pretty error messages • a lot of other small things

ikitommi05:05:35

the current linear-router is using the trie, could swap add the original, bit slower impl, that would make the whole trie go away with just some extra code in the impl.

ikitommi05:05:48

did a quick dirty code removal to see how small it can go, I think ~20kb should be reachable

ikitommi05:05:52

to balance between perf and size, any clues for: • how to automatically test the routing perf with cljs? (e.g. kaocha running something that gives numbers) • should there be some (compiler) options to include/remove things like route conflict resolution?

ikitommi05:05:41

as the route trees can be created dynamically (e.g. load from backend/json/edn files), I think there are cases when one want’s to have the route conflict resolution enabled for prod. for static route trees, it can be removed, removing 5kb+ of code.

ikitommi05:05:48

The latest React router is 8Kb, not going to be that small, things like protocols seem to generate a lot of js.

ikitommi05:05:08

(defprotocol Matcher
  (match [this i max path])
  (view [this])
  (depth ^long [this])
  (length [this]))

(view (reify Matcher (view [this] true)))

ikitommi05:05:17

/**
 * @interface
 */
cljs.user.Matcher = function(){};

cljs.user.match = (function cljs$user$match(this$,i,max,path){
  if((((!((this$ == null)))) && ((!((this$.cljs$user$Matcher$match$arity$4 == null)))))){
    return this$.cljs$user$Matcher$match$arity$4(this$,i,max,path);
  } else {
    var x__18528__auto__ = (((this$ == null))?null:this$);
    var m__18529__auto__ = (cljs.user.match[goog.typeOf(x__18528__auto__)]);
    if((!((m__18529__auto__ == null)))){
      return m__18529__auto__.call(null,this$,i,max,path);
    } else {
      var m__18526__auto__ = (cljs.user.match["_"]);
      if((!((m__18526__auto__ == null)))){
        return m__18526__auto__.call(null,this$,i,max,path);
      } else {
        throw cljs.core.missing_protocol.call(null,"Matcher.match",this$);
      }
    }
  }
});

cljs.user.view = (function cljs$user$view(this$){
  if((((!((this$ == null)))) && ((!((this$.cljs$user$Matcher$view$arity$1 == null)))))){
    return this$.cljs$user$Matcher$view$arity$1(this$);
  } else {
    var x__18528__auto__ = (((this$ == null))?null:this$);
    var m__18529__auto__ = (cljs.user.view[goog.typeOf(x__18528__auto__)]);
    if((!((m__18529__auto__ == null)))){
      return m__18529__auto__.call(null,this$);
    } else {
      var m__18526__auto__ = (cljs.user.view["_"]);
      if((!((m__18526__auto__ == null)))){
        return m__18526__auto__.call(null,this$);
      } else {
        throw cljs.core.missing_protocol.call(null,"Matcher.view",this$);
      }
    }
  }
});

cljs.user.depth = (function cljs$user$depth(this$){
  if((((!((this$ == null)))) && ((!((this$.cljs$user$Matcher$depth$arity$1 == null)))))){
    return this$.cljs$user$Matcher$depth$arity$1(this$);
  } else {
    var x__18528__auto__ = (((this$ == null))?null:this$);
    var m__18529__auto__ = (cljs.user.depth[goog.typeOf(x__18528__auto__)]);
    if((!((m__18529__auto__ == null)))){
      return m__18529__auto__.call(null,this$);
    } else {
      var m__18526__auto__ = (cljs.user.depth["_"]);
      if((!((m__18526__auto__ == null)))){
        return m__18526__auto__.call(null,this$);
      } else {
        throw cljs.core.missing_protocol.call(null,"Matcher.depth",this$);
      }
    }
  }
});

cljs.user.length = (function cljs$user$length(this$){
  if((((!((this$ == null)))) && ((!((this$.cljs$user$Matcher$length$arity$1 == null)))))){
    return this$.cljs$user$Matcher$length$arity$1(this$);
  } else {
    var x__18528__auto__ = (((this$ == null))?null:this$);
    var m__18529__auto__ = (cljs.user.length[goog.typeOf(x__18528__auto__)]);
    if((!((m__18529__auto__ == null)))){
      return m__18529__auto__.call(null,this$);
    } else {
      var m__18526__auto__ = (cljs.user.length["_"]);
      if((!((m__18526__auto__ == null)))){
        return m__18526__auto__.call(null,this$);
      } else {
        throw cljs.core.missing_protocol.call(null,"Matcher.length",this$);
      }
    }
  }
});

cljs.user.view.call(null,(function (){
  if((typeof cljs !== 'undefined') && (typeof cljs.user !== 'undefined') && (typeof cljs.user.t_cljs$user219 !== 'undefined')){
  } else {

    /**
* @constructor
 * @implements {cljs.core.IWithMeta}
 * @implements {cljs.core.IMeta}
 * @implements {cljs.user.Matcher}
*/
    cljs.user.t_cljs$user219 = (function (meta220){
      this.meta220 = meta220;
      this.cljs$lang$protocol_mask$partition0$ = 393216;
      this.cljs$lang$protocol_mask$partition1$ = 0;
    });
    cljs.user.t_cljs$user219.prototype.cljs$core$IWithMeta$_with_meta$arity$2 = (function (_221,meta220__$1){
      var self__ = this;
      var _221__$1 = this;
      return (new cljs.user.t_cljs$user219(meta220__$1));
    });

    cljs.user.t_cljs$user219.prototype.cljs$core$IMeta$_meta$arity$1 = (function (_221){
      var self__ = this;
      var _221__$1 = this;
      return self__.meta220;
    });

    cljs.user.t_cljs$user219.prototype.cljs$user$Matcher$ = cljs.core.PROTOCOL_SENTINEL;

    cljs.user.t_cljs$user219.prototype.cljs$user$Matcher$view$arity$1 = (function (this$){
      var self__ = this;
      var this$__$1 = this;
      return true;
    });

    cljs.user.t_cljs$user219.getBasis = (function (){
      return new cljs.core.PersistentVector(null, 1, 5, cljs.core.PersistentVector.EMPTY_NODE, [new cljs.core.Symbol(null,"meta220","meta220",(2137741028),null)], null);
    });

    cljs.user.t_cljs$user219.cljs$lang$type = true;

    cljs.user.t_cljs$user219.cljs$lang$ctorStr = "cljs.user/t_cljs$user219";

    cljs.user.t_cljs$user219.cljs$lang$ctorPrWriter = (function (this__18465__auto__,writer__18466__auto__,opt__18467__auto__){
      return cljs.core._write.call(null,writer__18466__auto__,"cljs.user/t_cljs$user219");
    });

    /**
 * Positional factory function for cljs.user/t_cljs$user219.
 */
    cljs.user.__GT_t_cljs$user219 = (function cljs$user$__GT_t_cljs$user219(meta220){
      return (new cljs.user.t_cljs$user219(meta220));
    });

  }

  return (new cljs.user.t_cljs$user219(cljs.core.PersistentArrayMap.EMPTY));
})()
                   );

👀 4
orestis06:05:02

Now I’m curious to see if deftype makes things smaller.

isak16:05:53

wow, that is a lot of js

orestis06:05:44

It’s a sticky problem in CLJS I think. It’s not very high in my priority list (not a huge pain yet) but once I have some time I’m also curious to see if GCC can go really deep in the DCE and remove unused stuff.

orestis06:05:36

I think that frontend code is generally much less sensitive about performance. But it sucks to be forced to make a decision at a library level.

juhoteperi06:05:44

The problem is that Reitit selects the router implementation on runtime, so DCE can't optimize them away. There is no easy way to fix this, will require quite big breaking change to change the API so that the router selection is done by user or something.

juhoteperi06:05:34

Maybe the default router can be changed to use a bit simplified router selection logic, and then we add another function where user provides the router implementation.

ikitommi06:05:19

this was my quick hack for router selection:

#?(:clj  (cond
           router router
           (and (= 1 (count compiled-routes)) (not wilds?)) single-static-path-router
           path-conflicting quarantine-router
           (not wilds?) lookup-router
           all-wilds? trie-router
           :else mixed-router)
   :cljs (or router linear-router))

ikitommi06:05:44

good thing is that linear-router works for all cases, just naive/slow. might not matter in the browser. would need to test the 100+ routes, how long it takes to match the last one with linear. if that’s ok, would be a quick win.

mkvlr07:05:24

sounds good, we force a linear router for cljs anyway

juhoteperi07:05:30

Yeah that should be good default. User can then select other implementations if needed.

Ruben.Hamers07:05:02

Hi guys. I'm looking into the reitit library and so far it looks really great. I like the data-oriented approach! I studied the examples and I'm now trying to wrap my head around how to properly separate an API implementation in multiple files / namespaces. (All examples, for simplicity purposes i think, are all slammed into 1 file) Could anyone point me to / explain how to setup a idiomatic reitit api?

dharrigan08:05:57

I have all my routes in one file 🙂 You could separate them by functionality I suppose, say a Foo API namespace and a Bar API namespace. Entirely up to you 🙂

Ruben.Hamers08:05:14

yeah, what I essentially want is to separate the routes into different files and also put all handlers in a `business logic package'. In this example: https://github.com/metosin/reitit/blob/master/examples/ring-swagger/src/example/server.clj everything is in 1 file. But is this idiomatic design for reitit apps, is there somekind of standard?

Ruben.Hamers08:05:08

So I would have a file for /file where are routes for /file would be defined

Ruben.Hamers08:05:38

same for /math

valerauko08:05:11

reitit routes are just vectors so splitting them up isn't hard

valerauko08:05:14

it's good when you have tons of routes

Ruben.Hamers08:05:38

Yeah exactly. Ill read through the repo you sent me. I was just wondering if there was some standard to handle the routing and handlers

Ruben.Hamers08:05:31

The kitsune repo seems to be very close to what I want, Thx!

👍 4
valerauko09:05:51

i don't think there's a standard. i prefer to split my routes when the list of handler/spec require just gets too long

ikitommi11:05:28

would you like to do a PR of this?