helix

https://github.com/Lokeh/helix
2020-01-27T15:01:31.051700Z

hi, I started using helix, switching from uix -> hx -> helix, but I still have problem with rules when camel-case conversion is applied, let’s say I’m getting some native react component (coming from a library) nd then using this element in place ($ myEl {:styles …}), helix decides to not treat myEl as native component and does not convert props to native js. I cannot really apply ^:native metadata to myEl because it is a symbol bound to a native js ReactElement, and I cannot attach cljs metadata to it. is there any solution?

2020-01-27T15:06:54.052300Z

ah, ^:native override works with $ macro, but it does not with $$

2020-01-27T15:07:56.053300Z

and my react element type is react.forward_ref, so this is maybe similar issue like my recent post in #hx channel

2020-01-27T15:19:13.055Z

just looking at https://reactjs.org/docs/react-api.html#createelement, it sound like type can be a “react component type”, which is probably my case forwardRef: https://reactjs.org/docs/react-api.html#reactforwardref pointing to native react component and that wants to consume native props

2020-01-27T15:19:49.055500Z

but it could be another simlar type, like memo or lazy, there would be the same issue I guess

2020-01-27T15:27:21.060400Z

and this maybe brings another more general question, I would expect that all react components created by my helix code convert props to native js props and all defnc components would give me a bean from them. it looks to me that you have some heuristics here[1] and skip this conversion when you think the consuming component is a helix component - I understand that this could be an optimization, but it leads to theses issues with more dynamic code, I’d like to strive for correctness first, I would explore a way how to do a conversion to native props lazily (e.g. via lazy js getters and let consuming helix component access cached cljs data if it finds them) - this way no heuristics would be needed [1] https://github.com/Lokeh/helix/blob/732453738a19c7c97d471c995f7471f3527b8917/src/helix/core.clj#L23-L27

2020-01-27T16:02:39.061300Z

hm, I should probably open some issues on github, this line looks outdated compared to the link above: https://github.com/Lokeh/helix/blob/732453738a19c7c97d471c995f7471f3527b8917/src/helix/core.cljs#L46

lilactown 2020-01-27T17:16:38.061900Z

that last one is a bug, yeah

lilactown 2020-01-27T17:17:10.062500Z

help me understand what you mean by forwardRef. you have to pass forwardRef a component (not a native element), I thought?

lilactown 2020-01-27T17:17:58.063100Z

I think seeing a slice of your code would help

lilactown 2020-01-27T17:18:44.063900Z

the heuristic that we are talking about is purely about whether to do camel->kebab conversion and deep conversion of :style prop when passing props in. it doesn’t have anything to do with how you consume props

lilactown 2020-01-27T17:21:47.066200Z

if you create your forwardRef component like so:

(defnc ForwardedDiv [props ref]
  {:wrap [(react/forwardRef)]}
  (d/div {:ref ref & props}))
it should do what you want. if not, it’s a bug

lilactown 2020-01-27T17:23:16.067300Z

does that match what you’re doing?

2020-01-27T17:25:46.068500Z

@lilactown thanks for help, I’m going to push my project and show you the problems exactly

lilactown 2020-01-27T17:27:53.068700Z

👍

2020-01-27T17:29:03.069400Z

needed this: https://github.com/Lokeh/helix/pull/7, please consider merging or drop my PR and write your own version

lilactown 2020-01-27T17:34:08.070700Z

I agree with this change, but I’d also like to understand why using $$ is necessary. it should be an escape hatch; if there’s some way I can make the $ fit your case then I’d like to do that as well

2020-01-27T17:34:32.070800Z

@lilactown I have just pushed my current version to https://github.com/binaryage/cljs-react-three-fiber/tree/helix/examples

lilactown 2020-01-27T17:35:11.071Z

great

lilactown 2020-01-27T17:35:23.071700Z

I like the <component> naming 😄

2020-01-27T17:36:10.072600Z

it would be nice for helix.dom macros as well, <div> etc. would minimize clashes with existing stuff and one could refer it directly

lilactown 2020-01-27T17:37:01.073300Z

where is react-three-fiber.core?

2020-01-27T17:37:34.073800Z

in the repo root

lilactown 2020-01-27T17:37:36.073900Z

is that defined in code? or an extern?

lilactown 2020-01-27T17:37:58.074500Z

👍

lilactown 2020-01-27T17:39:06.075600Z

I think that the ^:native metadata here is fine. either that, or you can hide it behind a component:

(defnc <canvas> [props]
  ($ ^:native Canvas {& props}))

2020-01-27T17:39:29.076200Z

sounds good!

2020-01-27T17:39:58.077200Z

but it would be even better if I didn’t have to think about this :native flag

2020-01-27T17:40:04.077400Z

interop should be something seamless

2020-01-27T17:40:07.077600Z

ideally

2020-01-27T17:41:42.079400Z

btw. only first 4 demos are ported to helix so far

2020-01-27T17:42:05.080100Z

will finish it today and then hopefully refine it

2020-01-27T17:42:19.080700Z

still using use-state from uix, I quite like it

lilactown 2020-01-27T17:43:36.082200Z

I agree with you on interop, but maybe not in the way you’re think. in general, I would expect interoping with external components to involve: • using :camelCase props • passing the appropriate type (e.g. JS objects instead of maps, arrays instead of vectors) as props my philosophy is that helix should make these explicit. for props, it increases grepability. and for both, there aren’t a bunch of rules you have to remember or problems you get into when you’re serializing things to JS objects and then deserializing them in event handlers

2020-01-27T17:44:14.082800Z

btw. also something like this could be part of helix, react is explicit about props.children to be opaque data structure https://github.com/binaryage/cljs-react-three-fiber/blob/helix/examples/src/app/react_three_fiber/examples/lib/ui.cljs#L17-L36

👌 1
2020-01-27T17:44:44.083400Z

if you pass only one child, children is not an array for example, but the raw child

2020-01-27T17:46:31.084800Z

why would you even had to think about interop? all components are react component, only helix-originated components have a wrapper on “input” and “output”

2020-01-27T17:46:53.085300Z

this wrapper should be smart enough to do no conversion when you nest multiple helix components

lilactown 2020-01-27T17:47:48.086600Z

helix components aren’t wrapped. they receive JS props just like any other React component

lilactown 2020-01-27T17:48:15.087400Z

it’s only inside the body of a defnc that they get shallowly converted to a map-like object for destructuring etc.

2020-01-27T17:48:42.087800Z

so why is ^:native needed?

lilactown 2020-01-27T17:49:21.088500Z

$ is some sugar to let you write (react/createElement #js {:my-prop-one foo :my-prop-two bar})

lilactown 2020-01-27T17:50:09.089400Z

the ^:native metadata is an escape hatch I added. in react-dom, because of the ubiquity of div span etc. I opted to allow those to be written using kebab-case

lilactown 2020-01-27T17:50:24.089800Z

the ^:native metadata can also be added to do the kebab-case conversion

lilactown 2020-01-27T17:50:57.090800Z

it came up when someone was trying to write a wrapper for React Native’s components similar to helix.dom

2020-01-27T17:51:06.091100Z

but I want all my cljs code to use kebab by convention, no matter if using native or helix components

2020-01-27T17:51:25.091800Z

and I want all components to use camelCase when used from js code

2020-01-27T17:52:06.092900Z

and I want escape hatch on individual keys see https://github.com/roman01la/uix/pull/41

lilactown 2020-01-27T17:52:15.093200Z

:man-shrugging: that’s not how helix works. the props you give a component is what it expects. If you have a component you’re going to expose to the outside world, it should take the correctly cased props as it’s API

lilactown 2020-01-27T17:53:13.094300Z

if you want to use kebab casing everywhere in your app code, it’s not too much work to create a few smart wrappers that will do the casing for you. that’s where the ^:native escape hatch can come in

2020-01-27T17:53:36.094800Z

hmm, I would say, then there should be no magical camel case conversion and user really needs to be consistent

lilactown 2020-01-27T17:54:08.095500Z

in general, there isn’t any magical camel case conversion other than for helix.dom

2020-01-27T17:54:50.096200Z

hmm, all my three-js components got converted when used as keywords in $

2020-01-27T17:55:11.096800Z

and that is what I actually wanted 🙂

lilactown 2020-01-27T17:56:34.098Z

yeah, that’s correct. your case seems far more strange because of the usage of a different renderer

2020-01-27T17:56:45.098400Z

anyways for a newcomer, I think it is quite big mental overhead to wrap his head around these rules

2020-01-27T17:57:16.099300Z

now I understand it, but using it as keyword works differently than importing it as a symbol, which could be quite puzzling for someone

lilactown 2020-01-27T17:58:05.100100Z

are there cases where something could be used as both a keyword or a component?

2020-01-27T17:59:46.101700Z

I don’t know, but if you do it, then it behaves differently

lilactown 2020-01-27T18:00:05.102200Z

@darwin I do appreciate your feedback. this has given me a lot to think about. I feel like the story when using helix.dom is very nice because this is all opaque, but branching out into these other renderers is starting to show chinks in the logic

2020-01-27T18:00:07.102300Z

have to go, will be back in 30mins

lilactown 2020-01-27T18:12:36.103300Z

some quick reviews: https://github.com/binaryage/cljs-react-three-fiber/blob/helix/examples/src/app/react_three_fiber/examples/demos/font.cljs#L110 this $$ can be converted to ($ :scene {:name "scene" & props})

lilactown 2020-01-27T18:13:18.104300Z

($ :bufferGeometry {:attach "geometry" & (bean (get-gltf-geometry gltf 1)))

lilactown 2020-01-27T18:13:38.104600Z

the line below that can similarly be converted using the & prop

2020-01-27T18:15:12.105500Z

I’m back, yep good points, have to learn about & option, thanks!

2020-01-27T18:16:35.106Z

the only problem is that cursive highlights & as unresolved symbol

2020-01-27T18:17:12.106600Z

would you consider adding the same functionality with :& keyword?

lilactown 2020-01-27T18:19:01.107100Z

ah that sucks

lilactown 2020-01-27T18:19:42.108Z

maybe. I didn’t want to remove people’s potential component API 😄

2020-01-27T18:20:38.108700Z

alternatively, I could define dummy & and refer it, it would be worse

2020-01-27T18:21:28.109700Z

I strive to have my main code without unresolved symbols, and move all problematic interop-y stuff under some kitchen-sink namespace where I don’t look that often

2020-01-27T18:21:46.110300Z

but I don’t want to disable unresolved symbols highlighting, that is very useful in day-to-day work

lilactown 2020-01-27T18:21:51.110500Z

could even include that as part of helix.core

2020-01-27T18:23:10.111400Z

but personally I would go with my own wrapper macro over defnc and convert those on my side

2020-01-27T18:24:17.112500Z

with the idea (above) that conversion is happening all the time, :& prop is invalid anyways, because it has no good conversion in js world

lilactown 2020-01-27T18:25:08.113200Z

it stringifies it. so it would be an "&" prop which is valid (although not valid JSX)

2020-01-27T18:25:39.113500Z

I see

2020-01-27T18:26:30.114300Z

or make the macro more sophisticated and interpret some (merge ...) cases

2020-01-27T18:26:50.114800Z

it would read well and could be copy&pasted outside

2020-01-27T18:27:27.115700Z

and throw error when you encounter too-dificult to understand form for static analysis

2020-01-27T18:27:41.116300Z

so user would then use $$ or rewrite it into supported form

2020-01-27T18:28:52.118Z

you could support stuff like (merge props1 {:my “map”} props2 {:another “map”}) etc.

2020-01-27T18:29:03.118500Z

which is probably not supported now with &

lilactown 2020-01-27T18:29:38.119100Z

I think I’d rather continue to use the & key and export it from helix.core like:

(def &
  "The & key can be used in helix create element macros ($, helix.dom) to merge map-like objects into static props. This symbol is exported to help with warnings about undefined code."
  '&)

lilactown 2020-01-27T18:30:10.119800Z

you can do:

($ foo {& (merge props1 {:my "map"} props2 {:another "map"})}) 

2020-01-27T18:32:27.120900Z

ok, I’m not too opinionated about it, that is a solution, but thinking about refering it still feels like an unnecessary dance

lilactown 2020-01-27T18:33:17.121900Z

Ideally cursive would have some way of adding these symbols to a list of global ignores. or respecting macros in some other way

2020-01-27T18:33:30.122300Z

also & or :& does not look very well when I put it on a new line and reformat my code, it gets aligned with other map keys

2020-01-27T18:33:55.122600Z

it looks nice as oneliner though

lilactown 2020-01-27T18:34:22.123Z

it does look a little different but I don’t hate it. It could be familiarity at this point.

2020-01-27T20:22:39.123700Z

hmm, use-effect should have a dynamic version as well, or at least warn in deps-macro-body that it was passed something else than expeced

2020-01-27T20:23:28.124400Z

I was passing deps via function argument (local symbol) and it silently compiled into no call

lilactown 2020-01-27T20:25:17.125400Z

it can be ambiguous what the caller wants in some cases, but I might check for the truly meaningless case of:

(use-effect
  [foo]
  bar)
which it sounds like is what you are running into?

2020-01-27T20:25:58.126200Z

(use-effect deps …) and deps was a local symbol

2020-01-27T20:26:12.126500Z

I was passing it into my function as a param

lilactown 2020-01-27T20:26:41.126900Z

interesting, yes that should be an error

2020-01-27T20:26:58.127200Z

the cond in deps-macro-body emits nothing

2020-01-27T20:27:19.127700Z

you should probably add an :else branch with some kind of exception

2020-01-27T20:27:36.127900Z

or emit dynamic code in that case

lilactown 2020-01-27T20:28:07.128300Z

the hooks dependencies should be static every render so I think it should be written literally

lilactown 2020-01-27T20:28:20.128700Z

I’m trying to remember how to emit a warning

2020-01-27T20:29:06.129400Z

I agree that this is really an edge case, depends how far you want to go with supporting this deps stuff in js I can pass deps as parameters, they don’t have to be in local scope

2020-01-27T20:29:45.130100Z

I believe

lilactown 2020-01-27T20:29:51.130300Z

I’m not sure what you mean

lilactown 2020-01-27T20:30:52.131500Z

I agree that you can do:

let deps = [foo, bar];
useEffect(() => doThing(foo, bar), deps);
but I don’t think you get much out of it. I would call that out in a code review that the deps should be written inline

lilactown 2020-01-27T20:31:57.132600Z

ahh interesting

lilactown 2020-01-27T20:32:28.133200Z

I hadn’t thought about custom hooks that would want to forward dependencies

2020-01-27T20:33:02.134Z

I think correct solution for your impl of use-effect would be to have a separate dynamic version, and fallback on it when you encounter non-static deps case

lilactown 2020-01-27T20:33:32.134700Z

the problem here is that if someone passes a vector in, then it will be an actual vector and not get converted to a JS array

2020-01-27T20:33:44.135Z

in your dynamic version you should handle all the semantics you have in the macro, e.g. :only :always etc

2020-01-27T20:34:56.135800Z

you can detect static vectors and everything else will be converted into-array if it is dynamic vector (in that dynamic branch)

lilactown 2020-01-27T20:35:02.136Z

yeah

lilactown 2020-01-27T20:35:35.136700Z

I think adding an :else (to-array deps)` branch would fix it

2020-01-27T20:36:06.137200Z

well, it would work only partially, what if deps is bound to :only?

2020-01-27T20:36:37.137800Z

you don’t want your users to undertand impl details of your use-effect

2020-01-27T20:37:00.138400Z

it must work the same for both cases dynamic and static

2020-01-27T20:37:17.138800Z

if you don’t want to deal with dynamic case, then throw and call it a day

2020-01-27T20:37:25.139100Z

better solution than doing inconsitent partial work

lilactown 2020-01-27T20:38:01.139700Z

yes, I see what you mean. unfortunately, I cannot infer the :auto-deps case in a custom hook if dynamic deps are passed in

2020-01-27T20:38:30.139900Z

ah, good point

2020-01-27T20:38:49.140500Z

so maybe throw on cases you don’t want to impl or cannot support

2020-01-27T20:39:26.141200Z

I’m still not sold on this auto-deps stuff

lilactown 2020-01-27T20:39:36.141800Z

I’m sort of confused by the useCannon example. I wonder why it doesn’t simply add the props and fn as deps

2020-01-27T20:39:47.142100Z

I would rather see it as a warning if your deps vector is not in agreement with static analysis

2020-01-27T20:39:59.142300Z

with an option to silence it

lilactown 2020-01-27T20:40:03.142500Z

that’s fair

2020-01-27T20:40:35.143100Z

for code reader it is better to see the deps explicitely and be aware that something important changed when touching the code

2020-01-27T20:40:56.143500Z

not sure, this is my first react app with hooks and deps

2020-01-27T20:41:21.143800Z

I like that you swapped order of deps and the fn itself

2020-01-27T20:41:55.144400Z

what I don’t like is that auto-deps forces mi to put fn body inline

2020-01-27T20:42:30.145100Z

sometimes I tend to define fns separately and then reference them for better code shape

lilactown 2020-01-27T20:42:43.145300Z

hm I see

lilactown 2020-01-27T20:43:22.146100Z

you can always do:

(defn do-thing! [foo bar]
   ...)

...
  (use-effect
   :auto-deps
   (do-thing! foo bar))

lilactown 2020-01-27T20:43:46.146500Z

but it can get hard to parameterize over lots of complex values

lilactown 2020-01-27T20:45:54.148Z

I will think about adding the linting as well. In practice, I have begun to agree that I like seeing the explicit deps

2020-01-27T20:47:13.149200Z

I’m thinking if this form wouldn’t be possible: (use-effect (fn [foo bar] ...)) which would be rewritten into code similar to above, foo and bar could be new names for fn scope, the use-effect macro would use that fn param list as deps and it would look natural

2020-01-27T20:48:27.149900Z

you would not have this handling of deps argument because important info can be inferred from the fn param list

lilactown 2020-01-27T20:49:30.150600Z

it still wouldn’t fix the current problem which is forwarding deps in custom hooks. it might even making it.. weirder

2020-01-27T20:50:08.151300Z

true

lilactown 2020-01-27T20:51:28.152Z

frankly I think this useCannon hook is bugged

lilactown 2020-01-27T20:52:39.152300Z

hmm

lilactown 2020-01-27T20:53:24.152900Z

I guess it’s routing around the need for users to aggressively useCallback their fn they pass in

lilactown 2020-01-27T20:54:23.153200Z

I wonder if this would be helped by a defhook macro

2020-01-27T20:59:19.157700Z

I can’t really say, don’t understand it that well, I just rewrote it hopefully 1:1

lilactown 2020-01-27T21:00:57.159500Z

FYI you can always use react/useEffect for custom hooks or helix.hooks/use-effect* which is just a proxy that does the conversion from vectors to arrays for deps, and returning js/undefined appropriately

2020-01-27T21:01:17.160100Z

another topic: I think I can force helix do what I wanted with naming props, 1) use ^:native everywhere, and then hack extract-cljs-props to give me a bean with custom :key->prop and :prop->key which will be mapping names from camecase back to dashes

2020-01-27T21:01:40.160900Z

so my components can stay in dash-land but underlying react components talk camelcase

2020-01-27T21:02:31.161200Z

yes, but I want to stick only to one method, if I adopt your wrapper I want to use it everywhere

lilactown 2020-01-27T21:04:21.161700Z

you could do that, yep

2020-01-27T21:04:53.162400Z

I have all the demos working, just need one extra patch to allow quoted keys

2020-01-27T21:05:13.162900Z

currently there is no easy way how to prevent camelCase conversion selectively on individual keys

2020-01-27T21:07:09.163400Z

btw. impl.utils don’t seem to be used anywhere

2020-01-27T21:07:17.163600Z

helix.impl.utils

lilactown 2020-01-27T21:07:45.164100Z

thanks, its usage was removed in a refactoring

lilactown 2020-01-27T21:08:44.164900Z

what’s your use case where you want to opt out of camelCase conversion sometimes?

lilactown 2020-01-27T21:09:04.165300Z

it should handle aria- and data- fields already

2020-01-27T21:09:48.166200Z

dashes are used to go deeper into objects in three.js, I guess

lilactown 2020-01-27T21:09:57.166400Z

😵

2020-01-27T21:10:35.166800Z

btw. using replace with function should be more perfomant than orig impl

2020-01-27T21:11:11.167600Z

if you wanted I could provide tailored :cljs branches for going directly via interop without clojure core

lilactown 2020-01-27T21:12:15.167800Z

sure, that would be helpful

2020-01-27T21:12:36.168100Z

something like this: https://gist.github.com/darwin/e1d990dea50d153b4a7474f59653cc80

lilactown 2020-01-27T21:12:51.168400Z

I’m slowly being convinced camelCasing all the time

lilactown 2020-01-27T21:13:12.168900Z

I think this would be a backwards compatible change, and it would make the life of everyone not using react-dom a lot easier

lilactown 2020-01-27T21:14:02.170400Z

I think there would still need to be some determination of whether a value is “native” or not, when deciding whether to recursively convert the :style prop to JS. but maybe I could just implement that in helix.dom instead of concerning the $ / $$ with that

2020-01-27T21:14:07.170500Z

I would vote for doing nothing by default, but providing hooks for people to pick different policy or own functions

2020-01-27T21:14:22.170800Z

not sure about performance, because this will be a hot path

lilactown 2020-01-27T21:14:44.171300Z

yes, that is the reason I de-opted for converting to camelCase at one point

lilactown 2020-01-27T21:15:04.172Z

but if people are using $, the performance should be negligible because props will be converted at macro time if they’re written statically

2020-01-27T21:15:32.172400Z

yes that’s what I like the most on helix, that static conversion

2020-01-27T21:15:49.172900Z

also that cljs keywords will become strings in rewritten code

2020-01-27T21:16:23.173600Z

I looked at uix results in advanced mode, it optimizes well, but there stayed a bunch of cljs keyword objects, which should ideally go away

2020-01-27T21:17:12.174400Z

I still think I will be able to get the best of both worlds, and convert only when dynamically crossing boundary between js and cljs land

2020-01-27T21:18:51.175200Z

or maybe only in dynamic cases which are rare

2020-01-27T21:19:34.176200Z

btw. your current “& props” idiom expects native js objects? didn’t see ->js conversion there

lilactown 2020-01-27T21:19:55.176600Z

it expects a map. I want to extend it to work with JS objs too

lilactown 2020-01-27T21:22:10.177600Z

when it detects & it emits a call to -native-props on the CLJS side, which does a shallow conversion of the map-like into a JS object using the same rules

2020-01-27T21:23:27.178Z

ah, good, thanks for explanation

2020-01-27T21:25:45.178200Z

I have just updated the pull request

2020-01-27T21:26:23.178900Z

some tests would be nice, I didn’t try the clj path, but its generic code worked under cljs for me

2020-01-27T21:34:41.179200Z

wait, the PR is broken I think

2020-01-27T21:35:55.179700Z

I misplaced close paren of that reader tag

2020-01-27T21:37:31.180400Z

fixed

2020-01-27T21:38:11.181300Z

I’m not a fan of cljc files, I’d rather write it twice 🙂

lilactown 2020-01-27T21:39:16.181900Z

hehehe. in these instances where I’m trying to mirror the same behavior I feel like it helps me sync changes to both

lilactown 2020-01-27T21:39:30.182200Z

I’ll need to circle back on this later today / early tomorrow, my day job needs my attention for a bit

2020-01-27T21:39:51.182900Z

sure. no worries, thanks for all your help

2020-01-27T21:39:59.183400Z

helix looks very promising

❤️ 1
lilactown 2020-01-27T21:40:06.183700Z

I really appreciate you trying out helix and all of the feedback you’ve given me. PRs are the cherry on top. it’s given me a lot to think about! and will help a lot

2020-01-27T22:12:37.184500Z

FYI, I have just compiled in release mode (via shadow-cljs) and the keywords related to hiccup really went away (nice!)

2020-01-27T22:13:01.185Z

but the code preparing and setting displayName is still there, I would expect it to be elided in release mode

lilactown 2020-01-27T22:16:27.185400Z

I would expect that too. it should rely on goog/DEBUG https://github.com/Lokeh/helix/blob/master/src/helix/core.clj#L145

lilactown 2020-01-27T22:18:10.186300Z

i wonder if the output of cond-> is messing with it. I could pull it out into a separate expression from the def

2020-01-27T22:23:02.186700Z

it would probably need some help: https://gist.github.com/darwin/1bdf46da01b16ecc19410091fca7d325#file-box-js-L60

2020-01-27T22:23:44.187400Z

also I compared the shadow-cljs report abou sizes with uix and sometimes the js files are a tiny bit bigger

2020-01-27T22:24:06.188Z

no big deal, but there will be probably some room for improvements

2020-01-27T22:26:22.188500Z

that line above is $APP.$cljs$core$truth_$$(!1) && ($G__19540$$.displayName = "react-three-fiber.examples.demos.box/\x3cdemo\x3e"); with pseudo names

lilactown 2020-01-27T22:27:09.189Z

I bet uix and reagent will be tiny bit smaller since it’s actually emitting less code

lilactown 2020-01-27T22:28:44.190200Z

tradeoff of emitting less code and doing more abstraction at runtime

lilactown 2020-01-27T22:28:59.190600Z

but yes, probably work to be done there for helix. I think we can get close enough

👍 1