l############################## [2015-05-18] ############################## [05:43:23] Kurtis Rainbolt-Greene(@krainboltgreene):So what's the status @jgaskins? ---------------------------------------------------------------------------------------------------- [18:47:01] Jamie Gaskins(@jgaskins):@krainboltgreene Status of what? ---------------------------------------------------------------------------------------------------- ############################## [2015-05-19] ############################## [01:46:45] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins You're using clearwater at work, right? ---------------------------------------------------------------------------------------------------- [14:36:21] Jamie Gaskins(@jgaskins):@krainboltgreene Not yet. I'm working on convincing the CTO and other ranking officials that it's usable in its current form. I've converted a couple of our front-end apps over to it as demos/experiments. ---------------------------------------------------------------------------------------------------- ############################## [2015-05-24] ############################## [01:24:00] Jamie Gaskins(@jgaskins):TodoMVC on Clearwater: https://github.com/jgaskins/clearwater_todomvc/tree/master/app ---------------------------------------------------------------------------------------------------- [01:24:05] Jamie Gaskins(@jgaskins):Demo: https://clearwater-todomvc.herokuapp.com ---------------------------------------------------------------------------------------------------- ############################## [2015-06-21] ############################## [19:54:41] Rick Carlino(@RickCarlino):Hey guys- how's the project coming along? ---------------------------------------------------------------------------------------------------- [20:36:31] Kurtis Rainbolt-Greene(@krainboltgreene):We're usable, but not sure if production ready. ---------------------------------------------------------------------------------------------------- [20:36:55] Kurtis Rainbolt-Greene(@krainboltgreene):Most of my time is spent in ROM and Rubyscript now. ---------------------------------------------------------------------------------------------------- [20:55:41] Rick Carlino(@RickCarlino):Ah cool. Was curious, as I haven't heard too much about the project as of late. ---------------------------------------------------------------------------------------------------- ############################## [2015-06-23] ############################## [02:58:44] Jamie Gaskins(@jgaskins):@RickCarlino It's moving along quite well. I'm trying to spread the word about it a bit more. I spoke about it at RubyNation in DC a week and a half ago. There was quite a bit of excitement about it and I'd like to keep that momentum going. ---------------------------------------------------------------------------------------------------- [02:58:58] Jamie Gaskins(@jgaskins):@RickCarlino By the way, I saw your screencast today. Thanks for mentioning Clearwater! :-) ---------------------------------------------------------------------------------------------------- [03:01:20] Kurtis Rainbolt-Greene(@krainboltgreene):<3 ---------------------------------------------------------------------------------------------------- [03:06:02] Rick Carlino(@RickCarlino):@jgaskins NP! Always glad to further the cause of frontend Ruby! ---------------------------------------------------------------------------------------------------- ############################## [2015-08-25] ############################## [22:00:52] Jamie Gaskins(@jgaskins):Last night I started working on an idea for server-rendered components in Clearwater. It's as simple as this your app (an initializer in Rails, for example): ```ruby Opal.append_paths(shared_components_path) ``` … where `shared_components_path` is where your isomorphic code lives, like `"app/shared"`. Then you can just put `<%= MyComponent.new %>` in your server-side view. I still need to add the ability to use the router on the server to handle routing targets (which will likely change how you put the component in your Rails views), but it works pretty well. The branch is here: https://github.com/clearwater-rb/clearwater/tree/server-render ---------------------------------------------------------------------------------------------------- ############################## [2015-08-26] ############################## [00:13:02] Adrian Madrid(@aemadrid):interesting ---------------------------------------------------------------------------------------------------- ############################## [2015-08-30] ############################## [13:47:51] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins So right off the bat it seems like Clearwater::Application shouldn't be concerned with the element I'm hanging the root component, the components should be concerned with this. ---------------------------------------------------------------------------------------------------- [13:48:17] Kurtis Rainbolt-Greene(@krainboltgreene):Two, why is the application initialization split between #initialize and #call? ---------------------------------------------------------------------------------------------------- [13:48:48] Kurtis Rainbolt-Greene(@krainboltgreene):I mean in a frontend application how many times are you holding the applications state and not rendering? ---------------------------------------------------------------------------------------------------- [14:06:12] Kurtis Rainbolt-Greene(@krainboltgreene):Also, it seems they've taken out sourcemaps for opal latest? ---------------------------------------------------------------------------------------------------- [14:09:39] Jamie Gaskins(@jgaskins):For element on the Application, it's mostly because the components don't have any idea what they're rendering into. We don't have an equivalent of React's `findDOMNode()`.I did something like that before we added the vdom and it had weird side effects, like having to wrap rendered templates in a div to be able to ---------------------------------------------------------------------------------------------------- [14:10:04] Jamie Gaskins(@jgaskins):… do anything with it. ---------------------------------------------------------------------------------------------------- [14:10:28] Jamie Gaskins(@jgaskins):Source maps work okay for me. Are you on 0.8? ---------------------------------------------------------------------------------------------------- [14:10:51] Kurtis Rainbolt-Greene(@krainboltgreene):Interesting. ---------------------------------------------------------------------------------------------------- [14:10:58] Kurtis Rainbolt-Greene(@krainboltgreene):I'm actually using github latest. ---------------------------------------------------------------------------------------------------- [14:12:37] Kurtis Rainbolt-Greene(@krainboltgreene):Switching to 0.8 ---------------------------------------------------------------------------------------------------- [14:13:37] Jamie Gaskins(@jgaskins):Splitting instantiation from rendering seems weird at first, but it was really the only way I could test it. :-) Also, I worry about having side effects just on instantiation. We could provide a single-step class method like `Clearwater::Application.call(component: Foo.new)`which would initialize and then call. ---------------------------------------------------------------------------------------------------- [14:14:25] Jamie Gaskins(@jgaskins):But I do think initializing without rendering is a good option to have. ---------------------------------------------------------------------------------------------------- [14:15:05] Kurtis Rainbolt-Greene(@krainboltgreene):This sort of thing has been something I've been internally debating for a while. ---------------------------------------------------------------------------------------------------- [14:15:25] Kurtis Rainbolt-Greene(@krainboltgreene):Object.new().function() is essentially a namespaced function with a setup phase. ---------------------------------------------------------------------------------------------------- [14:17:15] Kurtis Rainbolt-Greene(@krainboltgreene):`NoMethodError: undefined method 'source_map_register' for Opal::Processor:Class` :( ---------------------------------------------------------------------------------------------------- [14:17:29] Jamie Gaskins(@jgaskins):Weird. ---------------------------------------------------------------------------------------------------- [14:18:00] Jamie Gaskins(@jgaskins):What framework are you using server-side? ---------------------------------------------------------------------------------------------------- [14:18:10] Kurtis Rainbolt-Greene(@krainboltgreene):None, this is a static application. ---------------------------------------------------------------------------------------------------- [14:19:13] Jamie Gaskins(@jgaskins):Ah, okay. I have no idea how to get Opal to work with those yet. I only just figured out how to get it to work with Roda yesterday. ---------------------------------------------------------------------------------------------------- [14:19:37] Kurtis Rainbolt-Greene(@krainboltgreene):They removed source_map_register, but didn't write why in their changelog. ---------------------------------------------------------------------------------------------------- [14:20:03] Jamie Gaskins(@jgaskins):Huh, now that you mention it, I remember seeing that in the commit log. ---------------------------------------------------------------------------------------------------- [14:28:01] Kurtis Rainbolt-Greene(@krainboltgreene):Looks like they do source mapping through ... middleware. ---------------------------------------------------------------------------------------------------- [14:29:01] Jamie Gaskins(@jgaskins):I tried to find the commit to see what the rationale was, but I can't find it. ---------------------------------------------------------------------------------------------------- [14:30:05] Kurtis Rainbolt-Greene(@krainboltgreene):I'm going to ahve to monkey patch to get maps. ---------------------------------------------------------------------------------------------------- [15:11:36] Kurtis Rainbolt-Greene(@krainboltgreene):Ah-ha. ---------------------------------------------------------------------------------------------------- [15:11:42] Kurtis Rainbolt-Greene(@krainboltgreene):Opal::Builder#source_map works ---------------------------------------------------------------------------------------------------- [15:29:56] Jamie Gaskins(@jgaskins):Nice! ---------------------------------------------------------------------------------------------------- [16:27:50] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins: `Uncaught NoMethodError: undefined method `router=' for #` Thoughts? ---------------------------------------------------------------------------------------------------- [16:27:54] Kurtis Rainbolt-Greene(@krainboltgreene):Wait, nevermind. ---------------------------------------------------------------------------------------------------- [16:28:15] Jamie Gaskins(@jgaskins):Did you forget to `include Clearwater::Component`? :-) ---------------------------------------------------------------------------------------------------- [16:28:41] Kurtis Rainbolt-Greene(@krainboltgreene):No, I pointed the router route to Object.new ---------------------------------------------------------------------------------------------------- [16:28:49] Jamie Gaskins(@jgaskins):hehe ---------------------------------------------------------------------------------------------------- [16:29:12] Kurtis Rainbolt-Greene(@krainboltgreene):Clearwater::Router and Earhart are similar enough that I'm confusing them. ---------------------------------------------------------------------------------------------------- [16:32:51] Jamie Gaskins(@jgaskins):For components that are routing targets, the router wires itself to the component so it can have access to the route params, so for a route `/articles/:article_id`, it can do `params[:article_id]`. If a component isn't a routing target, it can be a PORO that responds to `render` and returns vdom nodes or strings: ```ruby component = Object.new def component.render VirtualDOM.node('div', nil, 'this is a thing') end ``` ---------------------------------------------------------------------------------------------------- [16:34:22] Kurtis Rainbolt-Greene(@krainboltgreene):Interesting. ---------------------------------------------------------------------------------------------------- [16:35:37] Kurtis Rainbolt-Greene(@krainboltgreene):Argh. ---------------------------------------------------------------------------------------------------- [16:35:40] Kurtis Rainbolt-Greene(@krainboltgreene):`Cannot read property 'nodeType' of null` ---------------------------------------------------------------------------------------------------- [16:35:54] Jamie Gaskins(@jgaskins):I've been thinking of removing the expectation of `outlet` and `router` attr_accessors in routed components so you could do the same with them, so the router would check to see if they exist before setting them. ---------------------------------------------------------------------------------------------------- [16:36:10] Jamie Gaskins(@jgaskins):@krainboltgreene Did that not work? ---------------------------------------------------------------------------------------------------- [16:36:22] Kurtis Rainbolt-Greene(@krainboltgreene):I think this is something different. ---------------------------------------------------------------------------------------------------- [16:36:58] Jamie Gaskins(@jgaskins):Ah, okay ---------------------------------------------------------------------------------------------------- [16:39:34] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins If I push up, mind taking a look? ---------------------------------------------------------------------------------------------------- [16:39:46] Jamie Gaskins(@jgaskins):Sure ---------------------------------------------------------------------------------------------------- [16:42:16] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins https://github.com/socialkardia/dashboard/tree/clearwater ---------------------------------------------------------------------------------------------------- [16:42:23] Kurtis Rainbolt-Greene(@krainboltgreene):Ruby code in lib/ ---------------------------------------------------------------------------------------------------- [16:42:44] Jamie Gaskins(@jgaskins):@krainboltgreene Having a look now ---------------------------------------------------------------------------------------------------- [16:45:43] Jamie Gaskins(@jgaskins):@krainboltgreene How do I run it? ---------------------------------------------------------------------------------------------------- [16:46:03] Jamie Gaskins(@jgaskins):Oh, It's Jekyll. `rake watch`? ---------------------------------------------------------------------------------------------------- [16:46:11] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins No, sorry ---------------------------------------------------------------------------------------------------- [16:46:55] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins `bundle install --path gems/ && npm install && bower install && bin/build && node_modules/.bin/http-server output/` ---------------------------------------------------------------------------------------------------- [16:47:06] Kurtis Rainbolt-Greene(@krainboltgreene):Shouldn't taint anything on your machine. ---------------------------------------------------------------------------------------------------- [16:47:16] Jamie Gaskins(@jgaskins)::+1: ---------------------------------------------------------------------------------------------------- [16:50:00] Jamie Gaskins(@jgaskins):@krainboltgreene I've got an `Opal::Builder::MissingRequire`: `can't find file: "dashboard/models"`. ---------------------------------------------------------------------------------------------------- [16:50:13] Jamie Gaskins(@jgaskins):Did one of the files get missed in the commit? ---------------------------------------------------------------------------------------------------- [16:51:33] Kurtis Rainbolt-Greene(@krainboltgreene):Oh, just comment out that require. ---------------------------------------------------------------------------------------------------- [16:51:39] Kurtis Rainbolt-Greene(@krainboltgreene):I didn't commit it, it's just empty for now. ---------------------------------------------------------------------------------------------------- [16:51:43] Jamie Gaskins(@jgaskins):Cool ---------------------------------------------------------------------------------------------------- [16:51:53] Kurtis Rainbolt-Greene(@krainboltgreene):Same with clients ---------------------------------------------------------------------------------------------------- [16:57:31] Jamie Gaskins(@jgaskins):@krainboltgreene Ah, it looks like it's the `$document.body` call before the `` tag exists. If you move the `` gets it going. ---------------------------------------------------------------------------------------------------- [16:58:55] Kurtis Rainbolt-Greene(@krainboltgreene):15s+ build times is a bit of a pain. ---------------------------------------------------------------------------------------------------- [16:58:56] Jamie Gaskins(@jgaskins):The other alternative is to run `app.call` in a ready block: `$document.ready { app.call }` ---------------------------------------------------------------------------------------------------- [16:59:27] Jamie Gaskins(@jgaskins):Ouch. ---------------------------------------------------------------------------------------------------- [16:59:38] Kurtis Rainbolt-Greene(@krainboltgreene):This one was 50s! Haha. ---------------------------------------------------------------------------------------------------- [16:59:43] Kurtis Rainbolt-Greene(@krainboltgreene):Better keep my mouth shut. ---------------------------------------------------------------------------------------------------- [17:00:03] Kurtis Rainbolt-Greene(@krainboltgreene):Ouch, so Clearwater::Component doesn't have a
tag? ---------------------------------------------------------------------------------------------------- [17:00:22] Jamie Gaskins(@jgaskins):Umm... Good question. I thought I gave it all of the HTML5 tags. ---------------------------------------------------------------------------------------------------- [17:00:54] Jamie Gaskins(@jgaskins):@krainboltgreene Sure enough, you're right. I'll add that in real quick. ---------------------------------------------------------------------------------------------------- [17:02:18] Jamie Gaskins(@jgaskins):@krainboltgreene Try bundle updating clearwater ---------------------------------------------------------------------------------------------------- [17:06:03] Jamie Gaskins(@jgaskins):It's in there now on `master` ---------------------------------------------------------------------------------------------------- [17:13:03] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins Oh shit it works ---------------------------------------------------------------------------------------------------- [17:13:10] Kurtis Rainbolt-Greene(@krainboltgreene):This feels so good. ---------------------------------------------------------------------------------------------------- [23:39:20] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins: So would you be interesting in replacing Clearwater::Router with Earhart? ---------------------------------------------------------------------------------------------------- ############################## [2015-08-31] ############################## [22:21:01] Adrian Madrid(@aemadrid):just hate when they use todos as an example ---------------------------------------------------------------------------------------------------- [22:21:05] Kurtis Rainbolt-Greene(@krainboltgreene):I'm currently working on porting ROM.rb over for Clearwater. ---------------------------------------------------------------------------------------------------- [22:21:16] Adrian Madrid(@aemadrid):what happens when you have too much data to pull into the browser every time? ---------------------------------------------------------------------------------------------------- [22:21:25] Adrian Madrid(@aemadrid):that sounds interesting ---------------------------------------------------------------------------------------------------- [22:31:57] Kurtis Rainbolt-Greene(@krainboltgreene):ROM is Pure Ruby, so it's mostly about moving them away from dynamic requires. ---------------------------------------------------------------------------------------------------- [22:32:09] Adrian Madrid(@aemadrid):nice ---------------------------------------------------------------------------------------------------- [22:32:35] Kurtis Rainbolt-Greene(@krainboltgreene):Oh and then writing the adapters (localstorage, indexdb, websql, and http) ---------------------------------------------------------------------------------------------------- [00:17:03] Jamie Gaskins(@jgaskins):@krainboltgreene I'm not sure. Earhart has some things that aren't used on the front end, like HTTP verbs. `Clearwater::Router` is really simple and lightweight. It just maps the URL path to a path through the routing tree. ---------------------------------------------------------------------------------------------------- [00:21:33] Jamie Gaskins(@jgaskins):@krainboltgreene I'm not all that familiar with Earhart yet, so I'm actually really interested to see it. If you make a branch that uses it instead and it ends up being more flexible (this part is probably easy, I didn't build a lot of flexibility into CW::Router) and doesn't impact performance or payload size to any significant degree (this part might be a bit more challenging because CW::Router is tiny), that would be a fun discussion point. ---------------------------------------------------------------------------------------------------- [01:53:13] Kurtis Rainbolt-Greene(@krainboltgreene):I'm working on that now. ---------------------------------------------------------------------------------------------------- [02:09:02] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins So earhart's VERB stuff is actually just at the DSL layer. ---------------------------------------------------------------------------------------------------- [02:09:12] Kurtis Rainbolt-Greene(@krainboltgreene):At the object layer it's just a pattern matching dictionary. ---------------------------------------------------------------------------------------------------- [02:09:26] Kurtis Rainbolt-Greene(@krainboltgreene):Rather it's a dictionary with strings or regexp as keys. ---------------------------------------------------------------------------------------------------- [05:16:20] Jamie Gaskins(@jgaskins):@krainboltgreene Interesting. I'll have a look tomorrow at work so I can understand a bit better. ---------------------------------------------------------------------------------------------------- [21:14:05] Adrian Madrid(@aemadrid):@jgaskins what are the latest examples you have of CW apps? ---------------------------------------------------------------------------------------------------- [22:16:19] Kurtis Rainbolt-Greene(@krainboltgreene):@aemadrid: I'm working on one right now. ---------------------------------------------------------------------------------------------------- [22:16:32] Kurtis Rainbolt-Greene(@krainboltgreene):Are you looking for baked-in-rails or standalone? ---------------------------------------------------------------------------------------------------- [22:16:39] Adrian Madrid(@aemadrid):@krainboltgreene very cool ---------------------------------------------------------------------------------------------------- [22:16:54] Adrian Madrid(@aemadrid):standalone would work best for me ATM ---------------------------------------------------------------------------------------------------- [22:17:32] Adrian Madrid(@aemadrid):but anything that shows more of a multi-page (router) with forms/pagination/etc kinda app would be great ---------------------------------------------------------------------------------------------------- [22:17:48] Adrian Madrid(@aemadrid):trying to evaluate if going with react-rb or CW right now for a project ---------------------------------------------------------------------------------------------------- [22:18:13] Kurtis Rainbolt-Greene(@krainboltgreene):@aemadrid: Socialkardia's dashboard will be that, but I haven't done more than one route right now. ---------------------------------------------------------------------------------------------------- [22:18:32] Adrian Madrid(@aemadrid):@krainboltgreene saw that before ---------------------------------------------------------------------------------------------------- [22:18:33] Kurtis Rainbolt-Greene(@krainboltgreene):@aemadrid Do you want more than just components? ---------------------------------------------------------------------------------------------------- [22:19:30] Adrian Madrid(@aemadrid):dealing with forms and things like grids w/pagination are the two topics I’m not completely understanding in CW ---------------------------------------------------------------------------------------------------- [22:19:48] Kurtis Rainbolt-Greene(@krainboltgreene):That's basically the difference between react-rb and cw. Clearwater is: Components, Routers, Connections, Models. React.rb is: Components ---------------------------------------------------------------------------------------------------- [22:19:55] Adrian Madrid(@aemadrid):I knida get the idea of building components over components ---------------------------------------------------------------------------------------------------- [22:20:12] Kurtis Rainbolt-Greene(@krainboltgreene):Well pagination requires state. ---------------------------------------------------------------------------------------------------- [22:20:16] Adrian Madrid(@aemadrid):The idea of Models is very interesting too ---------------------------------------------------------------------------------------------------- [22:20:37] Kurtis Rainbolt-Greene(@krainboltgreene):React.rb doesn't give you any state mechanism, it relies on whatever you have available. ---------------------------------------------------------------------------------------------------- [22:20:40] Adrian Madrid(@aemadrid):you need some stores to do something interesting anyways ---------------------------------------------------------------------------------------------------- [22:20:44] Kurtis Rainbolt-Greene(@krainboltgreene):Right. ---------------------------------------------------------------------------------------------------- ############################## [2015-09-01] ############################## [00:27:30] Jamie Gaskins(@jgaskins):@aemadrid I'm working on some scripts for a screencast (my next two are components and routing), but if you're just looking for some example code, I could post a couple example apps to show routing. Adding routes is pretty simple. ---------------------------------------------------------------------------------------------------- [02:31:37] Adrian Madrid(@aemadrid):would love to see some example code ---------------------------------------------------------------------------------------------------- [04:42:48] Jamie Gaskins(@jgaskins):@aemadrid I've got some code I just need to polish up tomorrow, add some comments and things, and then I'll push to GH and push a demo of it to Heroku. ---------------------------------------------------------------------------------------------------- [05:18:18] Adrian Madrid(@aemadrid):@jgaskins thx! ---------------------------------------------------------------------------------------------------- ############################## [2015-09-02] ############################## [02:47:30] Jamie Gaskins(@jgaskins):@aemadrid @krainboltgreene Here's an example app comparing Clearwater to React.js. Demo: https://clearwater-roda-example.herokuapp.com Code: https://github.com/jgaskins/clearwater-roda-example ---------------------------------------------------------------------------------------------------- [02:52:30] Jamie Gaskins(@jgaskins):Ha! I wrote the app on my laptop, which has Yosemite installed. I just tried it on my iMac (running El Capitan) for the first time and holy crap, Clearwater absolutely _crushes_ React.js on rendering the "Obnoxiously Huge Page" on Safari 9. ---------------------------------------------------------------------------------------------------- [03:00:18] Jamie Gaskins(@jgaskins):The Clearwater version was faster than the React.js version on the laptop, but the difference wasn't quite so huge. Maybe it's because Safari 9's faster to calculate styles and paint so I noticed the difference in JS execution time more? ---------------------------------------------------------------------------------------------------- [14:52:41] Adrian Madrid(@aemadrid):@jgaskins very cool ---------------------------------------------------------------------------------------------------- [14:52:47] Adrian Madrid(@aemadrid):thx for taking the time ---------------------------------------------------------------------------------------------------- [14:53:52] Jamie Gaskins(@jgaskins):@aemadrid No worries. Let me know if you have any questions about it. ---------------------------------------------------------------------------------------------------- [14:57:25] Adrian Madrid(@aemadrid):Just took a quick look ---------------------------------------------------------------------------------------------------- [14:57:32] Adrian Madrid(@aemadrid):like how the routing works so far ---------------------------------------------------------------------------------------------------- [14:57:47] Adrian Madrid(@aemadrid):I’ll try building a small app and see how far I get ---------------------------------------------------------------------------------------------------- [14:58:22] Adrian Madrid(@aemadrid):I can see a small difference between react and CW on the obnoxious page but it is just a laptop ---------------------------------------------------------------------------------------------------- [15:01:21] Adrian Madrid(@aemadrid):hmh, just profiled it and react took twice as much: 8892.0ms vs 4971.7ms ---------------------------------------------------------------------------------------------------- [15:02:31] Adrian Madrid(@aemadrid):actually it was smaller, there was some garbage collection and waiting for me to click ---------------------------------------------------------------------------------------------------- [15:03:15] Adrian Madrid(@aemadrid):nevertheless it proves the speed is a non-issue ---------------------------------------------------------------------------------------------------- [18:39:28] Jamie Gaskins(@jgaskins):@aemadrid Awesome. I didn't even do any profiling, I just noticed it went faster. :-) That's fantastic! ---------------------------------------------------------------------------------------------------- ############################## [2015-09-04] ############################## [19:34:49] Adrian Madrid(@aemadrid):do you have an example that deals with forms? ---------------------------------------------------------------------------------------------------- [19:35:15] Adrian Madrid(@aemadrid):I saw the search example in the readme but that deals with just the event of that 1 search input ---------------------------------------------------------------------------------------------------- [19:35:25] Adrian Madrid(@aemadrid):how do you normally deal with larger forms? ---------------------------------------------------------------------------------------------------- [21:05:57] Kurtis Rainbolt-Greene(@krainboltgreene):@aemadrid I need to do this too, want to pair? ---------------------------------------------------------------------------------------------------- [21:06:39] Adrian Madrid(@aemadrid):I’ll have some time later today like in 4 hours ---------------------------------------------------------------------------------------------------- [21:06:42] Adrian Madrid(@aemadrid):would that work? ---------------------------------------------------------------------------------------------------- [21:13:57] Kurtis Rainbolt-Greene(@krainboltgreene):Sounds good! ---------------------------------------------------------------------------------------------------- [21:14:20] Adrian Madrid(@aemadrid):I’ll look you up here when I’m ready ---------------------------------------------------------------------------------------------------- [23:48:14] Jamie Gaskins(@jgaskins):@aemadrid @krainboltgreene Forms are awkward because the DOM API doesn't provide form serialization — either native, in `opal-browser`, or in `virtual-dom`. What I've been doing is this: ---------------------------------------------------------------------------------------------------- [23:51:08] Jamie Gaskins(@jgaskins):```ruby class MyForm include Clearwater::Component def render form({ onsubmit: method(:do_the_thing) }, [ div(input(name: 'foo', onkeydown: method(:set_attribute))), div(input(name: 'bar', onkeydown: method(:set_attribute))), ]) end def do_the_thing event event.prevent # do things with foo and bar end def set_attribute event input = event.target instance_variable_set "@#{input[:name]}", input.value end end ``` ---------------------------------------------------------------------------------------------------- [23:54:06] Jamie Gaskins(@jgaskins):I haven't run that, so it may have a syntax error somewhere, but that's the idea behind how I've been doing forms. Either call `set_attribute` which uses the `name` attribute of the input field, or have it call `set_foo` or `set_bar` directly, which requires more code, but allows you to handle different inputs differently. ---------------------------------------------------------------------------------------------------- [23:59:15] Kurtis Rainbolt-Greene(@krainboltgreene):I've probably already said this but using method() like this is brilliant. ---------------------------------------------------------------------------------------------------- ############################## [2015-09-05] ############################## [00:25:28] Jamie Gaskins(@jgaskins):Right?! It's great because we get the `event` passed in automatically. In fact, it can be any callable object: a proc, a lambda, a method, or just an object that responds to `call`. ```ruby class LoginForm include Clearwater::Component attr_reader :email, :password def render form({ onsubmit: UserLogin.new(self) }, [ # ... ]) end end class UserLogin def initialize form @form = form end def credentials { email: @form.email, password: @form.password } end def call event event.prevent # Don't actually submit the form natively Browser::HTTP.post('/api/session', email: credentials).then do |response| # Handle response, set auth token, whatevs end end end ``` ---------------------------------------------------------------------------------------------------- [00:26:25] Jamie Gaskins(@jgaskins):I think most of the time it'll just be a method or a proc (I use methods nearly all the time until they get too big), but being able to swap in a service object is pretty neat in some cases. ---------------------------------------------------------------------------------------------------- [00:42:31] Kurtis Rainbolt-Greene(@krainboltgreene):Most people don't know or use method() ---------------------------------------------------------------------------------------------------- [00:56:53] Jamie Gaskins(@jgaskins):Yeah, I was thinking of covering it in a screencast. ---------------------------------------------------------------------------------------------------- [01:11:54] Adrian Madrid(@aemadrid):interesting ---------------------------------------------------------------------------------------------------- [01:14:03] Adrian Madrid(@aemadrid):@jgaskins @krainboltgreene that seems straight forward to me ---------------------------------------------------------------------------------------------------- [01:14:28] Adrian Madrid(@aemadrid):I do like handling the form processing with a little service object actually ---------------------------------------------------------------------------------------------------- [01:14:54] Adrian Madrid(@aemadrid):seems cleaner than dealing with that in the object responsible for all the html ---------------------------------------------------------------------------------------------------- [01:15:23] Adrian Madrid(@aemadrid):although I wonder how the interaction would be if you want to show validation errors for example ---------------------------------------------------------------------------------------------------- [02:02:15] Jamie Gaskins(@jgaskins):@aemadrid Validation on submission or while typing? ---------------------------------------------------------------------------------------------------- [02:02:53] Adrian Madrid(@aemadrid):I gues the latter makes it even more complex ---------------------------------------------------------------------------------------------------- [02:03:43] Adrian Madrid(@aemadrid):I’m thinking the interaction of input, rule-validation and error-messages is a long trail of interaction between the components and the service object handling submission and validation ---------------------------------------------------------------------------------------------------- [02:16:03] Jamie Gaskins(@jgaskins):While typing is actually pretty simple. ```ruby class MyForm include Clearwater::Component def render input( onkeydown: method(:set_email), style: { border_color: @valid_email ? 'green' : 'red', } ) end def set_email event @email = event.target.value @valid_email = !!(@email =~ /[\w\.\+_]+@\w+\.\w+/) call # Component#call re-renders the app end end ``` ---------------------------------------------------------------------------------------------------- [02:18:07] Adrian Madrid(@aemadrid):I could see that while typing although we would need more to stop submission until all fields are valid ---------------------------------------------------------------------------------------------------- [02:18:43] Adrian Madrid(@aemadrid):also we might want a separate div to show error messages like “email is invalid” or “email is missing" ---------------------------------------------------------------------------------------------------- [02:21:39] Jamie Gaskins(@jgaskins):Definitely. In the demo app I posted the other day, I originally had content on a couple of those pages and form validation on the "register" page, but I was goofing around a _lot_ trying to check performance and I don't think that got committed. ---------------------------------------------------------------------------------------------------- [02:21:49] Jamie Gaskins(@jgaskins):I'll add that real quick and show you what I mean. ---------------------------------------------------------------------------------------------------- [03:18:48] Jamie Gaskins(@jgaskins):@aemadrid Sorry, that wasn't as quick as I'd hoped, but here's how I've been doing form validation: https://github.com/jgaskins/clearwater-roda-example/blob/master/shared/components/user_registration.rb Demo: https://clearwater-roda-example.herokuapp.com/register ---------------------------------------------------------------------------------------------------- [03:30:51] Jamie Gaskins(@jgaskins):The `SubmitUserRegistration` service object at the bottom of the file just prints the form data to the console to simulate submitting to the server. ---------------------------------------------------------------------------------------------------- [16:02:33] Adrian Madrid(@aemadrid):interesting ---------------------------------------------------------------------------------------------------- [16:03:14] Adrian Madrid(@aemadrid):wondering if it wouldn’t help to have a service object a level up that keeps the data and process the form once submitted ---------------------------------------------------------------------------------------------------- [16:04:13] Adrian Madrid(@aemadrid):I’m going to try to find time and play with that idea ---------------------------------------------------------------------------------------------------- [16:04:32] Adrian Madrid(@aemadrid):thx for the example though! it gives me enough rope ---------------------------------------------------------------------------------------------------- [20:02:10] Jamie Gaskins(@jgaskins):It might. If it's a level up, you could pass it into other components inside. I should be able to find time to do a screencast about components this weekend. I unfortunately didn't get a chance last weekend. ---------------------------------------------------------------------------------------------------- [21:26:51] Adrian Madrid(@aemadrid):that’d be cool ---------------------------------------------------------------------------------------------------- ############################## [2015-09-06] ############################## [21:54:00] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins So far the biggest complaint is the HTML fluent language. ---------------------------------------------------------------------------------------------------- ############################## [2015-09-07] ############################## [00:07:24] Jamie Gaskins(@jgaskins):@krainboltgreene I'm not sure what you mean. ---------------------------------------------------------------------------------------------------- [00:21:59] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins: The `div()`. ---------------------------------------------------------------------------------------------------- [02:16:10] Jamie Gaskins(@jgaskins):@krainboltgreene: Do you have any suggestions to improve it? I'm actually interested to know if there's something better. I pretty much just pulled the idea for those methods from the `React.DOM` helpers. ---------------------------------------------------------------------------------------------------- [02:16:24] Jamie Gaskins(@jgaskins):… because I couldn't come up with a better way to do it. :-) ---------------------------------------------------------------------------------------------------- [02:17:46] Kurtis Rainbolt-Greene(@krainboltgreene):Currently working on https://github.com/krainboltgreene/hypertext.gem ---------------------------------------------------------------------------------------------------- [02:18:19] Kurtis Rainbolt-Greene(@krainboltgreene):But there's also mab and co. ---------------------------------------------------------------------------------------------------- [02:20:24] Jamie Gaskins(@jgaskins):Do you mean you would prefer to use the block syntax? ---------------------------------------------------------------------------------------------------- [02:21:17] Kurtis Rainbolt-Greene(@krainboltgreene):I have a preference, but I can use both just fine. ---------------------------------------------------------------------------------------------------- [02:21:36] Kurtis Rainbolt-Greene(@krainboltgreene):I think though the 7-8 I've talked to might prefer the block style. ---------------------------------------------------------------------------------------------------- [02:21:47] Kurtis Rainbolt-Greene(@krainboltgreene):Just something to consider. ---------------------------------------------------------------------------------------------------- [02:22:00] Kurtis Rainbolt-Greene(@krainboltgreene):I mean they could just be looking for an excuse. ---------------------------------------------------------------------------------------------------- [02:27:21] Jamie Gaskins(@jgaskins):Yeah, I've heard a few complaints about the `tag_name(attributes, content)` thing, too. ---------------------------------------------------------------------------------------------------- [02:30:15] Jamie Gaskins(@jgaskins):I prefer the array syntax, but maybe we could make the block syntax an option? Like include a different mixin to use the block syntax or something. ---------------------------------------------------------------------------------------------------- [02:31:26] Kurtis Rainbolt-Greene(@krainboltgreene):That seems best. Easy adoption for both sides. ---------------------------------------------------------------------------------------------------- [02:32:16] Jamie Gaskins(@jgaskins):Also, I worry about the performance of the block syntax. Maybe it won't be a big deal, but I need to see numbers and see how it performs with realistically sized trees of components. ---------------------------------------------------------------------------------------------------- [03:23:02] Jamie Gaskins(@jgaskins):Playing around with writing the block syntax, I'm having trouble figuring out a way to keep track of block nesting for child nodes. It'd be easy if we used `instance_exec`, but I really don't want to do that because then we wouldn't have access to methods on the component. ---------------------------------------------------------------------------------------------------- [03:48:33] Kurtis Rainbolt-Greene(@krainboltgreene):Well ---------------------------------------------------------------------------------------------------- [03:48:43] Kurtis Rainbolt-Greene(@krainboltgreene):Hmm. ---------------------------------------------------------------------------------------------------- [03:48:56] Kurtis Rainbolt-Greene(@krainboltgreene):I might have already solved this with hypertext. ---------------------------------------------------------------------------------------------------- ############################## [2015-09-09] ############################## [04:36:58] Adrian Madrid(@aemadrid):[![Screen Shot 2015-09-08 at 10.35.36 PM.png](https://files.gitter.im/clearwater-rb/clearwater/3Koy/thumb/Screen-Shot-2015-09-08-at-10.35.36-PM.png)](https://files.gitter.im/clearwater-rb/clearwater/3Koy/Screen-Shot-2015-09-08-at-10.35.36-PM.png) ---------------------------------------------------------------------------------------------------- [04:37:02] Adrian Madrid(@aemadrid):BTW trying the warmup app is throwing an error that looks ugly... ---------------------------------------------------------------------------------------------------- [04:37:34] Adrian Madrid(@aemadrid):```[500] Twitter::Error::Forbidden: Unable to verify your credentials /usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/twitter-5.14.0/lib/twitter/rest/response/raise_error.rb:13:in `on_complete' /usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/faraday-0.9.1/lib/faraday/response.rb:9:in `block in call’``` ---------------------------------------------------------------------------------------------------- [04:37:51] Adrian Madrid(@aemadrid):So I guess I need to enter my own credentials... ---------------------------------------------------------------------------------------------------- [04:38:01] Adrian Madrid(@aemadrid):the error in the page looks awful though... ---------------------------------------------------------------------------------------------------- [05:03:19] Adrian Madrid(@aemadrid):no big deal, got my credentials going and it all works ---------------------------------------------------------------------------------------------------- [06:56:00] Adrian Madrid(@aemadrid):ok, totally stupid, sent it to the wronf forum, sorry! ---------------------------------------------------------------------------------------------------- [20:14:05] Jamie Gaskins(@jgaskins):@aemadrid I was a little confused for a sec. I wasn't sure if I'd accidentally published one of my own Clearwater Twitter-client experiments. :-) ---------------------------------------------------------------------------------------------------- [21:02:53] Adrian Madrid(@aemadrid):sorry, my dumb self showing up again ;-) ---------------------------------------------------------------------------------------------------- [21:34:08] Kurtis Rainbolt-Greene(@krainboltgreene):Don't worry, we're not much better :) ---------------------------------------------------------------------------------------------------- ############################## [2015-09-17] ############################## [22:56:07] Kurtis Rainbolt-Greene(@krainboltgreene):Finally getting approval from the company to do OSS stuff. ---------------------------------------------------------------------------------------------------- [23:32:07] Adrian Madrid(@aemadrid):nice! ---------------------------------------------------------------------------------------------------- ############################## [2015-09-20] ############################## [03:56:17] Jamie Gaskins(@jgaskins):@krainboltgreene Sweet! ---------------------------------------------------------------------------------------------------- ############################## [2015-09-30] ############################## [17:45:51] Jamie Gaskins(@jgaskins):So what I usually do is either override `outlet`: ``` def outlet super || MyDefaultOutlet.new end ``` ---------------------------------------------------------------------------------------------------- [17:46:14] Jamie Gaskins(@jgaskins):Or I just do `outlet || MyDefaultOutlet.new` in the `render` method. ---------------------------------------------------------------------------------------------------- [17:47:08] Jamie Gaskins(@jgaskins):I haven't come up with a better way to do that yet. I thought about putting something for that in the router: ``` router = Clearwater::Router.new do route 'foo' => Foo.new default Bar.new end ``` ---------------------------------------------------------------------------------------------------- [17:47:40] Jamie Gaskins(@jgaskins):Then it would set `outlet` to the `Bar` component if it didn't match anything else. ---------------------------------------------------------------------------------------------------- [17:47:58] Jamie Gaskins(@jgaskins):But I haven't done it yet. ---------------------------------------------------------------------------------------------------- [17:49:49] Kurtis Rainbolt-Greene(@krainboltgreene):Ah. ---------------------------------------------------------------------------------------------------- [17:49:53] Kurtis Rainbolt-Greene(@krainboltgreene):Hmm. ---------------------------------------------------------------------------------------------------- [17:50:43] Kurtis Rainbolt-Greene(@krainboltgreene):Any documentation on the router, @jgaskins? ---------------------------------------------------------------------------------------------------- [17:51:21] Jamie Gaskins(@jgaskins):@krainboltgreene: Not yet. I'll try to work on some docs soon. ---------------------------------------------------------------------------------------------------- [17:51:35] Kurtis Rainbolt-Greene(@krainboltgreene):So what do I need to do this gist to make it work? ---------------------------------------------------------------------------------------------------- [17:51:55] Kurtis Rainbolt-Greene(@krainboltgreene):I want content to be the "wrapper", computer to be inside content. ---------------------------------------------------------------------------------------------------- [17:54:31] Jamie Gaskins(@jgaskins):Remove the route, then in `content.rb`: ``` class Content # ... def outlet super || Computer.new end end ``` ---------------------------------------------------------------------------------------------------- [17:54:41] Kurtis Rainbolt-Greene(@krainboltgreene):Interesting. ---------------------------------------------------------------------------------------------------- [17:55:15] Kurtis Rainbolt-Greene(@krainboltgreene):Thanks for your time :) ---------------------------------------------------------------------------------------------------- [17:56:17] Jamie Gaskins(@jgaskins):Another thing, I'm not sure how the requires inside your `Hacker::Application` class will work when the app gets precompiled for production. AFAIK, they may need to be moved up top. I'm not 100% sure on that, but just something to be aware of. :-) ---------------------------------------------------------------------------------------------------- [17:56:21] Jamie Gaskins(@jgaskins):@krainboltgreene No worries :-) ---------------------------------------------------------------------------------------------------- [17:59:54] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins The requires work. ---------------------------------------------------------------------------------------------------- [18:10:52] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins So everything's working, but I guess I don't understand `outlet`'s function? ---------------------------------------------------------------------------------------------------- [18:14:29] Kurtis Rainbolt-Greene(@krainboltgreene):Also, I agree with your assessment re: block ---------------------------------------------------------------------------------------------------- [18:14:37] Kurtis Rainbolt-Greene(@krainboltgreene):My views are very small and much easier to read. ---------------------------------------------------------------------------------------------------- [18:14:46] Kurtis Rainbolt-Greene(@krainboltgreene):I think we just need to cleanup the readme. ---------------------------------------------------------------------------------------------------- [18:25:39] Jamie Gaskins(@jgaskins):@krainboltgreene The `outlet` is something I took from Ember.js. When you call `outlet` in Ember, it renders the next child route. I couldn't come up with a better name for it, so I stole that. :-) ---------------------------------------------------------------------------------------------------- [18:26:29] Jamie Gaskins(@jgaskins):If there isn't a child route (because one was never declared in the router or there isn't another path segment after the current route), it returns `nil`. ---------------------------------------------------------------------------------------------------- [18:28:03] Jamie Gaskins(@jgaskins):Before the app gets rendered, the router sets up the chain of outlets as the path through the routing tree, based on the URL path. ---------------------------------------------------------------------------------------------------- [20:34:04] Kurtis Rainbolt-Greene(@krainboltgreene):Ah of course ---------------------------------------------------------------------------------------------------- [20:34:19] Kurtis Rainbolt-Greene(@krainboltgreene):I think the confusion came because outlet was nil and I didn't see a connection to the router. ---------------------------------------------------------------------------------------------------- [17:39:40] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins I seem to be super confused with how components work in our system. ---------------------------------------------------------------------------------------------------- [17:40:15] Kurtis Rainbolt-Greene(@krainboltgreene):https://gist.github.com/krainboltgreene/6eee3027472f739da137 ---------------------------------------------------------------------------------------------------- [17:40:21] Kurtis Rainbolt-Greene(@krainboltgreene):That should work in my mind ---------------------------------------------------------------------------------------------------- [17:40:31] Kurtis Rainbolt-Greene(@krainboltgreene):But only `Content` component renders. ---------------------------------------------------------------------------------------------------- [17:45:06] Jamie Gaskins(@jgaskins):@krainboltgreene Ooh, the `'/'` route is implied. I haven't put in a way to have a default `outlet`. ---------------------------------------------------------------------------------------------------- ############################## [2015-10-01] ############################## [02:01:19] Jamie Gaskins(@jgaskins):Yeah, the application sets up a two-way link between the router and itself, and the router does a similar thing in routing. It's a little magic, unfortunately. ---------------------------------------------------------------------------------------------------- [06:56:12] Kurtis Rainbolt-Greene(@krainboltgreene):Woo, did a clearwater.rb lightening talk. ---------------------------------------------------------------------------------------------------- [13:28:34] Jamie Gaskins(@jgaskins):@krainboltgreene Awesome! How'd it go? ---------------------------------------------------------------------------------------------------- [15:26:54] Kurtis Rainbolt-Greene(@krainboltgreene):For a lightening talk pretty well. ---------------------------------------------------------------------------------------------------- [15:53:32] Adrian Madrid(@aemadrid):very cool. would you share the slides? ---------------------------------------------------------------------------------------------------- [15:53:57] Kurtis Rainbolt-Greene(@krainboltgreene):@aemadrid No slides, just showed off my game. ---------------------------------------------------------------------------------------------------- [15:54:22] Kurtis Rainbolt-Greene(@krainboltgreene):Mostly really talked about the view layer and how we're not limited to react.js ---------------------------------------------------------------------------------------------------- [15:54:28] Adrian Madrid(@aemadrid):cool ---------------------------------------------------------------------------------------------------- [15:54:59] Adrian Madrid(@aemadrid):have you released it publicly? ---------------------------------------------------------------------------------------------------- [16:08:11] Jamie Gaskins(@jgaskins):Sweet! ---------------------------------------------------------------------------------------------------- [16:11:37] Kurtis Rainbolt-Greene(@krainboltgreene):The game itself isn't done, and I just switched it to clearwater so I'll publish it tonight on github. ---------------------------------------------------------------------------------------------------- [16:11:49] Adrian Madrid(@aemadrid):very cool thx ---------------------------------------------------------------------------------------------------- [17:54:55] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins: How do I determine UI stutter? ---------------------------------------------------------------------------------------------------- [17:54:57] Kurtis Rainbolt-Greene(@krainboltgreene):Er ---------------------------------------------------------------------------------------------------- [17:55:09] Kurtis Rainbolt-Greene(@krainboltgreene):How do I determine the cause of UI stutter from a clearwater perspective? ---------------------------------------------------------------------------------------------------- [18:38:47] Jamie Gaskins(@jgaskins):@krainboltgreene What do you mean? ---------------------------------------------------------------------------------------------------- [18:38:55] Jamie Gaskins(@jgaskins):I don't know what you mean by determining UI stutter. ---------------------------------------------------------------------------------------------------- [18:39:06] Jamie Gaskins(@jgaskins):You want to know how quickly it the app renders? ---------------------------------------------------------------------------------------------------- [18:45:51] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins: I have some scroll stutter now that it's 100% clearwater ---------------------------------------------------------------------------------------------------- [18:45:58] Kurtis Rainbolt-Greene(@krainboltgreene):And it's not my keframe animations or the big gif ---------------------------------------------------------------------------------------------------- [18:46:06] Kurtis Rainbolt-Greene(@krainboltgreene):Just kinda wondering how I "debug" that. ---------------------------------------------------------------------------------------------------- [18:46:15] Kurtis Rainbolt-Greene(@krainboltgreene):I guess really I just need to watch the web inspector courses online. ---------------------------------------------------------------------------------------------------- [18:53:31] Jamie Gaskins(@jgaskins):@krainboltgreene Hmm... Is it re-rendering frequently? ---------------------------------------------------------------------------------------------------- [18:54:50] Jamie Gaskins(@jgaskins):Is the project on GitHub? ---------------------------------------------------------------------------------------------------- [18:56:01] Jamie Gaskins(@jgaskins):You can see how long the app takes to render by defining a `debug?` method on the app that returns true: ``` def app.debug? true end ``` ---------------------------------------------------------------------------------------------------- [20:07:20] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins See yeah I can't even tell you if it's doing that, because I'm not sure what defines 're-rendering frequently' ---------------------------------------------------------------------------------------------------- [20:07:40] Kurtis Rainbolt-Greene(@krainboltgreene):kk ---------------------------------------------------------------------------------------------------- [20:11:03] Jamie Gaskins(@jgaskins):@krainboltgreene How frequently is it rendering? A few times a second? Every animation frame? :-) Just need a ballpark value. ---------------------------------------------------------------------------------------------------- [20:11:53] Jamie Gaskins(@jgaskins):Also, how long it takes to render is a factor. If it takes more than about 64ms (4 animation frames), then it'll definitely be noticeable. ---------------------------------------------------------------------------------------------------- [20:12:33] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins: Generated virtual DOM in 5.65ms / Rendered to actual DOM in 6.23ms ---------------------------------------------------------------------------------------------------- [20:12:55] Jamie Gaskins(@jgaskins):Huh, that's only about 12ms, less than a single animation frame. ---------------------------------------------------------------------------------------------------- [20:13:22] Jamie Gaskins(@jgaskins):@krainboltgreene Is this against the latest released gem or against master? ---------------------------------------------------------------------------------------------------- [20:14:08] Kurtis Rainbolt-Greene(@krainboltgreene):opal: 0.7?, clearwater: latest ---------------------------------------------------------------------------------------------------- [20:14:15] Kurtis Rainbolt-Greene(@krainboltgreene):gem "clearwater", github: "clearwater-rb/clearwater", ref: "395885d93a7a0419efc72326152f0993b2e842c1" ---------------------------------------------------------------------------------------------------- [20:26:37] Kurtis Rainbolt-Greene(@krainboltgreene):Also, does the view layer have a lifecycle? ---------------------------------------------------------------------------------------------------- [20:26:50] Kurtis Rainbolt-Greene(@krainboltgreene):Because for debugging purposes it'd be nice to hook in and print on different lifecycles. ---------------------------------------------------------------------------------------------------- [20:27:03] Kurtis Rainbolt-Greene(@krainboltgreene):init -> render -> update ---------------------------------------------------------------------------------------------------- [23:17:40] Jamie Gaskins(@jgaskins):@krainboltgreene Not really. The components don't mount themselves into the DOM the way React components do. The `render` method just returns a value, so after the app is rendered, that's really it. The DOM elements that have event handlers will have those handlers executed in the context of the component that rendered them, but otherwise the components get thrown away (unless they're cached inside a parent component or they are a routing target). ---------------------------------------------------------------------------------------------------- [23:20:23] Jamie Gaskins(@jgaskins):They're just objects. All the mixin does is supply the element DSL to return virtual-DOM nodes. So init is just initializing a PORO, render just returns a virtual-DOM tree, and there is no update. :-) ---------------------------------------------------------------------------------------------------- [23:21:56] Jamie Gaskins(@jgaskins):Updating happens by re-rendering the entire app. It doesn't _actually_ rerender the entire app, it just does the diff/patch, but on the entire tree. No rendering is localized to the component. ---------------------------------------------------------------------------------------------------- [23:25:29] Kurtis Rainbolt-Greene(@krainboltgreene):Interesting. ---------------------------------------------------------------------------------------------------- ############################## [2015-10-03] ############################## [23:57:17] Jamie Gaskins(@jgaskins):Nice ---------------------------------------------------------------------------------------------------- [23:58:38] Jamie Gaskins(@jgaskins):One thing you _can_ do at the moment is pass a block to `app.render`. So `app.render { emit(:my_event) }`. But that doesn't work for `app.call` yet, unfortunately. ---------------------------------------------------------------------------------------------------- [05:56:12] Kurtis Rainbolt-Greene(@krainboltgreene):Sourcemapping has been a pain. ---------------------------------------------------------------------------------------------------- [06:46:30] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins What does opal-browser give clearwater? ---------------------------------------------------------------------------------------------------- [20:48:45] Jamie Gaskins(@jgaskins):@krainboltgreene Yeah, source mapping outside of Rails seems iffy at best. ---------------------------------------------------------------------------------------------------- [20:50:53] Jamie Gaskins(@jgaskins):I thought recently about removing `opal-browser`, but I realized Clearwater uses it in quite a few places. In most places, we could just use the JS API and not care too much, but we also wrap the JS event in event handlers using `Browser::Event`. ---------------------------------------------------------------------------------------------------- [20:51:05] Kurtis Rainbolt-Greene(@krainboltgreene):Hmm. ---------------------------------------------------------------------------------------------------- [20:51:24] Kurtis Rainbolt-Greene(@krainboltgreene):Would it be worth it to just duplicate that functionality? ---------------------------------------------------------------------------------------------------- [20:51:32] Jamie Gaskins(@jgaskins):So `div({ onclick: method(:foo) })` will call `foo(Browser::Event.new(js_event))` ---------------------------------------------------------------------------------------------------- [20:54:08] Jamie Gaskins(@jgaskins):I'm not sure. The event setup in `opal-browser` is pretty involved. We would need to replicate so many different types of events: click, mouse{over,down,up}, drag{start,end,enter,leave}, touch{start,end,move,cancel}, key{up,down,}, change, etc. ---------------------------------------------------------------------------------------------------- [20:54:48] Jamie Gaskins(@jgaskins):I thought about removing it to reduce payload size if the app doesn't need to do things like AJAX or whatever, but we do use it quite a bit internally. ---------------------------------------------------------------------------------------------------- [20:56:27] Kurtis Rainbolt-Greene(@krainboltgreene):There's also the option of doing `opal-event`. ---------------------------------------------------------------------------------------------------- [20:56:42] Kurtis Rainbolt-Greene(@krainboltgreene):I get the feeling that `opal-browser` should probably be broken up anyhow. ---------------------------------------------------------------------------------------------------- [20:58:35] Jamie Gaskins(@jgaskins):I've talked to meh about doing things to reduce the file size because `require 'browser/event'` loads all event types (including things like game controller stuff) and `require 'browser/dom/element'` loads all types of DOM elements. ---------------------------------------------------------------------------------------------------- [20:59:39] Kurtis Rainbolt-Greene(@krainboltgreene):Yeah. ---------------------------------------------------------------------------------------------------- [20:59:40] Jamie Gaskins(@jgaskins):I wanted a way to cherry-pick the events and DOM elements an app would use, but at the moment, not every file in `opal-browser` requires every file it depends on, so that was a bit more work than I was willing to put in at the time. :-) ---------------------------------------------------------------------------------------------------- [21:00:32] Jamie Gaskins(@jgaskins):Rather, the DOM elements an app would need to interact with via Ruby. ---------------------------------------------------------------------------------------------------- [21:03:08] Kurtis Rainbolt-Greene(@krainboltgreene):Okay, I'll start making the gems. ---------------------------------------------------------------------------------------------------- [21:04:28] Jamie Gaskins(@jgaskins):For events and DOM elements? ---------------------------------------------------------------------------------------------------- [21:07:12] Jamie Gaskins(@jgaskins):@krainboltgreene Another reason I haven't tried to just make something minimal for DOM and events is that, if someone wants to do AJAX requests, they're likely to add `opal-browser` anyway. ---------------------------------------------------------------------------------------------------- [21:07:41] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins Making a gem for each part of opal-browser ---------------------------------------------------------------------------------------------------- [21:07:50] Jamie Gaskins(@jgaskins)::+1: ---------------------------------------------------------------------------------------------------- [23:52:25] Jamie Gaskins(@jgaskins):@krainboltgreene Not sure if we'll be able to use `hamster` in Opal. I ran into a few issues. First, it uses `undef :"<=>"`, which broke, so I added opal/opal#1128 to fix that, but it also seems to rely on `Object#hash` being an integer, but it returns a string in Opal. ---------------------------------------------------------------------------------------------------- [23:52:43] Jamie Gaskins(@jgaskins):Hash buckets are string keys in Opal (since they're stored in JS objects, which have string keys), rather than array indexes as in MRI. :-\ I don't know if there's anything we can do about that. ---------------------------------------------------------------------------------------------------- [23:52:46] Kurtis Rainbolt-Greene(@krainboltgreene):Intresesting. ---------------------------------------------------------------------------------------------------- [23:53:03] Kurtis Rainbolt-Greene(@krainboltgreene):It shouldn't rely on them being INT. ---------------------------------------------------------------------------------------------------- [23:53:12] Kurtis Rainbolt-Greene(@krainboltgreene):I'll bring it up with the hamster/immutable-ruby crew. ---------------------------------------------------------------------------------------------------- [23:53:33] Jamie Gaskins(@jgaskins)::+1: Awesome. ---------------------------------------------------------------------------------------------------- [23:54:20] Jamie Gaskins(@jgaskins):Er, well, at least `Numeric`, if not `Integer`. ---------------------------------------------------------------------------------------------------- [23:54:41] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins Is there a way to do things post-render on a component? ---------------------------------------------------------------------------------------------------- [23:54:52] Kurtis Rainbolt-Greene(@krainboltgreene):Chart.js needs to run code targeting the canvas element made. ---------------------------------------------------------------------------------------------------- [23:55:37] Jamie Gaskins(@jgaskins):Not yet. It's something I definitely want to add. Google Maps is the same way, you have to give it an element on the page to render into. ---------------------------------------------------------------------------------------------------- [23:56:19] Jamie Gaskins(@jgaskins):I talked a bit about that in #16. ---------------------------------------------------------------------------------------------------- [23:56:29] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins My current plan is to have a raw javascript file with event listeners, and just do: ---------------------------------------------------------------------------------------------------- [23:56:40] Kurtis Rainbolt-Greene(@krainboltgreene):`emit(:someevent) and canvas(properties, nodes)` ---------------------------------------------------------------------------------------------------- ############################## [2015-10-04] ############################## [07:54:26] Kurtis Rainbolt-Greene(@krainboltgreene):Night! ---------------------------------------------------------------------------------------------------- [00:55:59] Kurtis Rainbolt-Greene(@krainboltgreene):Interesting. ---------------------------------------------------------------------------------------------------- [00:57:39] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins I'm hoping that Opal takes the smart route Elm did and implements ports. ---------------------------------------------------------------------------------------------------- [00:57:50] Kurtis Rainbolt-Greene(@krainboltgreene):`` is handy, but makes code so freaking ugly. ---------------------------------------------------------------------------------------------------- [01:10:44] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins https://github.com/clearwater-rb/opal-event.gem ---------------------------------------------------------------------------------------------------- [01:11:12] Kurtis Rainbolt-Greene(@krainboltgreene):There's no documentation or tests for the event code, so woo. ---------------------------------------------------------------------------------------------------- [01:42:19] Jamie Gaskins(@jgaskins):@krainboltgreene Yeah, someone mentioned that backticks were a mistake. It seemed like a good idea when Opal was only being used in the browser, but if you want to use Opal with Node, you have no way to actually shell out to the OS. ---------------------------------------------------------------------------------------------------- [01:42:39] Kurtis Rainbolt-Greene(@krainboltgreene):Yeah. ---------------------------------------------------------------------------------------------------- [01:45:55] Jamie Gaskins(@jgaskins):The only way I figured out how opal-browser works most of the time was by reading the code. Thankfully, the code is pretty clean. ---------------------------------------------------------------------------------------------------- [01:46:46] Kurtis Rainbolt-Greene(@krainboltgreene):Gonna have to disagree on that one, at least when it comes to the events. :/ ---------------------------------------------------------------------------------------------------- [01:47:17] Kurtis Rainbolt-Greene(@krainboltgreene):I mean I get that it's a non-trivial binding, but I have no clear clue how to trigger an event. ---------------------------------------------------------------------------------------------------- [01:47:26] Kurtis Rainbolt-Greene(@krainboltgreene):I mean at this point I'm contemplating pulling in `opal-jquery`. ---------------------------------------------------------------------------------------------------- [01:49:59] Jamie Gaskins(@jgaskins):I don't think that's any better, tbh. I mean, people know jQuery already, but I like the fact opal-browser is self-contained. You don't need to pull in an outside JS lib. ---------------------------------------------------------------------------------------------------- [01:53:03] Kurtis Rainbolt-Greene(@krainboltgreene):Agreed, however at this point just being able to write `$($document).trigger('event', {...})` would be grand. ---------------------------------------------------------------------------------------------------- [01:53:46] Jamie Gaskins(@jgaskins):I think you can do `element.trigger('click')`. I'm trying to figure out what you're supposed to pass to `trigger`. ---------------------------------------------------------------------------------------------------- [01:54:49] Jamie Gaskins(@jgaskins):https://github.com/opal/opal-browser/blob/1336a869be2ff2aa1cbc57b323359b49cc47e7db/opal/browser/event/base.rb#L351-L357 ---------------------------------------------------------------------------------------------------- [01:55:14] Jamie Gaskins(@jgaskins):Looks like you can do the same: `element.trigger('click', {...})` ---------------------------------------------------------------------------------------------------- [01:55:33] Kurtis Rainbolt-Greene(@krainboltgreene):Okay, so Event.create is the entry point. ---------------------------------------------------------------------------------------------------- [01:55:42] Kurtis Rainbolt-Greene(@krainboltgreene):Now I'm betting that it's an ordering issue. ---------------------------------------------------------------------------------------------------- [02:07:12] Kurtis Rainbolt-Greene(@krainboltgreene):Alright, so it fires, but it's not setting detail like it's supposed to. Hmm. ---------------------------------------------------------------------------------------------------- [02:16:09] Kurtis Rainbolt-Greene(@krainboltgreene):As far as I can tell custom event triggering with detail, as described in MDN is impossible with opal-browser. Hmm. ---------------------------------------------------------------------------------------------------- [02:17:00] Jamie Gaskins(@jgaskins):I dunno. I've never used custom events. :-) ---------------------------------------------------------------------------------------------------- [02:17:36] Kurtis Rainbolt-Greene(@krainboltgreene):You can't! :D ---------------------------------------------------------------------------------------------------- [02:17:49] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins By the way, what's the next step for cw? ---------------------------------------------------------------------------------------------------- [02:21:59] Jamie Gaskins(@jgaskins):@krainboltgreene I'm not sure yet. I'm working on porting over one of our apps at work (currently a Backbone/Marionette app) to see how well it goes to try out a larger CW app than I've worked on so far. I'm trying to see how well things work for more complex apps so I can see if there's much difference from smaller apps. ---------------------------------------------------------------------------------------------------- [02:23:51] Jamie Gaskins(@jgaskins):If it works well, I'm going to demo it to my CTO and VP of engineering and see if they're okay with replacing the Backbone app. I showed them a port of part of one of our other apps for mobile, but they'd already decided that was going to go native instead of web. Apparently it was already in the works, I just hadn't been told about it yet because I don't do iOS/Android anymore at work. ---------------------------------------------------------------------------------------------------- [02:25:59] Kurtis Rainbolt-Greene(@krainboltgreene):Ah. ---------------------------------------------------------------------------------------------------- [02:26:08] Kurtis Rainbolt-Greene(@krainboltgreene):Well I'm currently building out all of socialkardia's frontend with it. ---------------------------------------------------------------------------------------------------- [02:26:14] Kurtis Rainbolt-Greene(@krainboltgreene):So I'll be throwing a lot of data at it. ---------------------------------------------------------------------------------------------------- [02:39:59] Jamie Gaskins(@jgaskins):Sweet ---------------------------------------------------------------------------------------------------- [02:41:37] Kurtis Rainbolt-Greene(@krainboltgreene):Just an FYI, my `emit and canvas()` trick didn't work. ---------------------------------------------------------------------------------------------------- [02:41:49] Kurtis Rainbolt-Greene(@krainboltgreene):Because the emit happens before the canvas is on the DOM. ---------------------------------------------------------------------------------------------------- [02:42:13] Jamie Gaskins(@jgaskins):Hmmm... ---------------------------------------------------------------------------------------------------- [02:42:49] Kurtis Rainbolt-Greene(@krainboltgreene):I got another idea. ---------------------------------------------------------------------------------------------------- [02:43:03] Kurtis Rainbolt-Greene(@krainboltgreene):I'll listen for every ready event on `document`, and then filter by element type. ---------------------------------------------------------------------------------------------------- [02:43:34] Jamie Gaskins(@jgaskins):That sounds interesting ---------------------------------------------------------------------------------------------------- [02:53:17] Kurtis Rainbolt-Greene(@krainboltgreene):Nope, doesn't help me get data to the chart. ---------------------------------------------------------------------------------------------------- [02:54:26] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins: We might have talked about this before, but how would you want me to implement lifecycles for clearwater-components? ---------------------------------------------------------------------------------------------------- [03:14:08] Kurtis Rainbolt-Greene(@krainboltgreene):https://github.com/jbarnette/watchable ---------------------------------------------------------------------------------------------------- [04:54:50] Kurtis Rainbolt-Greene(@krainboltgreene):Alright, so as far as I can tell there's no way to do this outside of the lifecycle of `Clearwater::Component`. ---------------------------------------------------------------------------------------------------- [06:56:09] Jamie Gaskins(@jgaskins):@krainboltgreene I was thinking it'd probably need to happen inside the router. When we call [`router.navigate_to`](https://github.com/clearwater-rb/clearwater/blob/395885d93a7a0419efc72326152f0993b2e842c1/opal/clearwater/router.rb#L56-L60), we'd need to get the targets before and after the path change, then find the differences between them (trivial since `targets_for_path` returns an array). ---------------------------------------------------------------------------------------------------- [06:57:58] Jamie Gaskins(@jgaskins):Then we'd call some callback method (if it exists) on the components we're transitioning away from and another callback method (again, if it exists) on the components we're transitioning to. The components that are part of both routes don't get their callbacks invoked. ---------------------------------------------------------------------------------------------------- [07:03:33] Jamie Gaskins(@jgaskins):Here's kind of the pattern I was thinking of: https://gist.github.com/jgaskins/f09c3aa980367ede72e4 ---------------------------------------------------------------------------------------------------- [07:03:59] Jamie Gaskins(@jgaskins):Of course, that only covers the pre-transition. Post-transition hooks are harder because rendering is asynchronous. ---------------------------------------------------------------------------------------------------- [07:09:17] Jamie Gaskins(@jgaskins):And then we'd need to invoke `Router#navigate_to` from the `Link` component to get that to work on link clicks. Right now, `Link` does its own navigation, which is gross but it works. And since `Link` components won't have access to the router (since you don't want to have to give every single link in your app a reference to the router), we'll need to set up a `RouterRegistry` similar to how we currently do the `AppRegistry` so that any component in the system can rerender the app — `Link` also uses this. ---------------------------------------------------------------------------------------------------- [07:09:21] Jamie Gaskins(@jgaskins):It's gonna be a yak shave. ---------------------------------------------------------------------------------------------------- [07:10:36] Kurtis Rainbolt-Greene(@krainboltgreene):This seems ot only work really if you're using the router. ---------------------------------------------------------------------------------------------------- [07:10:39] Kurtis Rainbolt-Greene(@krainboltgreene):(Which I'm not) ---------------------------------------------------------------------------------------------------- [07:11:05] Jamie Gaskins(@jgaskins):Yeah, it'll have to be generalized to be able to happen on the first render. ---------------------------------------------------------------------------------------------------- [07:13:22] Jamie Gaskins(@jgaskins):You still have a router even if you don't specify one. You just get a blank one. No matter what, the outlet tree gets setup in terms of the URL. If your router has no routes, then you'll have no outlets, but it'll still check. ---------------------------------------------------------------------------------------------------- [07:13:46] Kurtis Rainbolt-Greene(@krainboltgreene):Yeah, I saw that. ---------------------------------------------------------------------------------------------------- [07:14:40] Jamie Gaskins(@jgaskins):I like that the user doesn't have to care about that up front, though. Makes it a lot easier to get started. :-) ---------------------------------------------------------------------------------------------------- [07:15:13] Kurtis Rainbolt-Greene(@krainboltgreene):I briefly considered some sort of event system that got triggered when the entire tree was done rendering. ---------------------------------------------------------------------------------------------------- [07:15:43] Kurtis Rainbolt-Greene(@krainboltgreene):So like a component could be like `emit and render`, and then at the very end `emits.each(&:trigger)` ---------------------------------------------------------------------------------------------------- [07:15:59] Jamie Gaskins(@jgaskins):Yeah, `Application#render` takes a block that will be executed after the render is complete, but I don't think `Application#call` can yet. ---------------------------------------------------------------------------------------------------- [07:16:57] Jamie Gaskins(@jgaskins):Ah, looks like that'd be a trivial thing to add. ---------------------------------------------------------------------------------------------------- [07:17:52] Jamie Gaskins(@jgaskins):One sec, I'll add that in. ---------------------------------------------------------------------------------------------------- [07:19:56] Kurtis Rainbolt-Greene(@krainboltgreene):So right now Clearwater components have no intrisic knowledge of when to re-render, right? ---------------------------------------------------------------------------------------------------- [07:21:38] Jamie Gaskins(@jgaskins):Right. ---------------------------------------------------------------------------------------------------- [07:22:39] Jamie Gaskins(@jgaskins):You can invoke `Component#call` and it will rerender all Clearwater apps on the page (in case you have more than one), but it's not like React's `setState` where it will automatically rerender. ---------------------------------------------------------------------------------------------------- [07:22:52] Kurtis Rainbolt-Greene(@krainboltgreene):@krainboltgreene nods. ---------------------------------------------------------------------------------------------------- [07:23:11] Kurtis Rainbolt-Greene(@krainboltgreene):I like the idea of a component paying attention to a particular piece of the store. ---------------------------------------------------------------------------------------------------- [07:23:30] Kurtis Rainbolt-Greene(@krainboltgreene):Component::Articles watching the state, specifically the articles state. ---------------------------------------------------------------------------------------------------- [07:26:04] Jamie Gaskins(@jgaskins):Indeed. That'll be really nice. Especially if you're using the `CachedRender` mixin, you'll be able to invalidate the component's render cache in O(1) time. ---------------------------------------------------------------------------------------------------- [07:26:59] Kurtis Rainbolt-Greene(@krainboltgreene):I can't seem to get `Object#tap` to work, hmm. ---------------------------------------------------------------------------------------------------- [07:30:58] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins: Thoughts? https://gist.github.com/krainboltgreene/3cffa8df8740ddabf72b ---------------------------------------------------------------------------------------------------- [07:33:48] Jamie Gaskins(@jgaskins):That's an interesting way of doing it, calling it `let`. I haven't seen that before but it makes it read like Swift or Rust. ---------------------------------------------------------------------------------------------------- [07:33:55] Kurtis Rainbolt-Greene(@krainboltgreene):Right? ---------------------------------------------------------------------------------------------------- [07:34:11] Kurtis Rainbolt-Greene(@krainboltgreene):I've been doing it in rspec, instead of using `|config|` ---------------------------------------------------------------------------------------------------- [07:34:16] Kurtis Rainbolt-Greene(@krainboltgreene):`let.fail_fast = true` ---------------------------------------------------------------------------------------------------- [07:34:41] Kurtis Rainbolt-Greene(@krainboltgreene):Anyways, I also think I want the ability to talk to the application from any component. ---------------------------------------------------------------------------------------------------- [07:34:59] Jamie Gaskins(@jgaskins):I kinda dig it. ---------------------------------------------------------------------------------------------------- [07:35:59] Jamie Gaskins(@jgaskins):Yeah, not being able to talk directly to the application is a little awkward sometimes. That's where the `AppRegistry` came from. It basically broadcasts to all Clearwater apps running in that environment. ---------------------------------------------------------------------------------------------------- [07:36:11] Kurtis Rainbolt-Greene(@krainboltgreene):I figured that might be it. ---------------------------------------------------------------------------------------------------- [07:36:36] Kurtis Rainbolt-Greene(@krainboltgreene):Oh ---------------------------------------------------------------------------------------------------- [07:37:25] Jamie Gaskins(@jgaskins):I don't know if that's a great thing, but I couldn't think of another way to allow communication between them without having to pass a reference to the application all the way down through the component hierarchy. ---------------------------------------------------------------------------------------------------- [07:37:36] Kurtis Rainbolt-Greene(@krainboltgreene):By the way, my app is here https://github.com/socialkardia/dashboard/tree/clearwater ---------------------------------------------------------------------------------------------------- [07:38:43] Jamie Gaskins(@jgaskins):Because I really like the idea that components are POROs. Since they're going to make up the majority of the application, I wanted to keep them lightweight and make debugging as simple as possible. ---------------------------------------------------------------------------------------------------- [07:38:57] Kurtis Rainbolt-Greene(@krainboltgreene):Agreed. ---------------------------------------------------------------------------------------------------- [07:39:20] Jamie Gaskins(@jgaskins):It's already not super simple to debug Opal apps. Getting better, but I still sometimes go "wait, where is _that_?" ---------------------------------------------------------------------------------------------------- [07:39:30] Kurtis Rainbolt-Greene(@krainboltgreene):Haha ---------------------------------------------------------------------------------------------------- [07:39:35] Kurtis Rainbolt-Greene(@krainboltgreene):Yeah, I've basically given up. ---------------------------------------------------------------------------------------------------- [07:39:47] Kurtis Rainbolt-Greene(@krainboltgreene):Or at least, I've heavily considered running my code in MRI with pry :P ---------------------------------------------------------------------------------------------------- [07:40:02] Kurtis Rainbolt-Greene(@krainboltgreene):Today I learned that opal doesn't implement `public_methods` ---------------------------------------------------------------------------------------------------- [07:40:47] Jamie Gaskins(@jgaskins):Oh, yeah, there is no public/private in Opal because JS doesn't implement it. ---------------------------------------------------------------------------------------------------- [07:42:45] Jamie Gaskins(@jgaskins):Since method calls are just invoking JS properties as functions keyed on method names, public/private access control is probably possible, but would have some weird consequences. ---------------------------------------------------------------------------------------------------- [07:43:07] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins It implements other public_* methods. ---------------------------------------------------------------------------------------------------- [07:43:43] Jamie Gaskins(@jgaskins):Really? ---------------------------------------------------------------------------------------------------- [07:44:28] Jamie Gaskins(@jgaskins):I wonder if they're just aliases of the other methods, since everything's technically public. :-) ---------------------------------------------------------------------------------------------------- [07:44:40] Kurtis Rainbolt-Greene(@krainboltgreene):Haha, probably. ---------------------------------------------------------------------------------------------------- [07:44:49] Kurtis Rainbolt-Greene(@krainboltgreene):That's kinda what I expected out of `public_methods`. ---------------------------------------------------------------------------------------------------- [07:47:10] Jamie Gaskins(@jgaskins):That's a pretty neat app so far. I see why you need the canvas stuff: https://github.com/socialkardia/dashboard/blob/clearwater/lib/dashboard.rb ---------------------------------------------------------------------------------------------------- [07:50:34] Kurtis Rainbolt-Greene(@krainboltgreene):Yep, using chart.js ---------------------------------------------------------------------------------------------------- [07:51:25] Jamie Gaskins(@jgaskins):Alrighty, I added the block handler to `Application#call`: https://github.com/clearwater-rb/clearwater/commit/296aa7deaf381de709325ef065b11db2a860ed79 ---------------------------------------------------------------------------------------------------- [07:51:53] Kurtis Rainbolt-Greene(@krainboltgreene):Awesome, thanks. ---------------------------------------------------------------------------------------------------- [07:51:57] Jamie Gaskins(@jgaskins):Now you can do something like `app.call { signal and canvas(things) }` ---------------------------------------------------------------------------------------------------- [07:52:20] Kurtis Rainbolt-Greene(@krainboltgreene):I think I'll use it to go pop through a list of events to send. ---------------------------------------------------------------------------------------------------- [07:53:05] Jamie Gaskins(@jgaskins):And now I need to get to bed. I promised my wife I'd get to bed before 4am and I have about 7 minutes before that becomes a lie. :-) ---------------------------------------------------------------------------------------------------- [07:53:55] Jamie Gaskins(@jgaskins):Let me know if you have any luck with the canvas things! ---------------------------------------------------------------------------------------------------- ############################## [2015-10-07] ############################## [14:27:40] Forrest Chang(@fkchang):ah, the hidden actual clearwater gitter .... ---------------------------------------------------------------------------------------------------- [14:29:35] Forrest Chang(@fkchang):@jgaskins on the note of attaching css to the component, I was thinking along the lines of what lissio does, i.e one section for the component which in one place might specify all the various css for whatever subelements on that component exist ---------------------------------------------------------------------------------------------------- [14:30:04] Forrest Chang(@fkchang):```ruby class MyComponent < Lissio::Component on :click, '.title' do alert 'You clicked on the title' end on :hover, '.subtitle' do alert 'You hovered over the subtitle' end html do div.title 'hue' div.subtitle 'huehuehuehue' end css do rule '.title' do font size: 32.px end rule '.subtitle' do font size: 18.px, style: :italic end end end ``` ---------------------------------------------------------------------------------------------------- [14:30:32] Forrest Chang(@fkchang):if not, I can go w/the per html element thing ---------------------------------------------------------------------------------------------------- [14:46:53] Kurtis Rainbolt-Greene(@krainboltgreene):@fkchang At work we use react and put styles in the node property, works out real well. ---------------------------------------------------------------------------------------------------- [15:02:21] Jamie Gaskins(@jgaskins):@fkchang Oh, actual CSS-style stuff, no, we don't have that. I don't think we will. One thing I've been doing that's pretty nice is this: ```ruby class MyComponent include Clearwater::Component def render div({ style: Stylesheet.my_component }, [ # ... ]) end end ``` ---------------------------------------------------------------------------------------------------- [15:03:49] Jamie Gaskins(@jgaskins):Then `Stylesheet` can be either a global module or a nested module on the component's class. And you can mix and match those if you like. ---------------------------------------------------------------------------------------------------- [15:09:30] Kurtis Rainbolt-Greene(@krainboltgreene):Right, thats kinda nice. ---------------------------------------------------------------------------------------------------- [15:39:45] Jamie Gaskins(@jgaskins):`Stylesheet.my_component` just needs to return a hash of styles. For nearly all style attributes, you can just snake-case the attribute name: ```ruby module Stylesheet module_function def my_component { background_color: 'pink', border_radius: '10px', } end end ``` ---------------------------------------------------------------------------------------------------- [15:40:59] Jamie Gaskins(@jgaskins):You do need to keep any attribute names hyphenated inside the value string, though. So for style transitions: `{ transition: 'background-color 500ms' }` ---------------------------------------------------------------------------------------------------- [17:01:42] Forrest Chang(@fkchang):@krainboltgreene can u paste in a snippet of how that looks? ---------------------------------------------------------------------------------------------------- [17:03:47] Forrest Chang(@fkchang):@jgaskins I don't know if you need to have a ruby dsl for css, hash is still ok, I do like how lissio puts all the pertinent css in 1 place in the component itself, it's well organized to my eyes, events here, html here, css here, etc. I should play with your stylesheet approach and see how it goes ---------------------------------------------------------------------------------------------------- [17:10:39] Jamie Gaskins(@jgaskins):@fkchang You don't have to use a `Stylesheet` module or anything like that. I just like it because it consolidates your styles and makes them composable. You can just as easily assign a hash to the `style` attribute of a node, though. For the equivalent of that Lissio component, it could look something like this: ```ruby class MyComponent include Clearwater::Component def title_clicked alert 'You clicked on the title' end def subtitle_hovered alert 'You hovered over the subtitle' end def render div([ div({ onclick: method(:title_clicked), style: Stylesheet.title }, 'hue'), div({ onhover: method(:subtitle_hovered), style: Stylesheet.subtitle }, 'huehuehuehue'), ]) end module Stylesheet module_function # or extend self, whichever you prefer def title { font_size: '32px' } end def subtitle { font_size: '18px', font_style: :italic, } end end end ``` ---------------------------------------------------------------------------------------------------- [17:11:38] Jamie Gaskins(@jgaskins):The only real difference between the two components is that I'm explicitly putting the events and styles on the nodes, rather than making them all use the same CSS selector. ---------------------------------------------------------------------------------------------------- [17:24:19] Kurtis Rainbolt-Greene(@krainboltgreene):@fkchang Yep, hold on. ---------------------------------------------------------------------------------------------------- [17:25:59] Kurtis Rainbolt-Greene(@krainboltgreene):@fkchang: Clearwater'd: https://gist.github.com/krainboltgreene/225cfabeb17925012bef ---------------------------------------------------------------------------------------------------- [17:26:28] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins ^^ ---------------------------------------------------------------------------------------------------- ############################## [2015-10-08] ############################## [02:38:35] Jamie Gaskins(@jgaskins):Here are two experiments I've been working on that allow you to work with actual DOM nodes: https://gist.github.com/jgaskins/5bfe94ba62eb6ba4c52b — This one uses virtual-dom "widgets". You could use this anywhere you would use a component. Every time your `Widget` gets instantiated and is about to be inserted into the DOM, its `mount` gets called. When it's about to be replaced with a new version, its `update` method is called with the previous version of itself (so any state that was setup in `mount` can be copied over). And then when it is about to be removed from the DOM, its `unmount` method is called. https://gist.github.com/jgaskins/839ec56cad03306fb93b — This one has far simpler code, but instead of being used in place of a component, it becomes an attribute of one of your elements. It doesn't actually matter what the attribute name is, so you can name it whatever you like. It hooks into the conversion to a DOM node and allows you to work with that node. ---------------------------------------------------------------------------------------------------- ############################## [2015-10-11] ############################## [02:09:54] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins Honestly I kinda like the second one. ---------------------------------------------------------------------------------------------------- [02:10:41] Kurtis Rainbolt-Greene(@krainboltgreene):But it needs some cleaning. ---------------------------------------------------------------------------------------------------- [02:10:43] Kurtis Rainbolt-Greene(@krainboltgreene):And a real API. ---------------------------------------------------------------------------------------------------- [02:11:03] Kurtis Rainbolt-Greene(@krainboltgreene):Also, side note: I got a whole bunch of people interested in clearwater at LA Ruby Conf. ---------------------------------------------------------------------------------------------------- [06:14:44] Jamie Gaskins(@jgaskins):@krainboltgreene That's fantastic news! ---------------------------------------------------------------------------------------------------- [06:24:09] Jamie Gaskins(@jgaskins):I was thinking about cleaning up those examples over the past couple days, too. I'd like to have something that's more than just Rubified `virtual-dom` API. Hilariously, I wondered how easy it would be to make a Ruby-style clone of React with the first example (the `update` method is basically React's `willReceiveProps`). ---------------------------------------------------------------------------------------------------- [06:52:18] Jamie Gaskins(@jgaskins):I'm using the second example in a Clearwater port of one of our apps at work (a real-time food delivery tracker). ---------------------------------------------------------------------------------------------------- [16:10:46] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins Thoughts on making VirtualDOM.js just an adapter? ---------------------------------------------------------------------------------------------------- [16:59:53] Jamie Gaskins(@jgaskins):@krainboltgreene I wondered about that when I was playing with the server rendering stuff (and converting from HTML-based on the client to virtual-dom to begin with), but making it an adapter was more work than I had time for at the time. ---------------------------------------------------------------------------------------------------- [16:59:58] Jamie Gaskins(@jgaskins):What else could be used in its place? Thinking of making a React adapter? ---------------------------------------------------------------------------------------------------- [17:05:23] Kurtis Rainbolt-Greene(@krainboltgreene):No, actually the top three usecases that come to mind: Generating stylesheets, generating string html, test mocks. ---------------------------------------------------------------------------------------------------- [17:07:27] Kurtis Rainbolt-Greene(@krainboltgreene):I mean we're basically doing two things: Describing a tree of nodes & turning those nodes into VirtualDOM.js calls. ---------------------------------------------------------------------------------------------------- [17:07:40] Kurtis Rainbolt-Greene(@krainboltgreene):Oh fourth usecase: ---------------------------------------------------------------------------------------------------- [17:07:54] Kurtis Rainbolt-Greene(@krainboltgreene):Using Elm-style Ports-based calls to VirtualDOM.js instead of ``. ---------------------------------------------------------------------------------------------------- [17:08:14] Kurtis Rainbolt-Greene(@krainboltgreene):At which point we could phase out the other way. ---------------------------------------------------------------------------------------------------- [17:24:30] Jamie Gaskins(@jgaskins):Hmm… I think I might like the idea of test mocks. Right now, the only way I'm testing components is basically "if I instantiate with object X, the return value of method Y should be Z" or testing the effects of methods invoked on user interactions: ```ruby describe LoginForm do # input(onkeyup: method(:set_email)) it 'sets the email field' do form = LoginForm.new event = double(target: double(value: 'me@example.com')) form.set_email event expect(form.email).to eq 'me@example.com' end end ``` These get me most of the way there, but I can't really think of a way to test `render`. ---------------------------------------------------------------------------------------------------- [17:26:14] Jamie Gaskins(@jgaskins):And if we can generate string HTML, that would remove the need for some of the server-specific things I have in #20. ---------------------------------------------------------------------------------------------------- [17:26:16] Kurtis Rainbolt-Greene(@krainboltgreene):@krainboltgreene considers rewriting Hypertext.gem for this. ---------------------------------------------------------------------------------------------------- [18:55:37] Jamie Gaskins(@jgaskins):Speaking of event code, I was just thinking yesterday, it might not be feasible to split up event- and DOM-related code. They seem to be interdependent. For example: ```ruby element.on(:click) { |event| event.target } ``` The element has event-handling functionality via `on` and the event points at a DOM node with `target`. ---------------------------------------------------------------------------------------------------- [19:13:03] Kurtis Rainbolt-Greene(@krainboltgreene):Hmmm. ---------------------------------------------------------------------------------------------------- [22:32:13] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins What's the feasability of a "nothing" component. ---------------------------------------------------------------------------------------------------- [22:32:23] Kurtis Rainbolt-Greene(@krainboltgreene):nothing([component, component, component]) ---------------------------------------------------------------------------------------------------- ############################## [2015-10-12] ############################## [01:09:38] Kurtis Rainbolt-Greene(@krainboltgreene):Working up a sample application. ---------------------------------------------------------------------------------------------------- [02:13:31] Jamie Gaskins(@jgaskins):@krainboltgreene I'm not sure what you mean. You mean one that basically supplies the array of components as the return value from `render`? ---------------------------------------------------------------------------------------------------- [02:16:08] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins Yeah. I'm thinking it would be useful for a root component. ---------------------------------------------------------------------------------------------------- [02:23:26] Jamie Gaskins(@jgaskins):You can return an array, string, number, etc, from any non-root component (I only found out the other day about the array part, purely by accident), but I'm not sure it'd be possible for `virtual-dom`'s diffing algorithm to have the app's container element have multiple children. ---------------------------------------------------------------------------------------------------- [02:27:56] Kurtis Rainbolt-Greene(@krainboltgreene):Argh. ---------------------------------------------------------------------------------------------------- [02:28:10] Jamie Gaskins(@jgaskins):I know, it seems dumb to have a single element at the app root when it does have a parent element. ---------------------------------------------------------------------------------------------------- [02:28:16] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins: Right now I'm experimenting with rendering the entire document. ---------------------------------------------------------------------------------------------------- [02:28:34] Jamie Gaskins(@jgaskins):Whoa, as in rendering straight to `document.documentElement`? ---------------------------------------------------------------------------------------------------- [02:29:19] Kurtis Rainbolt-Greene(@krainboltgreene):Yep. ---------------------------------------------------------------------------------------------------- [02:29:55] Jamie Gaskins(@jgaskins):That seems like it'd be a really fun experiment, if nothing else. :-) ---------------------------------------------------------------------------------------------------- [02:31:22] Jamie Gaskins(@jgaskins):So is the problem that you can't render the doctype and `html` as siblings? ---------------------------------------------------------------------------------------------------- [02:32:05] Jamie Gaskins(@jgaskins):Or does the `html` node not exist and I'm thinking too much in terms of HTML? ---------------------------------------------------------------------------------------------------- [02:32:21] Kurtis Rainbolt-Greene(@krainboltgreene):``` application.js:29709 Rendering Application::Component::HTML application.js:29709 Rendering Application::Component::Head application.js:29709 Rendering Application::Component::Body application.js:3611 Uncaught ArgumentError: cannot instantiate a non derived Node object ``` ---------------------------------------------------------------------------------------------------- [02:33:29] Jamie Gaskins(@jgaskins):Huh, weird. I wonder if that's an `opal-browser` error. ---------------------------------------------------------------------------------------------------- [02:34:09] Jamie Gaskins(@jgaskins):Also, I just checked and apparently `document.documentElement` _is_ the `html` node. I didn't know that because I'm not usually working with DOM nodes that far up the tree. :-) ---------------------------------------------------------------------------------------------------- [02:35:09] Jamie Gaskins(@jgaskins):@krainboltgreene https://github.com/opal/opal-browser/blob/master/opal/browser/dom/node.rb#L34 ---------------------------------------------------------------------------------------------------- [02:36:08] Kurtis Rainbolt-Greene(@krainboltgreene):Argh, so I'm going to need to add some debugger statements to that. ---------------------------------------------------------------------------------------------------- [02:36:30] Jamie Gaskins(@jgaskins):Yeah. I wonder what node it was trying to create. ---------------------------------------------------------------------------------------------------- [02:36:46] Kurtis Rainbolt-Greene(@krainboltgreene):That array should be a constant. ---------------------------------------------------------------------------------------------------- [02:40:30] Jamie Gaskins(@jgaskins):Yeah, it seems like the entire idea behind it is to map native-DOM node types to `Opal::Browser::DOM::Node` classes. One direction of that mapping uses constants and the other uses a lazily-instantiated class-level ivar. :-) ---------------------------------------------------------------------------------------------------- [02:42:41] Kurtis Rainbolt-Greene(@krainboltgreene):DOCUMENT_TYPE_NODE || 10 ---------------------------------------------------------------------------------------------------- [02:44:11] Kurtis Rainbolt-Greene(@krainboltgreene):I guess that makes sense. ---------------------------------------------------------------------------------------------------- [02:44:52] Jamie Gaskins(@jgaskins):It's breaking on creating a `Document` node? ---------------------------------------------------------------------------------------------------- [02:44:59] Kurtis Rainbolt-Greene(@krainboltgreene):Lol its the ---------------------------------------------------------------------------------------------------- [02:45:10] Kurtis Rainbolt-Greene(@krainboltgreene):Oh, woops, I was doing $document ---------------------------------------------------------------------------------------------------- [02:45:36] Kurtis Rainbolt-Greene(@krainboltgreene):...And #documentElement doesn't exist. ---------------------------------------------------------------------------------------------------- [02:45:44] Jamie Gaskins(@jgaskins):lol You were trying to insert the doctype into the `$document` node? ---------------------------------------------------------------------------------------------------- [02:46:18] Jamie Gaskins(@jgaskins):Looks like it's `Document#root` ---------------------------------------------------------------------------------------------------- [02:46:42] Jamie Gaskins(@jgaskins):@krainboltgreene https://github.com/opal/opal-browser/blob/master/opal/browser/dom/document.rb#L106-L108 ---------------------------------------------------------------------------------------------------- [02:47:29] Kurtis Rainbolt-Greene(@krainboltgreene):I wonder why it's not just a straight up match. ---------------------------------------------------------------------------------------------------- [02:48:21] Kurtis Rainbolt-Greene(@krainboltgreene):Argh, I hate this bug. ---------------------------------------------------------------------------------------------------- [02:48:40] Kurtis Rainbolt-Greene(@krainboltgreene):Sometimes &block arguments get passed as nil. ---------------------------------------------------------------------------------------------------- [02:49:32] Jamie Gaskins(@jgaskins):Really? ---------------------------------------------------------------------------------------------------- [02:50:29] Kurtis Rainbolt-Greene(@krainboltgreene):Yup. I plan on reporting it tomorrow. ---------------------------------------------------------------------------------------------------- [02:50:31] Jamie Gaskins(@jgaskins):I haven't seen that, but I run on opal master. Maybe it's a bug that's been fixed but hasn't been released yet. ---------------------------------------------------------------------------------------------------- [02:53:10] Kurtis Rainbolt-Greene(@krainboltgreene):Opal already loaded. Loading twice can cause troubles, please fix your setup. ---------------------------------------------------------------------------------------------------- [02:53:11] Kurtis Rainbolt-Greene(@krainboltgreene):Haha ---------------------------------------------------------------------------------------------------- [02:53:25] Jamie Gaskins(@jgaskins):lol ---------------------------------------------------------------------------------------------------- [02:54:06] Kurtis Rainbolt-Greene(@krainboltgreene):Oh fuck it worked. ---------------------------------------------------------------------------------------------------- [02:54:13] Jamie Gaskins(@jgaskins):Nice!! ---------------------------------------------------------------------------------------------------- [02:54:17] Kurtis Rainbolt-Greene(@krainboltgreene):...Nevemrind ---------------------------------------------------------------------------------------------------- [02:55:28] Kurtis Rainbolt-Greene(@krainboltgreene):https://gist.github.com/krainboltgreene/d84ba94c4ee05d009a6b ---------------------------------------------------------------------------------------------------- [02:56:05] Jamie Gaskins(@jgaskins):hahahahaha ---------------------------------------------------------------------------------------------------- [02:56:37] Kurtis Rainbolt-Greene(@krainboltgreene):brb, store time. ---------------------------------------------------------------------------------------------------- [02:56:39] Jamie Gaskins(@jgaskins):What're you passing as the class? ---------------------------------------------------------------------------------------------------- [02:57:34] Kurtis Rainbolt-Greene(@krainboltgreene):A Hash, I'm sure. ---------------------------------------------------------------------------------------------------- [03:53:50] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins: Well, look. This would be solvable if I could return an array from `#render`. ---------------------------------------------------------------------------------------------------- [03:55:22] Jamie Gaskins(@jgaskins):Oh, I just realized there were two `html` nodes there. I only noticed `class="[object Object]"` before. :-) ---------------------------------------------------------------------------------------------------- [03:55:35] Kurtis Rainbolt-Greene(@krainboltgreene):Ah yeah. ---------------------------------------------------------------------------------------------------- [03:56:14] Jamie Gaskins(@jgaskins):That's what I was laughing at. I thought you were showing me it was working, but had weird class properties. :-) ---------------------------------------------------------------------------------------------------- [03:56:59] Kurtis Rainbolt-Greene(@krainboltgreene):It makes sense really. ---------------------------------------------------------------------------------------------------- [03:57:20] Kurtis Rainbolt-Greene(@krainboltgreene):`$document.root` points to ``, which is where I hook the application. ---------------------------------------------------------------------------------------------------- [03:57:41] Kurtis Rainbolt-Greene(@krainboltgreene):So my `tag_name("html")` is going to be in that element. ---------------------------------------------------------------------------------------------------- [03:59:19] Jamie Gaskins(@jgaskins):Yeah, since we need a container element for the app and the app needs a root node, that's a bit of a tough constraint. ---------------------------------------------------------------------------------------------------- [16:59:02] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins I think if we refactored Clearwater::Application we could do Array of node components. ---------------------------------------------------------------------------------------------------- ############################## [2015-10-13] ############################## [16:41:22] Kurtis Rainbolt-Greene(@krainboltgreene):Removing the kwarg "solved" it. ---------------------------------------------------------------------------------------------------- [16:52:34] Kurtis Rainbolt-Greene(@krainboltgreene):https://github.com/clearwater-rb/clearwater.libruby.org ---------------------------------------------------------------------------------------------------- [18:42:42] Jamie Gaskins(@jgaskins):Weird. I've noticed some bugs with kwargs, as well. I need to file an issue. ---------------------------------------------------------------------------------------------------- [18:46:56] Jamie Gaskins(@jgaskins):… or jump on the one you're filing ---------------------------------------------------------------------------------------------------- [18:56:02] Jamie Gaskins(@jgaskins):Regarding the example Clearwater app, it's pretty neat, and I understand why you did it the way you did, but I'm concerned that someone looking for a "getting started with Clearwater" example would probably think that Clearwater is too complicated to get going with after seeing that. I wonder if it'd be a good idea to have a minimal example and a "this is what your app might look like when it's older and has been through a lot of refactoring" example. ---------------------------------------------------------------------------------------------------- [20:07:12] Kurtis Rainbolt-Greene(@krainboltgreene):I mean, this is probably a good time to have a discussion of your idea of what a "minimal" clearwater application is. ---------------------------------------------------------------------------------------------------- [20:14:29] Forrest Chang(@fkchang):@krainboltgreene trying out clearwater.libruby.org , in the absence of instrutions, I'm assuming I do ``` bin/setup bin/build ``` Then open site/index.html. Nothing seems to happen on the app, I'll note that it can't find the analytics.js or the favicon. Should I be using broccoli serve? ---------------------------------------------------------------------------------------------------- [20:15:36] Kurtis Rainbolt-Greene(@krainboltgreene):@fkchang Sorry, do two processes: `bundle exec guard` and `node_modules/.bin/http-server site/` ---------------------------------------------------------------------------------------------------- [20:16:03] Kurtis Rainbolt-Greene(@krainboltgreene):I haven't had a chance to make that into it's own script. ---------------------------------------------------------------------------------------------------- [20:19:18] Forrest Chang(@fkchang):2 things, nothing renders under safari for me, on chrome looks like viewing the index.html directly (which showed something on safari), I only see Application and Hello! ---------------------------------------------------------------------------------------------------- [20:19:25] Forrest Chang(@fkchang):no js errors ---------------------------------------------------------------------------------------------------- [20:19:44] Kurtis Rainbolt-Greene(@krainboltgreene):Yeah, safari has issues. ---------------------------------------------------------------------------------------------------- [20:20:01] Kurtis Rainbolt-Greene(@krainboltgreene):I think it's http-server? ---------------------------------------------------------------------------------------------------- [20:20:04] Kurtis Rainbolt-Greene(@krainboltgreene):I use chrome. ---------------------------------------------------------------------------------------------------- [20:22:14] Forrest Chang(@fkchang):yeah, so what's it supposed to do if I only see Application and Hello! ---------------------------------------------------------------------------------------------------- [20:22:25] Kurtis Rainbolt-Greene(@krainboltgreene):@fkchang So far? That's all it does, is render to the page. ---------------------------------------------------------------------------------------------------- [20:23:44] Forrest Chang(@fkchang):oh, ok, I saw all those components being required, thought it would do something ---------------------------------------------------------------------------------------------------- [20:23:52] Kurtis Rainbolt-Greene(@krainboltgreene):I just uploaded it :) ---------------------------------------------------------------------------------------------------- [20:24:00] Forrest Chang(@fkchang):sure, no prob ---------------------------------------------------------------------------------------------------- [20:24:38] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins I mean we have 3 types in my opinion: 1. Regular apps that use parts of clearwater for small pieces (views and store most likely) 2. Rails-based full scale applications 3. Standalone full scale applications ---------------------------------------------------------------------------------------------------- [20:25:05] Kurtis Rainbolt-Greene(@krainboltgreene):1 is showed off on each individual gem we split each piece into (grandcentral, component, etc) ---------------------------------------------------------------------------------------------------- [20:25:26] Kurtis Rainbolt-Greene(@krainboltgreene):2 is more your jam, and probably it's own repository (clearwaterrails.libruby.org) ---------------------------------------------------------------------------------------------------- [20:25:54] Kurtis Rainbolt-Greene(@krainboltgreene):3 is what this was intended as (clearwater-standalone.libruby.org is probably what it should be named) ---------------------------------------------------------------------------------------------------- [20:26:05] Kurtis Rainbolt-Greene(@krainboltgreene):(All of the above is my lay of the land) ---------------------------------------------------------------------------------------------------- [01:23:21] Jamie Gaskins(@jgaskins):@krainboltgreene How so? ---------------------------------------------------------------------------------------------------- [02:13:40] Jamie Gaskins(@jgaskins):@krainboltgreene Is this related to the nil block thing you were talking about last night? https://github.com/opal/opal/pull/1132/files ---------------------------------------------------------------------------------------------------- [16:41:05] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins Yes!...But it didn't fix my bug. ---------------------------------------------------------------------------------------------------- [16:41:14] Kurtis Rainbolt-Greene(@krainboltgreene):But I used it to inform myself on how to "fix" my bug. ---------------------------------------------------------------------------------------------------- ############################## [2015-10-14] ############################## [23:12:59] Jamie Gaskins(@jgaskins):@krainboltgreene Oh, I meant the structure of the Clearwater app itself. For example, where you subclassed all of the Clearwater classes for your application, I don't think most apps would need that until they were sufficiently complex to refactor to it. The reason I brought it up is that people might think that's how you have to work with Clearwater from the beginning. ---------------------------------------------------------------------------------------------------- ############################## [2015-10-17] ############################## [19:52:00] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins: I guess this is where I figure out if you want to have Clearwater be an Backbone (light weight pieces that can be used at whim), an Angular (uniform pieces that can be used to define your own framework), or an Ember (Uniform pieces that define a framework that you apply your domain on top of). ---------------------------------------------------------------------------------------------------- [21:21:58] Jamie Gaskins(@jgaskins):I don't think any of them are an exact match. Of the frameworks you mentioned, Ember is probably the closest. I actually took several ideas from Ember (like routing/URLs and the `outlet` method). I like the idea of having the `Application` object and routes pointing to persistent components (not re-instantiated on every render). ---------------------------------------------------------------------------------------------------- [21:24:59] Jamie Gaskins(@jgaskins):The things I _don't_ like about Ember are the sheer amount of magic it involves — or at least it did last time I used it (1.0 era, I think?) — and the amount of unnecessary indirection (which we get around by using a single component instead of a route, a controller, and a view). ---------------------------------------------------------------------------------------------------- [21:27:29] Kurtis Rainbolt-Greene(@krainboltgreene):Then my repo is probably what people are going to expect. ---------------------------------------------------------------------------------------------------- [21:31:10] Jamie Gaskins(@jgaskins):I don't think I understand why they would. I wouldn't expect to subclass all of the Clearwater classes unless I needed to extend them. ---------------------------------------------------------------------------------------------------- [23:01:01] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins It's how you signify control over those components. ---------------------------------------------------------------------------------------------------- [23:01:15] Kurtis Rainbolt-Greene(@krainboltgreene):I mean every Rails component is subclassed. ---------------------------------------------------------------------------------------------------- [23:01:32] Kurtis Rainbolt-Greene(@krainboltgreene):Not that it's a good thing, just I think that's what people expect. ---------------------------------------------------------------------------------------------------- ############################## [2015-10-27] ############################## [03:02:04] Jamie Gaskins(@jgaskins):I forgot to mention, I was on the Read the Source video podcast last week with Charles Max Wood (from the Ruby Rogues and JavaScript Jabber). http://hangouts.readthesource.io/hangouts/clearwater/ ---------------------------------------------------------------------------------------------------- [03:28:14] Forrest Chang(@fkchang):indeed, and it was a good talk, your code looked to be in pretty good shape ---------------------------------------------------------------------------------------------------- [04:54:34] Kurtis Rainbolt-Greene(@krainboltgreene):Yeah, my coworkers have been asking me about it all week. ---------------------------------------------------------------------------------------------------- [15:10:50] Jamie Gaskins(@jgaskins):@fkchang: Thanks! @krainboltgreene Awesome! ---------------------------------------------------------------------------------------------------- ############################## [2015-10-28] ############################## [20:16:19] Forrest Chang(@fkchang):@jgaskins are you using grand central on any projects? I'm probably going to try it w/react.rb at some point. ---------------------------------------------------------------------------------------------------- [20:23:33] Jamie Gaskins(@jgaskins):@fkchang I'm using it on a real-time delivery tracker app that I'm trying to get to replace the one we currently have in production. ---------------------------------------------------------------------------------------------------- [20:25:20] Jamie Gaskins(@jgaskins):Renders at 60fps, uses a Google Map (speaking of which, I wrote Opal bindings for Gmaps; need to extract it to its own gem) ---------------------------------------------------------------------------------------------------- [20:40:27] Forrest Chang(@fkchang):@jgaskins nice. I have yet to do any research, but I'd like to support the redux development tools w/whatever I end up using in opal, since grand central is "inspired by redux", I suppose that's the 1st place to look ---------------------------------------------------------------------------------------------------- [21:24:06] Jamie Gaskins(@jgaskins):@fkchang Yeah, I need to write some better docs for it (working on a docs site for Clearwater, too). ---------------------------------------------------------------------------------------------------- ############################## [2015-11-22] ############################## [20:30:27] Kurtis Rainbolt-Greene(@krainboltgreene):Been spending so much time in ES6 and Stage 0. ---------------------------------------------------------------------------------------------------- [21:11:25] Forrest Chang(@fkchang):@krainboltgreene is that a good thing? ---------------------------------------------------------------------------------------------------- [21:13:49] Kurtis Rainbolt-Greene(@krainboltgreene):I'm loving it. It makes JS a great language. ---------------------------------------------------------------------------------------------------- ############################## [2015-11-23] ############################## [00:15:27] Jamie Gaskins(@jgaskins):@krainboltgreene ES6 is indeed a pretty amazing update to JS, but what's stage 0? ---------------------------------------------------------------------------------------------------- [00:18:02] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins "ES7+" ---------------------------------------------------------------------------------------------------- [00:18:18] Kurtis Rainbolt-Greene(@krainboltgreene):They basically group them into stages: 0, 1, 2, 3. ---------------------------------------------------------------------------------------------------- [00:18:40] Kurtis Rainbolt-Greene(@krainboltgreene):Where 0 is most experimental, 3 is least experimental. ---------------------------------------------------------------------------------------------------- [00:19:14] Kurtis Rainbolt-Greene(@krainboltgreene):Stage 0 is some changes plus the sum of all changes in 1..3 ---------------------------------------------------------------------------------------------------- [00:19:23] Kurtis Rainbolt-Greene(@krainboltgreene):Stage 1 is some changes plus the sum of all changes in 2..3 ---------------------------------------------------------------------------------------------------- [00:19:24] Kurtis Rainbolt-Greene(@krainboltgreene):Etc. ---------------------------------------------------------------------------------------------------- [00:19:56] Jamie Gaskins(@jgaskins):Ahh, okay ---------------------------------------------------------------------------------------------------- [00:24:07] Kurtis Rainbolt-Greene(@krainboltgreene):Example: Array spread: [ ...things, thing ] is in ES6 ---------------------------------------------------------------------------------------------------- [00:24:22] Kurtis Rainbolt-Greene(@krainboltgreene):Object spread: { ...object, foo: 'bar' } is in Stage-3 ---------------------------------------------------------------------------------------------------- [00:24:27] Kurtis Rainbolt-Greene(@krainboltgreene):It's basically "in". ---------------------------------------------------------------------------------------------------- [00:35:36] Jamie Gaskins(@jgaskins):Yeah, those things make it a lot easier to work in JS. Not being able to say "this hash, but with these properties" without relying on something like Underscore.js was really frustrating. ---------------------------------------------------------------------------------------------------- [00:58:31] Kurtis Rainbolt-Greene(@krainboltgreene):Yah. ---------------------------------------------------------------------------------------------------- ############################## [2015-11-28] ############################## [07:57:45] Jamie Gaskins(@jgaskins):I showed off my Clearwater port of part of our most performance-intensive React app to our VP of engineering last week. It rendered at 60fps even on his 3-year-old phone, which is pretty amazing since the React+Backbone version is pretty choppy on desktop during peak hours. It uses web sockets for real-time updates and they come in pretty hot, but Clearwater+Grand Central handle it like a champ. It's partly Backbone because we were porting it from Backbone/Marionette, but never finished — at the time, it was fast enough just to have the hot spots running on React. The top-level app containers and the models are still Backbone. In the Clearwater version, the models are POROs and everything's immutable. It works pretty well. ---------------------------------------------------------------------------------------------------- [16:59:34] Michał Kalbarczyk(@fazibear): ---------------------------------------------------------------------------------------------------- [22:37:36] Kurtis Rainbolt-Greene(@krainboltgreene):Very very cool. ---------------------------------------------------------------------------------------------------- ############################## [2015-11-30] ############################## [19:20:09] Forrest Chang(@fkchang):@jgaskins nice ---------------------------------------------------------------------------------------------------- ############################## [2015-12-03] ############################## [06:23:41] Jamie Gaskins(@jgaskins):Nah, the server-side `Component#render` returns HTML, so it could be done on its own. ---------------------------------------------------------------------------------------------------- [06:23:45] Andrew Havens(@andrewhavens):haha, yeah, I’m hoping to create a CMS that doesn’t require rails ---------------------------------------------------------------------------------------------------- [06:26:43] Jamie Gaskins(@jgaskins):I don't think that PR for server rendering will merge cleanly as-is because I had to modify the component a bit when I added SVG support. I'd like to try to get it ready soon, though. Server rendering is definitely the new hotness. :-) ---------------------------------------------------------------------------------------------------- [06:27:12] Andrew Havens(@andrewhavens):=] ---------------------------------------------------------------------------------------------------- [14:17:17] Forrest Chang(@fkchang):@jgaskins cool beans on performance. I've been touting the impressiveness of clearwater perf to my coworker for a while, I think it's a testament to the viability of opal when it can run fast as, sometimes faster than pure js react.js ---------------------------------------------------------------------------------------------------- [14:19:29] Forrest Chang(@fkchang):I would completely use clearwater if I wasn't interested in react-native opening up IOS/Android ---------------------------------------------------------------------------------------------------- [14:19:37] Forrest Chang(@fkchang):which a current project hopes to do ---------------------------------------------------------------------------------------------------- [14:24:41] Forrest Chang(@fkchang):on the note of dbmonster and react.rb I did a partial port to test it out on opal-playground http://git.io/v8Sm7 ---------------------------------------------------------------------------------------------------- [15:10:04] Michał Kalbarczyk(@fazibear):How you can figure out app performance with this bunch of random numbers ? ---------------------------------------------------------------------------------------------------- [18:00:54] Jamie Gaskins(@jgaskins):@fkchang Nice! ---------------------------------------------------------------------------------------------------- [18:02:22] Jamie Gaskins(@jgaskins):@fazibear It's about rendering speed. The numbers themselves are meaningless. It's about how quickly it re-renders. ---------------------------------------------------------------------------------------------------- [18:03:02] Jamie Gaskins(@jgaskins):If you run the two React and Clearwater versions side-by-side, you can see the frame rate of the Clearwater one is much higher. ---------------------------------------------------------------------------------------------------- [21:55:58] Michał Kalbarczyk(@fazibear):I need much more accurate measurements than the eye. I don't see differences, dights are required ;) ---------------------------------------------------------------------------------------------------- [22:13:03] Jamie Gaskins(@jgaskins):@fazibear Apparently Chrome has an FPS counter for just such a task: https://www.reddit.com/r/ruby/comments/3v96p2/clearwater_ruby_on_the_front_end_outperforms/cxm2lv0 ---------------------------------------------------------------------------------------------------- [22:20:56] Jamie Gaskins(@jgaskins):Here's a video of Clearwater outperforming React by almost 50% on my machine: https://youtu.be/sWp1KxDzuRE ---------------------------------------------------------------------------------------------------- [22:21:36] Adrian Madrid(@aemadrid):what are you using to show the FPS? ---------------------------------------------------------------------------------------------------- [22:22:25] Jamie Gaskins(@jgaskins):@aemadrid Chrome's FPS meter. Inside Chrome Dev Tools, hit Esc, click the "Rendering" tab that pops up, then tick the "Show FPS meter" box. ---------------------------------------------------------------------------------------------------- [22:22:40] Adrian Madrid(@aemadrid):nice, didn’t know about that ---------------------------------------------------------------------------------------------------- [22:22:48] Jamie Gaskins(@jgaskins):I'd forgotten all about it. ---------------------------------------------------------------------------------------------------- [22:22:58] Jamie Gaskins(@jgaskins):Until someone mentioned it in the Reddit thread. ---------------------------------------------------------------------------------------------------- [05:17:58] Jamie Gaskins(@jgaskins):A lot of people have been using a thing called DB Monster to demonstrate the rendering performance of their front-end framework (basically, TodoMVC for perf). So I thought I'd throw Clearwater into it, as well. Ember (2.0 w/ Glimmer engine): https://dbmonster.firebaseapp.com Backbone: https://jashkenas.github.io/dbmonster/ React: http://web-perf.github.io/react-worker-dom/dist/index.html?worker=false&rows=20 React + web worker: http://web-perf.github.io/react-worker-dom/dist/index.html?worker=true&rows=20 Clearwater version: https://clearwater-dbmonster.herokuapp.com The performance of the Clearwater version is about on par with the React+worker one, but uses half as much CPU. It uses a nearly identical amount of RAM as the React version. The Backbone and Ember versions aren't even close. ---------------------------------------------------------------------------------------------------- [05:20:18] Andrew Havens(@andrewhavens):wow, had no idea clearwater was doing so well in terms of performance. good to hear. nice work! ---------------------------------------------------------------------------------------------------- [05:22:04] Jamie Gaskins(@jgaskins):@andrewhavens Thanks! I've been putting in a lot of work trying to make sure Clearwater apps are fast by default. :-) This has included a lot of PRs to Opal to optimize some things upstream, as well. ---------------------------------------------------------------------------------------------------- [05:22:29] Jamie Gaskins(@jgaskins):Basically, I don't want people to try it and go "ugh, this is slow" and give up. ---------------------------------------------------------------------------------------------------- [05:33:15] Andrew Havens(@andrewhavens):makes me want to take a second look at clearwater =] ---------------------------------------------------------------------------------------------------- [05:33:49] Jamie Gaskins(@jgaskins):@andrewhavens Here's the code for the Clearwater implementation: https://github.com/jgaskins/clearwater-app/tree/db-monster/app/assets/javascripts ---------------------------------------------------------------------------------------------------- [05:47:42] Andrew Havens(@andrewhavens):cool! ---------------------------------------------------------------------------------------------------- [05:48:03] Andrew Havens(@andrewhavens):I didn’t remember that clearwater was so focused on components (like react) ---------------------------------------------------------------------------------------------------- [05:50:17] Andrew Havens(@andrewhavens):I recently came across this Opal version of React and thought it was pretty nice: https://github.com/zetachang/react.rb ---------------------------------------------------------------------------------------------------- [05:50:56] Andrew Havens(@andrewhavens):I am only getting started learning about React, but I like the simplicity of these componentized javascript frameworks ---------------------------------------------------------------------------------------------------- [05:51:31] Jamie Gaskins(@jgaskins):In the beginning, it wasn't about components. It was very much an MVC framework — controllers held state and handled interactions, models re-rendered views when they changed. But then I realized I was frequently using views more like components or presenters, so I tried the component structure and it simplified things a _lot_. ---------------------------------------------------------------------------------------------------- [05:52:25] Jamie Gaskins(@jgaskins):Yeah, I was pretty excited about React.rb. I actually experimented with trying to use React within Clearwater for a while. I blogged about it here: http://jgaskins.org/blog/2015/04/06/clearwater-and-the-virtual-dom ---------------------------------------------------------------------------------------------------- [05:58:34] Andrew Havens(@andrewhavens):I think the hardest thing for me to accept is the co-mingling of logic and template (which is why I was initially turned off by React) ---------------------------------------------------------------------------------------------------- [05:59:34] Jamie Gaskins(@jgaskins):Totally understandable, especially when web devs have preached for years not to mix HTML, CSS, and JS. :-) ---------------------------------------------------------------------------------------------------- [06:00:31] Andrew Havens(@andrewhavens):=] ---------------------------------------------------------------------------------------------------- [06:01:23] Andrew Havens(@andrewhavens):does clearwater render on the server in ruby or only on the client in opal? ---------------------------------------------------------------------------------------------------- [06:01:31] Andrew Havens(@andrewhavens):(I mean both) ---------------------------------------------------------------------------------------------------- [06:01:38] Jamie Gaskins(@jgaskins):But it's like how people have experimented on the server side with separating parts of the app based on what they were concerned with (like articles, comments, etc) instead of separating them into groups of models, views, and controllers. So instead of having all your models together, you have your article_view, article_controller, and article model grouped up. ---------------------------------------------------------------------------------------------------- [06:03:24] Jamie Gaskins(@jgaskins):Only the client for now, but I've done some server-rendering work in #20. It works, but I want to make it better before merging it. ---------------------------------------------------------------------------------------------------- [06:04:02] Jamie Gaskins(@jgaskins):Mostly, I want to be able to handle routing on the server side without copy/pasting the router to the server-side app. :-) ---------------------------------------------------------------------------------------------------- [06:06:30] Jamie Gaskins(@jgaskins):It was pretty easy to get working, to be honest. The `Component` and the `Application` needed a somewhat different implementation (due to differences between HTML and DOM objects), but everything else (like routing) was pretty easy to generalize. ---------------------------------------------------------------------------------------------------- [06:07:34] Jamie Gaskins(@jgaskins):I tried it on both Rails and Roda. On both I was able to navigate around my app even with JS turned off. It was pretty awesome. ---------------------------------------------------------------------------------------------------- [06:08:06] Andrew Havens(@andrewhavens):Yeah, I’ve decided components is the way to go. I’ve always liked Backbone because Views felt like components. ---------------------------------------------------------------------------------------------------- [06:08:56] Jamie Gaskins(@jgaskins):Exactly. So much of the original implementation of Clearwater was inspired by Backbone (we use it a lot at work). ---------------------------------------------------------------------------------------------------- [06:09:36] Andrew Havens(@andrewhavens):I guess I wonder if there is a way to support templates too ---------------------------------------------------------------------------------------------------- [06:09:47] Andrew Havens(@andrewhavens):I read your blog post ---------------------------------------------------------------------------------------------------- [06:10:27] Andrew Havens(@andrewhavens):I like the Slim/HAML syntax…I find the clearwater DOM DSL a little hard to read =/ ---------------------------------------------------------------------------------------------------- [06:11:30] Jamie Gaskins(@jgaskins):Using Slim templates was hard to give up, both because of how awesome it was to render Slim on the client and because I really like Slim. ---------------------------------------------------------------------------------------------------- [06:12:00] Andrew Havens(@andrewhavens):I really like the HAML style DSL that the react.rb/reactive-ruby provides: https://github.com/zetachang/react.rb/wiki/Composing-Components ---------------------------------------------------------------------------------------------------- [06:16:20] Andrew Havens(@andrewhavens):I’m really looking for an Opal framework I can bake into my CMS that I’m building. A Javascript SPA editor for admins will be used for placing widgets/components on a page, but since I’m using Opal, I’m hoping to be able to render those components on the server side too (for normal users and search engines). ---------------------------------------------------------------------------------------------------- [06:17:59] Andrew Havens(@andrewhavens):I wouldn’t want to share my routing between client and server because they will be different ---------------------------------------------------------------------------------------------------- [06:18:00] Jamie Gaskins(@jgaskins):The block-based DSL is interesting from a particular PoV. I thought a long time about including it because people seem to like it. I wrote about it in #22, but the TLDR is that as much as I like the cool factor of it (it's really awesome that you can do things like that with Ruby), I can't think of passing a block that way the same as returning a value, which is kind of the idea. ---------------------------------------------------------------------------------------------------- [06:19:31] Jamie Gaskins(@jgaskins):Well, the server-side rendering of a Clearwater app (or any front-end app, really) would be more like a Rails engine that you mount at a particular place in your app, and then it would handle any sub-routes. ---------------------------------------------------------------------------------------------------- [06:20:16] Jamie Gaskins(@jgaskins):So the server-side app would have a superset of the routes that the client apps do. ---------------------------------------------------------------------------------------------------- [06:21:04] Andrew Havens(@andrewhavens):i see ---------------------------------------------------------------------------------------------------- [06:21:53] Jamie Gaskins(@jgaskins):It wouldn't necessarily have to be a Rails engine or a Rack app at all (my implementation of Clearwater server rendering isn't). It basically just lets you instantiate your Clearwater app on the server, then `app.render` returns the HTML, which you can include into your `app/views/home/index.html.slim` or whatever. ---------------------------------------------------------------------------------------------------- [06:23:08] Jamie Gaskins(@jgaskins):Making it a Rack app is less flexible because it doesn't let you use the framework's layout template and making it a Rails engine couples it to Rails itself — and I think enough crap in the Ruby ecosystem couples itself to Rails. ;-) ---------------------------------------------------------------------------------------------------- [06:23:14] Andrew Havens(@andrewhavens):could you render an individual component in the same way? Or would you have to use a Clearwater app as a container? ---------------------------------------------------------------------------------------------------- ############################## [2015-12-04] ############################## [04:37:31] Jamie Gaskins(@jgaskins):@fkchang Is it possible to load outside scripts in Opal Playground? ---------------------------------------------------------------------------------------------------- [04:38:04] Jamie Gaskins(@jgaskins):I'm trying to make a Clearwater example. ---------------------------------------------------------------------------------------------------- [04:52:13] Jamie Gaskins(@jgaskins):Oh wait, it looks like Opal Playground doesn't like the script. Apparently `alias` isn't defined. @fkchang What version of Opal Playground running? ---------------------------------------------------------------------------------------------------- [05:05:17] Jamie Gaskins(@jgaskins):Ah, 0.7.2. This is odd because it should run on 0.7. Looks like I'll have to investigate. ---------------------------------------------------------------------------------------------------- [05:58:54] Jamie Gaskins(@jgaskins):Well, turns out there was a bug, but it wasn't what I thought it was. I had to compile Clearwater with 0.7.2 because internals changed, so Ruby code compiled with 0.9.0.beta2 wasn't wired up to the right functions inside Opal. ---------------------------------------------------------------------------------------------------- [07:15:19] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins So I've been neck deep in ES6/React/Redux land the last two weeks. ---------------------------------------------------------------------------------------------------- [14:51:40] Jamie Gaskins(@jgaskins):@krainboltgreene Cool, liking it? ---------------------------------------------------------------------------------------------------- [16:41:12] Kurtis Rainbolt-Greene(@krainboltgreene):Yes, very much. ---------------------------------------------------------------------------------------------------- [16:41:26] Kurtis Rainbolt-Greene(@krainboltgreene):Cycle.js and vdux for the moment are my favorite. ---------------------------------------------------------------------------------------------------- [17:09:00] Forrest Chang(@fkchang):@jgaskins did you figure out what you needed? ---------------------------------------------------------------------------------------------------- [20:07:39] Jamie Gaskins(@jgaskins):@krainboltgreene Haven't used Cycle.js yet. Heard good things about it, though. ---------------------------------------------------------------------------------------------------- [20:09:12] Jamie Gaskins(@jgaskins):@fkchang Yep, it was just a compatibility issue between the version of Opal used on Opal Playground and the one I compiled Clearwater with. I ended up getting it working by compiling Clearwater with 0.7.2. ---------------------------------------------------------------------------------------------------- [22:43:12] Forrest Chang(@fkchang):@jgaskins cool, look forward to seeing the example, I can't upgrade past 0.7* until middleman supports sprockets 3, 0.8 and above switched to that ---------------------------------------------------------------------------------------------------- [23:51:39] Jamie Gaskins(@jgaskins):@fkchang Yeah, I had a lot of trouble getting Opal 0.8 into our app at work because we have a whole lot of gems using the asset pipeline that were all locked to Sprockets 2. I had to upgrade so many gems and make sure everything still worked. It was so gross. ---------------------------------------------------------------------------------------------------- ############################## [2015-12-05] ############################## [00:03:05] Jamie Gaskins(@jgaskins):Here's a basic Clearwater template for Opal Playground: http://fkchang.github.io/opal-playground/?code:class%20Layout%0A%20%20include%20Clearwater%3A%3AComponent%0A%20%20%0A%20%20def%20render%0A%20%20%20%20h1('Hello%20world')%0A%20%20end%0Aend%0A%0Aapp%20%3D%20Clearwater%3A%3AApplication.new(%0A%20%20component%3A%20Layout.new%2C%0A%20%20element%3A%20%24document%5B'%23app'%5D%0A)%0A%0Aapp.call&html_code=%3Cscript%20src%3D%22https%3A%2F%2Fs3.amazonaws.com%2Fjgaskins%2Fclearwater%2Fclearwater--compiled-by-opal-0.7.2.js%22%3E%3C%2Fscript%3E%0A%3Cdiv%20id%3D%22app%22%3E%3C%2Fdiv%3E&css_code=body%20%7B%0A%20%20background%3A%20%23eeeeee%3B%0A%7D%0A ---------------------------------------------------------------------------------------------------- [00:03:15] Jamie Gaskins(@jgaskins):@fkchang ^^ ---------------------------------------------------------------------------------------------------- [08:31:18] Forrest Chang(@fkchang):@jgaskins cool, I get what looks to be a CORS type error, I would guess it might be solved by adjusting the CORS settings on the compiled file on s3? ---------------------------------------------------------------------------------------------------- [21:37:26] Adrian Madrid(@aemadrid):getting Uncaught NameError: uninitialized constant Layout::Clearwater ---------------------------------------------------------------------------------------------------- [23:46:55] Jamie Gaskins(@jgaskins):@fkchang Huh. It shows `The XSS Auditor refused to execute a script in '' because its source code was found within the request. The auditor was enabled as the server sent neither an 'X-XSS-Protection' nor 'Content-Security-Policy' header.` It sounds like it doesn't like the code being inside the URL with a remote script? ---------------------------------------------------------------------------------------------------- [23:47:15] Jamie Gaskins(@jgaskins):@aemadrid Probably related to the XSS thing. I'll try to work on it later. ---------------------------------------------------------------------------------------------------- ############################## [2015-12-07] ############################## [03:53:44] Jamie Gaskins(@jgaskins):@fkchang It looks like it's because the script's location is in the URL. It works if you change `s3.amazonaws.com/jgaskins` in the script src attribute to `jgaskins.s3.amazonaws.com` after the page loads, but if you generate another link with that URL and load that URL, it breaks again. Once you execute it without the error, if you change it back it will give you the XSS error again but the script is already loaded at that point so it doesn't matter. It also doesn't seem to be something I can fix with CORS headers on my S3 bucket. Is there a way you can add `X-Content-Security-Policy` / `X-XSS-Protection` headers to Opal Playground to whitelist `s3.amazonaws.com`? I don't know how GH-pages works. ---------------------------------------------------------------------------------------------------- [03:55:40] Jamie Gaskins(@jgaskins):Otherwise, I think in order to support that, you'd have to be able to reference it without specifying the script URL inside the Opal Playground URL. ---------------------------------------------------------------------------------------------------- [03:56:48] Jamie Gaskins(@jgaskins):So something like JSBin does where you save it to their DB and reference the environment by id. ---------------------------------------------------------------------------------------------------- [17:12:04] Forrest Chang(@fkchang):@jgaskins I'll look into it, I've been trying to avoid db's so that I can keep it free as a GH page, but I might have to bite the bullet because, I've gone over the max size limit for urls for whatever GH uses as their webserver. I could also just include clearwater into the compile. I would like to setup some sort of "libraries to add" dropdown, but I'd need people to precompile their libs like you did for clearwater ---------------------------------------------------------------------------------------------------- [17:43:28] Jamie Gaskins(@jgaskins):@fkchang Cool. I played around with making a Clearwater Playground app this past weekend. I'd like to be able to show off Clearwater apps reasonably well, and Opal Playground will work for it, but for some apps people will want to include routing, which is a little more difficult on an app that is already served from a sub-route (though Clearwater's router does have support for that). ---------------------------------------------------------------------------------------------------- [17:46:41] Forrest Chang(@fkchang):@jgaskins interesting, I compiled in that reactive-router for react.rb, which has the same issue. What clearwater gems should I include? Also been meaning to give grand central a try as I try to digest the various approaches to flux ---------------------------------------------------------------------------------------------------- [20:03:53] Jamie Gaskins(@jgaskins):@fkchang I checked out the Elm language tutorial from Pragmatic Studio over the weekend, too. Grand Central works a lot like the Elm architecture for state management. ---------------------------------------------------------------------------------------------------- [20:19:46] Michał Kalbarczyk(@fazibear):@fkchang @jgaskins If you want to deploy static files try netlify. It works fine for me :) ---------------------------------------------------------------------------------------------------- [20:32:42] Forrest Chang(@fkchang):@jgaskins interesting, my coworker did the pragmatic elm tutorial on the plane flight back from the East Coast no Friday ---------------------------------------------------------------------------------------------------- [21:39:42] Jamie Gaskins(@jgaskins):@fkchang It's pretty interesting. I'm not ready to go full FP, but using a functional state container has been awesome in Clearwater apps. ---------------------------------------------------------------------------------------------------- ############################## [2015-12-08] ############################## [02:57:58] Jamie Gaskins(@jgaskins):@fkchang I just realized I missed the part of one your messages earlier about which Clearwater gems to include. I just use `clearwater` and `grand_central` gems. ---------------------------------------------------------------------------------------------------- [02:58:21] Jamie Gaskins(@jgaskins):Sorry, I saw the part about Grand Central and tunnel-visioned on it. :-) ---------------------------------------------------------------------------------------------------- [06:57:38] Forrest Chang(@fkchang):@jgaskins getting this ``` Bundler could not find compatible versions for gem "opal": In Gemfile: grand_central (>= 0) ruby depends on opal (~> 0.8) ruby opal (0.7.2) ``` ---------------------------------------------------------------------------------------------------- [06:58:32] Forrest Chang(@fkchang):I tried all the versions ---------------------------------------------------------------------------------------------------- [13:39:50] Jamie Gaskins(@jgaskins):@fkchang Ah, apparently I set grand_central's opal dependency at 0.8. I didn't realize that. I'll update that today. It should work just fine on 0.7. ---------------------------------------------------------------------------------------------------- [16:27:56] Martin Becker(@Thermatix):hi, I'm building an opal router that's framework agnostic ---------------------------------------------------------------------------------------------------- [16:28:05] Martin Becker(@Thermatix):but I'm still having a little trouble with the route/matching ---------------------------------------------------------------------------------------------------- [16:28:55] Martin Becker(@Thermatix):also in `params_for_path` I have to ask how does `path_parts = path.split("/").reject(&:empty?)` work? I thought strings were immutable? ---------------------------------------------------------------------------------------------------- [16:31:25] Forrest Chang(@fkchang):@jgaskins lemme know and I'll rebuild and push it up to GH ---------------------------------------------------------------------------------------------------- [18:05:43] Jamie Gaskins(@jgaskins):@Thermatix Yep, they're immutable. `String#split` returns an array of the parts of the string surrounding the delimiter you pass in, then rejecting the empty strings in that array removes any parts caused by leading, trailing, or duplicate slashes. ``` 2.2.3 :001 > '/foo//bar/'.split('/').reject(&:empty?) => ["foo", "bar"] ``` ---------------------------------------------------------------------------------------------------- [18:06:29] Jamie Gaskins(@jgaskins):@fkchang Sure thing, I'll do it when I've got a minute to chill. :+1: ---------------------------------------------------------------------------------------------------- [19:21:24] Martin Becker(@Thermatix):hmmm so methods that directly affect the string like `gsub` don't work but things that create something new like `.split` work? ---------------------------------------------------------------------------------------------------- [19:55:02] Jamie Gaskins(@jgaskins):@Thermatix `gsub` will work because it doesn't modify `self`. You can't use `gsub!`, though. ---------------------------------------------------------------------------------------------------- [21:05:42] Jamie Gaskins(@jgaskins):@fkchang Should be good to go with GrandCentral. ---------------------------------------------------------------------------------------------------- [21:07:17] Martin Becker(@Thermatix):... I feel stupid... ---------------------------------------------------------------------------------------------------- [21:22:17] Jamie Gaskins(@jgaskins):Nah, it's okay. It's easy to forget in Ruby what does and doesn't mutate `self`. :-) ---------------------------------------------------------------------------------------------------- [23:26:04] Forrest Chang(@fkchang):@jgaskins it's up http://fkchang.github.io/opal-playground/?code:class%20Layout%0A%20%20include%20Clearwater%3A%3AComponent%0A%20%20%0A%20%20def%20render%0A%20%20%20%20h1('Hello%20world')%0A%20%20end%0Aend%0A%0Aapp%20%3D%20Clearwater%3A%3AApplication.new(%0A%20%20component%3A%20Layout.new%2C%0A%20%20element%3A%20%24document%5B'%23app'%5D%0A)%0A%0Aapp.call&html_code=%3Cdiv%20id%3D%22app%22%3E%3C%2Fdiv%3E&css_code=body%20%7B%0A%20%20background%3A%20%23eeeeee%3B%0A%7D%0A ---------------------------------------------------------------------------------------------------- ############################## [2015-12-09] ############################## [00:30:00] Jamie Gaskins(@jgaskins):@fkchang Sweet! Thanks! ---------------------------------------------------------------------------------------------------- ############################## [2015-12-12] ############################## [04:33:53] Jamie Gaskins(@jgaskins):I'm experimenting with removing `opal-browser` from Clearwater. ---------------------------------------------------------------------------------------------------- [04:35:15] Jamie Gaskins(@jgaskins):Because we're using a virtual DOM, we don't need the full functionality. We just need basic support for browser functionality and `opal-browser` is pretty big. ---------------------------------------------------------------------------------------------------- [04:39:05] Jamie Gaskins(@jgaskins):For example, Clearwater itself only needs less than a half-dozen methods on each of `window`, `document`, and elements. For events it needs a couple more, but still not much. I've fit all of it into 180 lines of LoC. ---------------------------------------------------------------------------------------------------- [04:41:34] Jamie Gaskins(@jgaskins):There's still the matter of AJAX support, though. That part will probably be pretty much a copy/paste of `Opal::Browser::HTTP` because cross-browser support for that is a mess. However, since the router already only supports IE10+ because of `pushState` (all other browsers released in the past 5 years already support it), we may not need to worry *too* much about supporting every browser. ---------------------------------------------------------------------------------------------------- [04:43:19] Jamie Gaskins(@jgaskins):But so far, removing `opal-browser` has reduced the minified/gzipped payload of a TodoMVC app by almost 40KB (122KB->83KB). ---------------------------------------------------------------------------------------------------- [18:16:12] Forrest Chang(@fkchang):@jgaskins @meh mentioned he wants to make opal browser more cherry pickable, this might give him the motivation to do it, then arguably you could just pull in the parts you need ---------------------------------------------------------------------------------------------------- [22:57:21] Jamie Gaskins(@jgaskins):@fkchang I talked to him about it a while ago. I've worked on that, though, and it was _really_ hard to do due to the way `opal-browser` is designed. It's super convenient for its use case, but because it does so much, it depends on itself in a lot of places. I think it'll be a lot of work to make it cherry-pickable. The work I've done so far in #32 does most of what is actually needed in a Clearwater app: basic DOM support (you should do _very_ little with the actual DOM since you should rely on the virtual DOM and app state), simple events, and AJAX support. I just want to tune and improve that support a bit. ---------------------------------------------------------------------------------------------------- ############################## [2015-12-13] ############################## [00:17:04] Michał Kalbarczyk(@fazibear):@jgaskins Wait! What do you think about rewrite opal-browser ? I have same problems with it. I also need a tiny replacement with same or similar api. A cherry-pickable replacement ? ---------------------------------------------------------------------------------------------------- [00:23:19] Michał Kalbarczyk(@fazibear):You include a subset of opal-browser in clearwater, I'm thinkin of write a opal-browser-mini gem so I could replace it easliy. I think we're doing same thing ? ---------------------------------------------------------------------------------------------------- [00:24:26] Michał Kalbarczyk(@fazibear):Including whole opal-browser was a bed idea :( ---------------------------------------------------------------------------------------------------- [22:43:55] Jamie Gaskins(@jgaskins):@fazibear It could easily be extracted so anyone could use it. In fact, that's pretty much what I'm aiming for. :-) Minimal DOM support (with events), good AJAX support, and that'd be about it. Anything further (like your webcam stuff) would probably be worthy of its own gem. ---------------------------------------------------------------------------------------------------- [22:45:49] Jamie Gaskins(@jgaskins):I wouldn't say including `opal-browser` was a _bad_ idea. It was the most pragmatic choice for both of us at the time. Now that both projects have multiple apps working, it's a good time to start optimizing things like load time by streamlining our DOM abstraction. ---------------------------------------------------------------------------------------------------- ############################## [2015-12-23] ############################## [05:36:50] Jamie Gaskins(@jgaskins):@fazibear I extracted the browser implementation in #32 into a separate gem called `bowser` if you want to give it a shot with Inesita. ---------------------------------------------------------------------------------------------------- [05:37:03] Jamie Gaskins(@jgaskins):@fazibear https://github.com/clearwater-rb/bowser ---------------------------------------------------------------------------------------------------- ############################## [2015-12-31] ############################## [15:22:07] Jamie Gaskins(@jgaskins):@krainboltgreene We seem to have most of what we need featurewise, so I've been thinking of releasing 1.0.0.beta soon. Any thoughts? ---------------------------------------------------------------------------------------------------- [17:33:46] Kurtis Rainbolt-Greene(@krainboltgreene):At this point you know way more about what's going out than me, but my suggestion is the name of the version be: 1.0.0-rc1 ---------------------------------------------------------------------------------------------------- [19:38:53] Jamie Gaskins(@jgaskins):Will Bundler/Rubygems recognize the `-` as a separator for version specifiers like `"~> 1.0.0-rc1"`? I thought it had to be a dot. ---------------------------------------------------------------------------------------------------- [19:40:28] Kurtis Rainbolt-Greene(@krainboltgreene):It will accept and recognize it, but sadly it formats it on ppush ---------------------------------------------------------------------------------------------------- [19:40:48] Kurtis Rainbolt-Greene(@krainboltgreene):But now that I'm paid to work on Rubygems I can fix that. ---------------------------------------------------------------------------------------------------- [19:40:56] Jamie Gaskins(@jgaskins):Wow, nice! ---------------------------------------------------------------------------------------------------- ############################## [2016-01-10] ############################## [22:41:47] Jamie Gaskins(@jgaskins):Here's a list of things I've been working on for Clearwater, trying to pave the way to 1.0: http://jgaskins.org/blog/2016/01/10/clearwater-pending-projects ---------------------------------------------------------------------------------------------------- [22:42:02] Jamie Gaskins(@jgaskins):And here's where we'll be tracking the roadmap to 1.0: https://github.com/clearwater-rb/clearwater/issues/33 ---------------------------------------------------------------------------------------------------- [22:43:39] Jamie Gaskins(@jgaskins):@jaredcwhite: ^^ Any chance we could get this into the next newsletter? ---------------------------------------------------------------------------------------------------- ############################## [2016-01-11] ############################## [18:03:45] Forrest Chang(@fkchang):@jgaskins pretty slick, I look forward to seeing what comes of such ---------------------------------------------------------------------------------------------------- ############################## [2016-01-14] ############################## [18:40:50] Jared White(@jaredcwhite):@jgaskins Got both links in the newsletter :) ---------------------------------------------------------------------------------------------------- ############################## [2016-01-16] ############################## [01:10:39] Jamie Gaskins(@jgaskins):@jaredcwhite: Thanks! ---------------------------------------------------------------------------------------------------- ############################## [2016-01-24] ############################## [04:30:53] Jamie Gaskins(@jgaskins):https://twitter.com/rubygems/status/690974645319761920 ---------------------------------------------------------------------------------------------------- [04:31:16] Jamie Gaskins(@jgaskins):^^ Includes everything on the roadmap except server rendering ---------------------------------------------------------------------------------------------------- [04:32:36] Jamie Gaskins(@jgaskins):The trimmed-down JS payload with `bowser` instead of `opal-browser` is pretty huge in dev, especially in Rails apps where each asset is fetched individually. ---------------------------------------------------------------------------------------------------- ############################## [2016-01-25] ############################## [16:55:53] Adrian Madrid(@aemadrid):very cool ---------------------------------------------------------------------------------------------------- [17:24:38] Forrest Chang(@fkchang):@jgaskins good deal! ---------------------------------------------------------------------------------------------------- ############################## [2016-01-26] ############################## [00:07:29] Jamie Gaskins(@jgaskins):@LeoDaoTao You mean how we use arrays instead of blocks? ---------------------------------------------------------------------------------------------------- [00:08:04] Jamie Gaskins(@jgaskins):Thank you for the kind words, btw :-) ---------------------------------------------------------------------------------------------------- [00:08:19] LeoDaoTao(@LeoDaoTao):@jgaskins yeah ---------------------------------------------------------------------------------------------------- [00:08:25] LeoDaoTao(@LeoDaoTao):it looks less ruby that way ---------------------------------------------------------------------------------------------------- [00:09:49] LeoDaoTao(@LeoDaoTao):is there a performance difference? ---------------------------------------------------------------------------------------------------- [00:13:30] Jamie Gaskins(@jgaskins):Blocks don't represent an element's child nodes to me. Blocks in Ruby are anonymous functions, used either for their return value or for side effects, but in an N-ary tree (which is what a DOM tree is), any given node has an ordered collection of child nodes. An ordered collection is generally represented as an array or a linked list. ---------------------------------------------------------------------------------------------------- [00:14:25] Jamie Gaskins(@jgaskins):It can be done without a hit in performance. I was concerned it couldn't be, but it can. ---------------------------------------------------------------------------------------------------- [00:14:52] LeoDaoTao(@LeoDaoTao):I see your point, makes sense ---------------------------------------------------------------------------------------------------- [00:16:35] Jamie Gaskins(@jgaskins):@LeoDaoTao But that's the thing about Clearwater components: they provide a very small API outside the DSL. If someone wants a block syntax, all they have to do is provide the HTML tag-name methods that provide that DSL and `attr_accessor :router, :outlet`. That is all that's necessary for a component in Clearwater (and the `attr_accessor` methods are only for components serving as routing targets. ---------------------------------------------------------------------------------------------------- [00:17:59] LeoDaoTao(@LeoDaoTao):@jgaskins that sounds cool, will play with it for sure ---------------------------------------------------------------------------------------------------- [00:18:49] Jamie Gaskins(@jgaskins):@LeoDaoTao For example, this is a valid Clearwater component: ```ruby class Layout attr_accessor :router, :outlet def render VirtualDOM.node(:h1, nil, 'Hello World') end end ``` And if you're not using this as a routing target or app root component, you can omit the second line. :-) ---------------------------------------------------------------------------------------------------- [00:22:25] LeoDaoTao(@LeoDaoTao):@jgaskins sure looks cool I have about 30 internal apps to build that all use MaterialDesign, I'm thinking Clearwater for the front-end, just create all the components that are needed and re-use between apps. ---------------------------------------------------------------------------------------------------- [00:23:24] LeoDaoTao(@LeoDaoTao):@jgaskins on a fence between Clearwater and reactive.rb at this point, need to play with each to see which one I like better ---------------------------------------------------------------------------------------------------- [00:24:06] Jamie Gaskins(@jgaskins):@LeoDaoTao I've been thinking of doing something similar. I didn't have Material Design in mind, but some sort of Bootstrap-like starter-kit thing. I suppose they're not that different. ---------------------------------------------------------------------------------------------------- [00:30:16] LeoDaoTao(@LeoDaoTao):@jgaskins I guess if well though-out the components could be generic and just styled per requirement, will share when I create somthing that looks and works decent :-) ---------------------------------------------------------------------------------------------------- [00:37:13] Jamie Gaskins(@jgaskins):I'll let you know what I come up with, too :-) ---------------------------------------------------------------------------------------------------- [02:08:02] jiayp(@jiayp):Is there some one benched the clearwater's performance than react.rb?My project have a lot dom elements in one page. ---------------------------------------------------------------------------------------------------- [03:13:57] LeoDaoTao(@LeoDaoTao):@jiayp I’m going to make components with both react.rb & clearwater in the next two weeks to see which works better for me. I’ll let you know what I find out. Remind me if you will in about 2 weeks if I don’t get back to you ---------------------------------------------------------------------------------------------------- [04:29:42] Jamie Gaskins(@jgaskins):@jiayp @LeoDaoTao I haven't checked against React.rb, but I've checked against React.js and Clearwater is faster: https://www.reddit.com/r/ruby/comments/3v96p2/clearwater_ruby_on_the_front_end_outperforms ---------------------------------------------------------------------------------------------------- [04:29:43] Jamie Gaskins(@jgaskins):http://i.imgur.com/Yh3sKfn.gifv ---------------------------------------------------------------------------------------------------- [04:36:55] Jamie Gaskins(@jgaskins):Since React.rb runs on top of React.js, I'm pretty sure it won't be faster. It's not guaranteed to be slower, but it's pretty likely that it adds performance overhead. ---------------------------------------------------------------------------------------------------- [05:45:33] LeoDaoTao(@LeoDaoTao):@jgaskins @jiayp Just for the record I want to say that @catmando did hell of a good job on improving react.rb. I played with it a bit and it is very well done. I will use it in my projects that require react. #DeathToJS ---------------------------------------------------------------------------------------------------- [06:54:40] jiayp(@jiayp):@LeoDaoTao @jgaskins Thanks, I will try it. ---------------------------------------------------------------------------------------------------- [14:57:22] Jamie Gaskins(@jgaskins):@LeoDaoTao That wasn't in question. :-) I was only addressing performance. ---------------------------------------------------------------------------------------------------- [15:11:35] Kurtis Rainbolt-Greene(@krainboltgreene):@jgaskins I haven't done shit on cw, feel free to UN commitbit me. I won't have time to even maintain right now :( ---------------------------------------------------------------------------------------------------- [15:44:24] Jamie Gaskins(@jgaskins):@krainboltgreene It's all good. I know you maintain a lot of popular projects. If you don't think you'll be up for maintaining it in the future or you just need to reduce your scope right now, it's totally cool and we can go ahead and remove it, but you're more than welcome to it for as long as you want it. ---------------------------------------------------------------------------------------------------- [15:54:48] Kurtis Rainbolt-Greene(@krainboltgreene):I just don't want to give the false impression that I have much time right now :( ---------------------------------------------------------------------------------------------------- [15:55:03] Kurtis Rainbolt-Greene(@krainboltgreene):And also you've been doing so many amazing things with it ---------------------------------------------------------------------------------------------------- [16:01:34] Jamie Gaskins(@jgaskins):@krainboltgreene Thanks! :-) I don't have any expectations, so there's no false impression here, no obligation, just a welcome mat for if you _do_ want to work on it. ---------------------------------------------------------------------------------------------------- [17:16:49] Mitch VanDuyn(@catmando):@LeoDaoTao just for the record the hard stuff was done by @zetachang, @ajjahn, @loicboutet and others... I just did the fun stuff. ---------------------------------------------------------------------------------------------------- [17:21:55] Mitch VanDuyn(@catmando):As far as performance goes, I am sure that reactrb will be big fat and slow. I have a simple philosophy: There is a world wide developer shortage, not a world wide compute power shortage. The primary concern for any library should be to build apps quickly that work. That said we recently did a test on our app, against a big competitor. What we observed that is that for for the full order process the competitor loaded and ran about 50% longer than ours. There is a big advantage to structuring a large app as a set of smaller SPAs, and then using prerendering and caching to reduce initial load time. Have fun with your test, can't wait to see the results. ---------------------------------------------------------------------------------------------------- [17:22:27] Mitch VanDuyn(@catmando):FYI... I am reading this: http://teropa.info/blog/2015/09/10/full-stack-redux-tutorial.html and think it makes a great example that is different from the same old "todo app" ---------------------------------------------------------------------------------------------------- [18:36:43] Jamie Gaskins(@jgaskins):@catmando I agree that the app functionality and development time are important, but client-side performance is _much_ different from server-side. I can't throw hardware at an app that runs on hardware and software I don't control. I doubt React.rb is too much slower than React.js in any way that isn't optimizable, though. I'd bet the deoptimizations in React.js offer more of a performance ceiling than the Ruby bindings do. ---------------------------------------------------------------------------------------------------- [00:06:51] LeoDaoTao(@LeoDaoTao):@jgaskins Congrats on getting 1.0 betta1! Will start diving in this week for my projects :-) Have a question. Any reason why you use method calls in your dsl instead of blocks? What I mean by that is why this: ``` def render form({ onsubmit: method(:handle_submit), [ # Notice the dom_ref attribute here input(type: :email, dom_ref: @email_field), ... ]) end ``` instead of ``` def render form do input type: :email, dom_ref: @email_field ... end end ``` ---------------------------------------------------------------------------------------------------- ############################## [2016-02-01] ############################## [04:26:10] Jamie Gaskins(@jgaskins):I've added a PR to Grand Central to simplify dispatching actions in response to UI events (https://github.com/clearwater-rb/grand_central/pull/2). Comments are welcome. ---------------------------------------------------------------------------------------------------- ############################## [2016-02-13] ############################## [20:47:31] LeoDaoTao(@LeoDaoTao):@jgaskins are there any Clearwater SPA out in the wild? You mentinon in one of your posts that you use Clearwater for production work. Is that something you can share? ---------------------------------------------------------------------------------------------------- ############################## [2016-02-14] ############################## [01:42:03] Jamie Gaskins(@jgaskins):@LeoDaoTao Unfortunately our Clearwater apps at work are internal. I'm working on getting some consumer-facing stuff working with it, but our consumer-facing web app has changed very little in the past year so it's still running our old Backbone code. ---------------------------------------------------------------------------------------------------- [01:43:41] LeoDaoTao(@LeoDaoTao):@jgaskins understood :-) I know how that works. All the projects I want to try Clearwater for are internal as well :-) ---------------------------------------------------------------------------------------------------- [01:45:52] Jamie Gaskins(@jgaskins):@LeoDaoTao I might be able to replace one of the consumer-facing apps with a Clearwater port. I've got the code written and ready to go, I just need to make sure the team's okay with it. :-) The downside is that it's a real-time delivery tracker, so it's not something you'd be able to see unless you place an order. :-) ---------------------------------------------------------------------------------------------------- [01:46:57] LeoDaoTao(@LeoDaoTao):@jgaskins Still it would be cool to see the source :-) ---------------------------------------------------------------------------------------------------- [01:49:38] Jamie Gaskins(@jgaskins):@LeoDaoTao That I might be able to do. I'll see if I can get approval for that. Before we were acquired by Groupon it wasn't a big deal (one of my coworkers showed off some of our React code at RubyNation), but now that we're enterprise, they've been filing patent applications for a lot of stuff we built and it's a lot less simple. ---------------------------------------------------------------------------------------------------- [01:50:30] LeoDaoTao(@LeoDaoTao):@jgaskins good luck with the red tape ---------------------------------------------------------------------------------------------------- [01:51:18] Jamie Gaskins(@jgaskins):@LeoDaoTao I've also been wanting to do more screencasts. I did one that showed getting started with Clearwater and Rails, but every time I start on another one I hate the way it looks or sounds or whatever and I scrap it. :-) ---------------------------------------------------------------------------------------------------- [01:52:07] LeoDaoTao(@LeoDaoTao):@jgaskins never done a screncast but I imagine I would feel the same :-) ---------------------------------------------------------------------------------------------------- [01:52:26] LeoDaoTao(@LeoDaoTao):@jgaskins would like to see even a raw screencast ---------------------------------------------------------------------------------------------------- [01:54:46] Jamie Gaskins(@jgaskins):@LeoDaoTao That'll probably be what it is. The hardest part there is getting some time when the house is quiet. :-) ---------------------------------------------------------------------------------------------------- [01:55:53] Jamie Gaskins(@jgaskins):I also need to stop going off on tangents about how or why something works the way it does and just present the information needed. ---------------------------------------------------------------------------------------------------- [01:55:58] LeoDaoTao(@LeoDaoTao):@jgaskins would not mind hiring you for an hour or two to walk me through a rails-clearwater sample app setup, would save me a lot of time figuring it out ---------------------------------------------------------------------------------------------------- [01:56:02] Jamie Gaskins(@jgaskins):That's another problem I have while recording them. ---------------------------------------------------------------------------------------------------- [01:56:40] LeoDaoTao(@LeoDaoTao):@jgaskins I think making good screencasts is a skill, I’m sure I don’t have it :-) ---------------------------------------------------------------------------------------------------- [01:56:44] Jamie Gaskins(@jgaskins):lol ---------------------------------------------------------------------------------------------------- [01:56:47] Jamie Gaskins(@jgaskins):Neither do I ---------------------------------------------------------------------------------------------------- [01:57:53] Jamie Gaskins(@jgaskins):I really wish I knew someone who was interested in the project who was great at talking to people about things. Basically we need an evangelist or two. :-) ---------------------------------------------------------------------------------------------------- [01:58:14] LeoDaoTao(@LeoDaoTao):that sure would help ---------------------------------------------------------------------------------------------------- [01:58:21] Jamie Gaskins(@jgaskins):@LeoDaoTao But nah, no need to hire me. I'm happy to pair on something some time. ---------------------------------------------------------------------------------------------------- [01:58:39] LeoDaoTao(@LeoDaoTao):@jgaskins that would be cool!!! ---------------------------------------------------------------------------------------------------- [01:59:22] LeoDaoTao(@LeoDaoTao):@jgaskins I’ll play a bit with Clearwater myself first to get the basic ideas worked out ---------------------------------------------------------------------------------------------------- [02:00:15] LeoDaoTao(@LeoDaoTao):@jgaskins esentially I would like Clearwater to run as a SPA with Rails+Grape as the API on the backend ---------------------------------------------------------------------------------------------------- [02:00:38] Jamie Gaskins(@jgaskins):@LeoDaoTao All good. This week's pretty packed for me. I'm coaching at a RailsGirls-style event next weekend and the coaching training is this week after work. :-) ---------------------------------------------------------------------------------------------------- [02:01:25] Jamie Gaskins(@jgaskins):@LeoDaoTao Nice, I haven't used Grape, but it integrates really well with Rails with `opal-rails` and I've also had great success with Roda. ---------------------------------------------------------------------------------------------------- [02:01:38] LeoDaoTao(@LeoDaoTao):@jgaskins will be in touch, I’m sure I’ll have some questions while I figure out basics of Clearwater, which I may be able to start to do mid next week. ---------------------------------------------------------------------------------------------------- [02:01:57] LeoDaoTao(@LeoDaoTao):@jgaskins Roda is on my ToDo list as well ---------------------------------------------------------------------------------------------------- ############################## [2016-02-17] ############################## [14:06:33] Jamie Gaskins(@jgaskins):@/all Not sure if you've seen this yet, but I was invited onto the Ruby Rogues podcast to talk about Clearwater :-D https://devchat.tv/ruby-rogues/246-rr-clearwater-with-jamie-gaskins ---------------------------------------------------------------------------------------------------- [14:07:06] Jamie Gaskins(@jgaskins):@jaredcwhite ^^ Might be good for the newsletter. :-) ---------------------------------------------------------------------------------------------------- [21:49:27] Forrest Chang(@fkchang):@jgaskins cool beans, I saw reference to such on twitter, congrats ---------------------------------------------------------------------------------------------------- [21:50:34] Forrest Chang(@fkchang):looks like u've wandered into the right circles. Feels like to me opal is sort of black listed in various parts of the Ruby community, volt notwithstanding ---------------------------------------------------------------------------------------------------- ############################## [2016-02-19] ############################## [03:46:34] LeoDaoTao(@LeoDaoTao):@jgaskins listend to the RR podcast today. Good work man! ---------------------------------------------------------------------------------------------------- [20:28:09] Brendan Grainger(@rainkinz):Hi, sorry. Maybe dumb question, but I am trying to get the example app from: https://github.com/clearwater-rb/clearwater working and navigating to http://localhost:3000/#/articles doesn’t show any articles (I am assuming the # here). Any ideas? ---------------------------------------------------------------------------------------------------- [20:28:43] Brendan Grainger(@rainkinz):Also tried http://localhost:3000/articles, but rails doesn’t like that route ---------------------------------------------------------------------------------------------------- [20:29:10] Brendan Grainger(@rainkinz):This is my routes.rb just in case: ``` Rails.application.routes.draw do root to: 'home#index’ end ``` ---------------------------------------------------------------------------------------------------- [21:38:33] Jamie Gaskins(@jgaskins):@rainkinz You need to tell Rails to add a catch-all route to point to the same controller and action: ```ruby Rails.application.routes.draw do root to: 'home#index' get '*all' => 'home#index' end ``` ---------------------------------------------------------------------------------------------------- [21:39:26] Jamie Gaskins(@jgaskins):That will route all `GET` requests that haven't matched any previous routes to your Clearwater app. ---------------------------------------------------------------------------------------------------- [21:40:32] Jamie Gaskins(@jgaskins):@rainkinz Also, Clearwater's router doesn't use the `#`. It handles the URL's actual path. :-) ---------------------------------------------------------------------------------------------------- [21:50:49] Brendan Grainger(@rainkinz):@jgaskins thanks. Working now. Was following along with clearwater before, but great hearing you on RR the other day ---------------------------------------------------------------------------------------------------- ############################## [2016-02-20] ############################## [04:15:02] Jamie Gaskins(@jgaskins):@rainkinz Awesome, thanks! :-) ---------------------------------------------------------------------------------------------------- ############################## [2016-02-21] ############################## [20:25:34] Jamie Gaskins(@jgaskins):@fkchang I just realized I never responded to your message. I thought I did. I must've closed the browser before sending it. I find a lot of draft emails where I've forgotten to hit send, too, so I do this a lot. :-) There are a few reasons why people may not want to use Opal. So far, the ones I've seen the most are fear of transpilers (the "just use JS!" crowd that also hates CoffeeScript but for some reason loves ES6 transpilers) and Elia/meh. I can't do anything about the second one, but I'm trying to show that the first is not something to worry about. I'd like to blog about it, but I've got a lot of other drafts written, as well. :-) I kind of glossed over it during the RR episode where Coraline asked about debugging. I could've gone into a lot more detail there (and really wanted to), but I was fairly nervous and rambled/stuttered a lot (most of which got edited out, thankfully). ---------------------------------------------------------------------------------------------------- ############################## [2016-02-22] ############################## [23:36:41] Colin Gunn(@balmoral):@jgaskins trying to get clearwater going in a volt test app and getting a gem dependency problem with 1.0.0.beta2: ``` Bundler could not find compatible versions for gem "opal": In Gemfile: volt (= 0.9.6) ruby depends on opal (< 0.9, >= 0.8.0) ruby opal-rspec (~> 0.4.2) ruby depends on opal (< 0.9, >= 0.7.0) ruby clearwater (= 1.0.0.beta2) ruby depends on opal (~> 0.7) ruby clearwater (= 1.0.0.beta2) ruby depends on bowser (~> 0.1.2) ruby depends on opal (~> 0.9.0) ruby ``` ---------------------------------------------------------------------------------------------------- ############################## [2016-02-23] ############################## [00:12:21] Jamie Gaskins(@jgaskins):@balmoral Looks like Volt isn't compatible with Opal 0.9, but Bowser (the DOM abstraction in Clearwater 1.0 beta) depends on it. I don't know if Bowser would work on Opal 0.8 (0.9 was out when I wrote it), but it might. ---------------------------------------------------------------------------------------------------- [00:13:58] Colin Gunn(@balmoral):thanks @jgaskins. Is it worth trying an earlier version of clearwater for now? ---------------------------------------------------------------------------------------------------- [00:15:05] Jamie Gaskins(@jgaskins):@balmoral I haven't tried Volt+Clearwater in the same app before. I wonder if they'll step on each other. Clearwater assumes it has sole ownership of the DOM node you pass into `Clearwater::Application.new` and all of its children. Volt may assume similar. ---------------------------------------------------------------------------------------------------- [00:16:23] Jamie Gaskins(@jgaskins):@balmoral Sure, you can give it a shot. The difference between 0.3.1 and 1.0.0.beta is primarily the DOM abstraction (0.3.1 uses `opal-browser`, 1.0.0.beta uses `bowser`). I only switched it up because Clearwater uses so little of a DOM library. :-) ---------------------------------------------------------------------------------------------------- [00:23:25] Colin Gunn(@balmoral):@jgaskins I think so long as I can pass the root node of the volt view to clearwater, all will be ok - I’ve been experimenting with opal-browser and it works fine. I’ve had speed issues on large pages using volt’s reactive views and want to try getting a bit closer to the DOM and managing DOM updates more directly. Really like how clean (clear :smile:) the clearwater interface to the DOM elements is. I was getting tied up in knots with paggio/browser working out whether/how sub-components should be treated in blocks, etc. Keeping it simple with explicit arrays is great :+1: ---------------------------------------------------------------------------------------------------- [00:33:25] Jamie Gaskins(@jgaskins):@balmoral Arrays as content makes my heart sing when it comes to debugging. Being able to use `Enumerable` methods on my components' content has made me so glad to have stuck with that choice. I'm porting over one of our React apps at work (an order dashboard for support personnel to use) to Clearwater+Grand Central (React is banned at Groupon for the patent clause in its license) and this is basically how a lot of things look: ```ruby class OrderList include Clearwater::Component def initialize orders @orders = orders end def render ul(@orders.map { |order| li({ key: order.id }, OrderEntry.new(order)) }) end end ``` ---------------------------------------------------------------------------------------------------- [00:36:10] Jamie Gaskins(@jgaskins):The reason to wrap the `OrderEntry.new` call inside an `li` is something I need to document, but basically it's so that if the `OrderEntry` component uses caching, those cached renders are reused even if the array is in a different order or has insertions/deletions in the middle. ---------------------------------------------------------------------------------------------------- [00:39:14] Colin Gunn(@balmoral):Couldn’t agree more about arrays :smile: What I’ll be wanting to do is track changes in the model via computations (watches) and re-render the related components. I’m sure to need some guidance on this. ---------------------------------------------------------------------------------------------------- [00:43:09] Jamie Gaskins(@jgaskins):@balmoral I'm happy to chat about it whenever. I'm still a little fuzzy on how Volt's watched computations work (I looked into them a while back, but that's a bit of magic that stayed magic to me ;-) ), but I'll help however I can on the Clearwater side. ---------------------------------------------------------------------------------------------------- [01:01:46] Colin Gunn(@balmoral):@jgaskins basically the logic will be something like this: ``` def watch_order(order) -> { order.total_cost = order.quantity * order.unit_cost render_order(order) }.watch! end ``` Whenever (wherever/ however) the order’s quantity or unit_cost is changed, the code inside the watched proc is executed, causing #render_order to be executed. The related order entry component would have to be found and rendered. Based on your example above, would something like this work: ``` def render_order(order) order_entry = DOM[order.id] # or however clearwater does this order_entry.render if order_entry end ``` ---------------------------------------------------------------------------------------------------- [01:18:25] Jamie Gaskins(@jgaskins):@balmoral The great thing about Clearwater is that you can just call `app.render` and it'll just rerender with the new state. So if you modify `store._orders` (I think that's how Volt does it), you can pass that array to your Clearwater component: ```ruby @orders_app = Clearwater::Application.new( component: OrdersList.new(store._orders), element: Bowser.document['#orders-list'], # in Clearwater < 1.0.0.beta: $document['#orders-list'] ) # ... def render_order(order) @orders_app.render end ``` ---------------------------------------------------------------------------------------------------- [01:22:55] Jamie Gaskins(@jgaskins):One thing to keep in mind is that if the `#orders-list` element gets removed from the DOM, you need to re-instantiate the Clearwater app on the next render. Because you pass in a live DOM element (rather than a CSS selector) as the element, it renders to that DOM element rather than one with the same CSS selector. If it's removed from the DOM and a new one is rendered, you'll end up rendering to an element that isn't on the screen. :-) ---------------------------------------------------------------------------------------------------- [05:36:01] Colin Gunn(@balmoral):@jgaskins isn’t there potential for very large overhead if the whole application is rerendered (especially if the rendering is dependent on database retrieval). Or is the idea to break the page up into smaller applications to modularise view updates? (The word application suggests something bigger than a group of elements/components). BTW got some Clearwater happening in Volt :smile: ---------------------------------------------------------------------------------------------------- [15:19:09] Mitch VanDuyn(@catmando):@balmoral - FYI if you ever want to pick my brain how this gets handled in reactive-record let me know... ---------------------------------------------------------------------------------------------------- [20:11:50] Colin Gunn(@balmoral):Thanks @catmando. So much to explore. ---------------------------------------------------------------------------------------------------- ############################## [2016-02-24] ############################## [03:45:32] Jamie Gaskins(@jgaskins):@balmoral When you rerender the entire application, it doesn't rerender the entire thing to the DOM. It "renders" to a data structure (the virtual DOM), finds the changes since the last render (to another virtual-DOM data structure), then applies those changes to the screen-rendered DOM. Same concept as in React rendering, but uses a different abstraction (the `Clearwater::Application`). There's more optimization to be made using `Clearwater::CachedRender`. For example, in this Clearwater app: ```ruby class RandomThing include Clearwater::Component include Clearwater::CachedRender def render div(rand.to_s) end end class Layout include Clearwater::Component def render div([ RandomThing.new, # Pro-tip: Component#call re-renders all mounted Clearwater apps button({ onclick: proc { call } }, 'Re-render'), ]) end end Clearwater::Application.new(component: Layout.new).call ``` Clicking the `Re-render` button will never show anything different than the first random number shown. Remove the line that says `include Clearwater::CachedRender` and it will render a new one every time. Adding this method will perform random cache invalidation (sometimes it will use the cache, sometimes not): ```ruby class RandomThing # ... # previous = the component instance that was used on the last render def should_render? previous rand < 0.5 end end ``` ---------------------------------------------------------------------------------------------------- [03:46:51] Jamie Gaskins(@jgaskins):@balmoral I'm not sure how well versed you are in virtual DOMs and Clearwater, so I went for the full explanation. My apologies if you already knew about all that. ---------------------------------------------------------------------------------------------------- [03:53:46] Jamie Gaskins(@jgaskins):Regarding database retrieval, you can indeed use up way too much memory on the client if you try to load everything. It's difficult to know how much is too much in development, so I recommend testing with a production-like load. The good news is, though, that in our order dashboard, we fit all in-progress orders and their drivers across 30 markets in 30 MB of RAM. ---------------------------------------------------------------------------------------------------- [03:53:56] Jamie Gaskins(@jgaskins):[![Screen Shot 2016-02-23 at 2.34.14 PM copy.png](https://files.gitter.im/clearwater-rb/clearwater/HFBY/thumb/Screen-Shot-2016-02-23-at-2.34.14-PM-copy.png)](https://files.gitter.im/clearwater-rb/clearwater/HFBY/Screen-Shot-2016-02-23-at-2.34.14-PM-copy.png) ---------------------------------------------------------------------------------------------------- [04:08:59] Jamie Gaskins(@jgaskins):That uses real-time updates (via [`opal-pusher`](https://github.com/jgaskins/opal-pusher)) with a lot of data coming in very quickly (every time a driver comes online/goes offline, updates their location, an order is dispatched or moved between delivery states, etc). It's all stored in an immutable [`grand_central`](https://github.com/clearwater-rb/grand_central) store (so each update generates a completely new object, replacing the previous one in the store). ---------------------------------------------------------------------------------------------------- [04:11:20] Jamie Gaskins(@jgaskins):Basically, what I'm saying is that you can overdo it with data, but even what I'd consider more data than I can process with my eyes can be loaded without overburdening the machine's RAM. :-) ---------------------------------------------------------------------------------------------------- ############################## [2016-02-25] ############################## [00:03:40] Colin Gunn(@balmoral):@jgaskins thanks for the detailed explanation. Much appreciated. I'm pretty sure I get the idea of the virtual DOM. But having used Volt for a while, I’m accustomed to changes in the model triggering partial renderings of dependent elements on the page (via bindings/computations), not a total rerendering of the (virtual) DOM. I’m wanting to stick with the Volt pattern and its built-in data syncing (no need for pusher or grand_central, since Volt does it all) and implement watches/computations on fields in the Volt model(s) which then trigger rerendering on the related DOM elements, i.e. binding specific model change states to associated component rendering. So I’m thinking CachedRender#should_render? might be the way to go to inhibit unnecessary renders (and thus unnecessary data retrieval for unchanged data). I’ve already made some good experimental progress. Forked Bowser and Clearwater to change Opal dependencies back to ~> 0.8.0, and all appears to be working nicely inside a Volt::ModelController. :smile: ---------------------------------------------------------------------------------------------------- [04:51:38] Jamie Gaskins(@jgaskins):Cool, I'd gladly accept PRs for that. ---------------------------------------------------------------------------------------------------- ############################## [2016-02-29] ############################## [20:55:27] Mitch VanDuyn(@catmando):@fkchang - missed the article?? ---------------------------------------------------------------------------------------------------- [21:14:31] Jamie Gaskins(@jgaskins):@catmando http://jgaskins.org/blog/2016/02/28/turbolinks-vs-the-virtual-dom ---------------------------------------------------------------------------------------------------- [21:17:19] Mitch VanDuyn(@catmando):@jgaskins been meaning to ask... given that clearwater virtual dom is faster, what are the chances we could adapt reactrb to use it? I would see this being on some kind of config switch... ---------------------------------------------------------------------------------------------------- [21:23:44] Mitch VanDuyn(@catmando):@jgaskins - Great Article! - how do you figure that clearwater is faster than react? This to me is a bit surprising given (I assume) that clearwater is written in Opal?? ---------------------------------------------------------------------------------------------------- [21:32:26] Jamie Gaskins(@jgaskins):@catmando I'm not sure how much work would be involved in making [`virtual-dom`](https://github.com/Matt-Esch/virtual-dom) a drop-in replacement for React.js, but I've been thinking about ways to do it in case someone wants to use them in a Clearwater app (the framework doesn't depend on components being `Clearwater::Component`s, just that they respond to `render` with vdom nodes). The hardest part would be getting the lifecycle hooks working, but `virtual-dom` does provide some [hooks](https://github.com/Matt-Esch/virtual-dom/blob/master/docs/hooks.md) you can use (which is how I implemented `Clearwater::DOMReference`) ---------------------------------------------------------------------------------------------------- [21:35:23] Mitch VanDuyn(@catmando):So there are a couple of motivations for this: ---------------------------------------------------------------------------------------------------- [21:35:30] Mitch VanDuyn(@catmando):1) speed ---------------------------------------------------------------------------------------------------- [21:35:42] Mitch VanDuyn(@catmando):2) simplification ---------------------------------------------------------------------------------------------------- [21:36:09] Jamie Gaskins(@jgaskins):@catmando Regarding performance, I made a post on Reddit about it a while back (https://www.reddit.com/r/ruby/comments/3v96p2/clearwater_ruby_on_the_front_end_outperforms/?) and included a screencast showing it running faster on the same app: https://youtu.be/vzir5gJX2Xw ---------------------------------------------------------------------------------------------------- [21:36:41] Jamie Gaskins(@jgaskins):And someone posted a gif showing the Chrome FPS gauge between the two apps: http://i.imgur.com/Yh3sKfn.gifv ---------------------------------------------------------------------------------------------------- [21:36:46] Mitch VanDuyn(@catmando):3) allowing prerendering to be done by server ruby (rather than in a js on the server) ---------------------------------------------------------------------------------------------------- [21:37:05] Jamie Gaskins(@jgaskins):It looks like the React version's been taken down. That's disappointing. ---------------------------------------------------------------------------------------------------- [21:38:02] Mitch VanDuyn(@catmando):and interesting ---------------------------------------------------------------------------------------------------- [21:38:25] Jamie Gaskins(@jgaskins):To be honest, the speed totally surprised me when I first benchmarked it. I had no idea it was as fast as it was. ---------------------------------------------------------------------------------------------------- [21:38:43] Mitch VanDuyn(@catmando):you are using that JS virtual dom library you mentioned? ---------------------------------------------------------------------------------------------------- [21:38:47] Jamie Gaskins(@jgaskins):Yep ---------------------------------------------------------------------------------------------------- [21:39:05] Jamie Gaskins(@jgaskins):That's what Clearwater runs under the hood. It provides what I've found to be a great blend of performance and features. ---------------------------------------------------------------------------------------------------- [21:39:13] Mitch VanDuyn(@catmando):and you react to some equivilent of state changes? ---------------------------------------------------------------------------------------------------- [21:39:26] Mitch VanDuyn(@catmando):and rerender? ---------------------------------------------------------------------------------------------------- [21:39:41] Jamie Gaskins(@jgaskins):It's not the fastest vdom library, but it's still plenty fast. ---------------------------------------------------------------------------------------------------- [21:42:45] Jamie Gaskins(@jgaskins):Clearwater components by default are simple Ruby objects. "State" is just instance variables. The DSL methods are pure functions and don't do anything but generate vdom nodes. Including the mixin used to add an `attributes` DSL method to the component class that would rerender whenever any of those attributes changed (they were just `attr_accessor`s that rerendered when you ran `self.foo = 'bar'`, but I decided I wanted to keep it as pure as possible and let people build on that. ---------------------------------------------------------------------------------------------------- [21:45:11] Mitch VanDuyn(@catmando):I wonder if that why react is slower? Could it be that they have hooks all over the place to handle state changes? I know by default react.js assumes components are NOT pure, so time a parent renders, all the children re-rerender as well. (react.rb assumes components are are FYI.) ---------------------------------------------------------------------------------------------------- [21:47:59] Jamie Gaskins(@jgaskins):A lot of it is that JSX sends a variable number of arguments to `React.createElement`, which makes the function too polymorphic and the VM will no longer optimize it. ---------------------------------------------------------------------------------------------------- [21:48:22] Jamie Gaskins(@jgaskins):Ugh, office internet looks like it's causing some of my messages not to go through ---------------------------------------------------------------------------------------------------- [21:48:41] Jamie Gaskins(@jgaskins):Trying again: If you run a React app through the Chrome profiler and then trigger a lot of renders, there are a lot of function deoptimizations in the VM, both in generating the vdom tree and in diffing/patching. We ran into this quite a bit. ---------------------------------------------------------------------------------------------------- [21:50:22] Mitch VanDuyn(@catmando):Well I think people like to hear fast... frankly I am not seeing speed as any kind of problem. We do have to be careful that prerendering works properly so that initial display time masks the relatively large application.js file coming after it. ---------------------------------------------------------------------------------------------------- [21:51:16] Jamie Gaskins(@jgaskins):Indeed. ---------------------------------------------------------------------------------------------------- [21:52:08] Mitch VanDuyn(@catmando):I am just not seeing any kind of react.js libraries taking off to the point that its really worth staying glued at the hip with react.js. It would be nice to offer an alternative that was pure ruby, and that could be prerendered directly in ruby on the server (rather than in a JS engine.) for us fast prerendering is far more important that actual update time on the client. ---------------------------------------------------------------------------------------------------- [21:55:29] Mitch VanDuyn(@catmando):Our other much bigger problem (and I would love it if I could get help on this from perhaps @balmoral who seems interested) is the generalized syncing of server db changes to all clients. its easy for trivial cases, but nobody to my knowledge has a general solution that will intelligently update scopes on clients. ---------------------------------------------------------------------------------------------------- [21:55:37] Mitch VanDuyn(@catmando):so much fun to be had :-) ---------------------------------------------------------------------------------------------------- [21:55:37] Jamie Gaskins(@jgaskins):I've noticed when it comes to front-end Ruby stuff that people seem to be primarily writing Ruby bindings to JS libraries, which is cool but I found it to be pretty liberating not to be tied to something like that. I could completely swap vdoms to something with similar features and you wouldn't even know. :-) ---------------------------------------------------------------------------------------------------- [21:56:47] Mitch VanDuyn(@catmando):I am glad you said that, because that is my intuition too. I somehow feel very boxed in by react.js as much as I love what it offers from a conceptual level. ---------------------------------------------------------------------------------------------------- [21:58:04] Jamie Gaskins(@jgaskins):Synchronizing server-side updates is something we do in our order dashboard. We just send out updates via Pusher, monitor those channels with [`opal-pusher`](https://github.com/jgaskins/opal-pusher) and update the models with [`grand_central`](https://github.com/clearwater-rb/grand_central) (you might use reactive-record). ---------------------------------------------------------------------------------------------------- [21:58:34] Mitch VanDuyn(@catmando):Sure basically the same here. ---------------------------------------------------------------------------------------------------- [21:58:51] Jamie Gaskins(@jgaskins):When I first started with the vdom approach with Clearwater (it used to inject HTML), I tried compiling the templates to React components. That was a lot harder than I thought it would be. :-) ---------------------------------------------------------------------------------------------------- [21:59:09] Jamie Gaskins(@jgaskins):Here's kinda how that went: http://jgaskins.org/blog/2015/04/06/clearwater-and-the-virtual-dom ---------------------------------------------------------------------------------------------------- [21:59:33] Mitch VanDuyn(@catmando):but what I want is to just have my existing active-record models work on the client, without any extra code. ---------------------------------------------------------------------------------------------------- [22:00:45] Jamie Gaskins(@jgaskins):Yeah, that'd still require some sort of server push. We haven't come up with anything better than sending JSON to Pusher yet. :-) ---------------------------------------------------------------------------------------------------- [22:00:47] Mitch VanDuyn(@catmando):That is the way reactive-record works now, EXCEPT for the case that client "A" does an update, that client "B" should know about. For this case we have to hand write case specific code to refresh the scopes that client "B" currently cares about. Ugh. ---------------------------------------------------------------------------------------------------- [22:02:41] Colin Gunn(@balmoral):@catmando @jgaskins can't go past volt for server side sync/push to clients. ---------------------------------------------------------------------------------------------------- [22:02:51] Mitch VanDuyn(@catmando):So for example if I to a `todo.complete = true; todo.save` on client A, and client B, is looking at `Todo.active` I expect client B to rerender with the shortened todo list. ---------------------------------------------------------------------------------------------------- [22:04:07] Mitch VanDuyn(@catmando):@balmoral I had a discussion with Ryan a while back, and while it works for trivial cases (as does reactive-record) the general case of complex scopes does not work, and while he has plans, it sounds quite complicated, and server intensive. ---------------------------------------------------------------------------------------------------- [22:04:57] Mitch VanDuyn(@catmando):He basically agreed its a hard problem that needs to get solved. ---------------------------------------------------------------------------------------------------- [22:06:03] Colin Gunn(@balmoral):@catmando fair enough. It's been good for the level I'm working at. ---------------------------------------------------------------------------------------------------- [22:06:49] Mitch VanDuyn(@catmando):No doubt! ---------------------------------------------------------------------------------------------------- [22:07:05] Colin Gunn(@balmoral):@jgaskins @catmando have just implemented a page in clearwater ---------------------------------------------------------------------------------------------------- [22:07:55] Colin Gunn(@balmoral):Which took 12 secs using volt html bindings - in Clearwater well under a second :smile: ---------------------------------------------------------------------------------------------------- [22:08:43] Jamie Gaskins(@jgaskins):@balmoral The fact that Volt does client/server sync by default is really cool. It means you're not trying to shoehorn it in later. I really like that. ---------------------------------------------------------------------------------------------------- [22:10:31] Jamie Gaskins(@jgaskins):@balmoral Nice! That's a huge performance improvement! ---------------------------------------------------------------------------------------------------- [22:11:05] Mitch VanDuyn(@catmando):@balmoral - I don't even get it... how complex is this page? ---------------------------------------------------------------------------------------------------- [23:02:22] Colin Gunn(@balmoral):@catmando @jgaskins the page was an order report - may a couple of hundred rows with 9 columns (no pagination). All the time was in the rendering (not data loading). There were a lot of Volt bindings {{ }}, both in the element content and attributes, which I suspect have a lot of overhead. The great thing about using Clearwater is that all my page generation code is now Ruby :smile: The {{ }} in html is useful as far as it goes -but for anything beyond simple the html + {{ ruby }} gets pretty unreadable quickly. And hard to debug. Now it’s all in Ruby, it’s readable, and it’s fast. There’s no time spent parsing html + {{ ruby }} to regnerate final html, nor what must be hundreds of computations waiting to be triggered. I really like the way @jgaskins has kept Clearwater clean and simple. It was trivial converting my Volt::ModelController to render the virtual DOM - even less code required in the controller than originally and virtually NO HTML! :smile: I’ve refactored a couple of things to fit into the Volt paradigm (a Clearwater `Application` pretty much corresponds to a Volt::ModelController) and I’ve allowed for more than one virtual DOM per controller (different root elements) to allow for targeted re-rendering as required. (To to this each Volt::VirtualDOM::Component (which includes Clearwater::Component) requires a dom id so it knows which dom to re-render - not sure if this is a good idea, but it works for now). I’ve been looking for something like this for a while. The less languages I have to work in the better, and I’m just loving that I can get all the view logic in pretty much one place using just Ruby (and css). ---------------------------------------------------------------------------------------------------- [19:06:10] Forrest Chang(@fkchang):@jgaskins good article on virtual dom vs turbolinks ---------------------------------------------------------------------------------------------------- ############################## [2016-03-01] ############################## [01:32:02] Jamie Gaskins(@jgaskins):@balmoral This is awesome! I'm absolutely thrilled that you can embed a Clearwater app inside a Volt app. I mean, I was _hoping_ it'd be flexible enough to do things like that, but I wasn't sure about it. :-) ---------------------------------------------------------------------------------------------------- [01:36:52] Colin Gunn(@balmoral):@jgaskins I’ve got a bit of app coding to get on with and also to test the wrap I’ve put around clearwater, but will get a gem out as soon as possible. On the Opal version side of things, I need cleartwater/bowser to be happy with ~> 0.8. Is there any chance that could be accommodated in the current beta? It all seems to work fine with 0.8.x ---------------------------------------------------------------------------------------------------- [01:37:44] Jamie Gaskins(@jgaskins):@balmoral I can go ahead and adjust the opal version requirement in bowser and release a new gem if you've confirmed it works. ---------------------------------------------------------------------------------------------------- [01:38:24] Colin Gunn(@balmoral):great - thanks. ---------------------------------------------------------------------------------------------------- [01:38:46] Jamie Gaskins(@jgaskins):Looks like there's a change in there I needed to push out anyway. One sec. ---------------------------------------------------------------------------------------------------- [01:39:08] Colin Gunn(@balmoral):no rush , whenver it suits ---------------------------------------------------------------------------------------------------- [01:44:40] Jamie Gaskins(@jgaskins):@balmoral Bowser 0.1.4 is up ---------------------------------------------------------------------------------------------------- [01:45:40] Colin Gunn(@balmoral):@jgaskins :+1: will try it out shortly ---------------------------------------------------------------------------------------------------- [04:34:12] Colin Gunn(@balmoral):@jgaskins have you had any problems with safari? I’ve got some straightforward stuff which works on chrome and firefox, but not on safari. Simple thing like text-align. Does clearwater or virtual dom do anything unusual in terms of creating intermediate divs or anything which might cause style attributes to be lost or overridden in divs which have more than one element? ---------------------------------------------------------------------------------------------------- [04:35:04] Jamie Gaskins(@jgaskins):@balmoral Nope. I use style attributes almost exclusively (because hashes are great and composable). How are you declaring it? ---------------------------------------------------------------------------------------------------- [04:39:58] Jamie Gaskins(@jgaskins):@balmoral Try this: ```ruby def render style = { text_align: :center, } div({ style: style }, [ h1('Hi'), ]) end ``` ---------------------------------------------------------------------------------------------------- [04:40:40] Colin Gunn(@balmoral):``` def quantity_column_attrs { class: quantity_column_width, style: "text-align: right; padding-left: 0.5em; padding-right: 0.5em; margin-top: 0.1em; margin-bottom: 0.1em" } end def customer_order_row_attrs(i, total: false) bg = total ? 'total-row-bg' : 'table-row-bg' alt_bg = 'table-row-alt-bg' { class: "row #{i % 2 == 0 ? bg : alt_bg} table-row-bottom-border", } end def customer_order_row(customer_order, i) div( customer_order_row_attrs(i), [ div(product_column_attrs, customer_order.name) ] + customer_order.quantities.map do |qty| div(quantity_column_attrs, qty) end ) end ``` experimental work in progress ---------------------------------------------------------------------------------------------------- [04:41:08] Jamie Gaskins(@jgaskins):Oooooooh, styles aren't strings. That's the problem. ---------------------------------------------------------------------------------------------------- [04:41:10] Jamie Gaskins(@jgaskins):They're hashes. ---------------------------------------------------------------------------------------------------- [04:41:17] Jamie Gaskins(@jgaskins):Snake-cased hashes. ---------------------------------------------------------------------------------------------------- [04:41:33] Colin Gunn(@balmoral):oops! ---------------------------------------------------------------------------------------------------- [04:42:13] Colin Gunn(@balmoral):old habits die hard ---------------------------------------------------------------------------------------------------- [04:42:38] Jamie Gaskins(@jgaskins):So it would be: ```ruby def quantity_column_attrs { class: quantity_column_width, style: { text_align: :right, padding_left: '0.5em', padding_right: '0.5em', margin_top: '0.1em', margin_bottom: '0.1em', }, } end ``` ---------------------------------------------------------------------------------------------------- [04:43:18] Colin Gunn(@balmoral):yep - got it. thanks :smile: ---------------------------------------------------------------------------------------------------- [04:43:22] Jamie Gaskins(@jgaskins)::-) ---------------------------------------------------------------------------------------------------- [04:45:16] Jamie Gaskins(@jgaskins):I believe you can do it JSON-style, as well, and use the actual CSS property name (instead of the snake-cased or camel-cased version): ```ruby def render style = { "text-align": "center" } # This is actual, valid Ruby code div({ style: style }, h1('Hi')) end ``` ---------------------------------------------------------------------------------------------------- [04:45:52] Jamie Gaskins(@jgaskins):But I don't know about browser support for that. I've confirmed it works in Safari and Chrome. ---------------------------------------------------------------------------------------------------- [04:46:33] Jamie Gaskins(@jgaskins):@balmoral Speaking of which, I'm surprised that Firefox and Chrome allow setting the `style` attribute to a string. I don't think that's in the JS DOM API standard. ---------------------------------------------------------------------------------------------------- [04:50:37] Colin Gunn(@balmoral):@jgaskins they seem to accept strings - enough to let me keep going the wrong way. My brain must be a little tired or distracted, because I remember now coming across the snake_case hash keys for style. Then I completely forgot! ---------------------------------------------------------------------------------------------------- [04:57:09] Jamie Gaskins(@jgaskins):@balmoral hehe I've been using them a lot rather than using CSS ids and classes. Being able to compose component styles in hashes is every bit as great as arrays for content: https://gist.github.com/jgaskins/439af129c2075f018f75 ---------------------------------------------------------------------------------------------------- [04:58:08] Jamie Gaskins(@jgaskins):Not quite CSS modules, but they're modules with styles in them. ;-) ---------------------------------------------------------------------------------------------------- [04:58:48] Jamie Gaskins(@jgaskins):And they don't step on each other because they're contained within the component. ---------------------------------------------------------------------------------------------------- [04:59:48] Colin Gunn(@balmoral):but easy enough to set up app wide style ‘sheets’ (modules) if desired. I like it :smile: ---------------------------------------------------------------------------------------------------- [05:02:42] Jamie Gaskins(@jgaskins):I've done the app-wide version, too. It's really interesting. I think functions like `side_by_side` that are more generally useful (I use that one a lot) are really good for that so you don't have to duplicate it. You can even `include` a global stylesheet module into that component-scoped one so you're still only using component-scoped styles, but you don't have to duplicate that style over and over. ---------------------------------------------------------------------------------------------------- [05:09:42] Colin Gunn(@balmoral):I like yor MasterDetailComponent too. It demonstrates how view patterns can be abstracted and reused easily. Gotta say I’m really looking forward to going further with all of this. You’ve provided a very clean, relatively simple solution to a typically frustrating and tedious part of coding web pages. ---------------------------------------------------------------------------------------------------- [05:12:22] Colin Gunn(@balmoral):so just added a github star! ---------------------------------------------------------------------------------------------------- [05:14:22] Jamie Gaskins(@jgaskins):Thanks, I've had a blast doing it! Every Clearwater app I've worked on has been a lot of fun to build — everything from the toy apps to the ones we're using in production. I'm working on building up a set of components I'll probably use a lot. If I find them to be generally usable enough, I may pack them up into a gem. The great part is that you can require them individually, so your JS payload stays small. ---------------------------------------------------------------------------------------------------- ############################## [2016-03-03] ############################## [02:36:44] jiayp(@jiayp):Is there some Bootstrap wapper for clearwater? ---------------------------------------------------------------------------------------------------- [06:58:26] jiayp(@jiayp):Is there some thing in Clearwater like reactjs's after_mount? ---------------------------------------------------------------------------------------------------- [11:56:45] jiayp(@jiayp):@jgaskins Component.call will render all app?https://github.com/clearwater-rb/clearwater/blob/master/opal/clearwater/component.rb#L197-L199 ---------------------------------------------------------------------------------------------------- [11:57:15] jiayp(@jiayp):Is there a way just rerender one component? ---------------------------------------------------------------------------------------------------- [18:50:30] Jamie Gaskins(@jgaskins):@jiayp Yes, it renders all mounted Clearwater apps (usually you'll only have 1, but you aren't limited to that). Is there a reason you want to render just a single component? ---------------------------------------------------------------------------------------------------- [18:50:33] Jamie Gaskins(@jgaskins):@jiayp No Bootstrap wrapper yet, no, but I've been thinking of coming up with a set of generally useful components like that. ---------------------------------------------------------------------------------------------------- [19:53:05] Forrest Chang(@fkchang):@jgaskins congrats on getting into Ruby Weekly, hard to see opal related content actually get accepted there ---------------------------------------------------------------------------------------------------- [20:00:13] Jamie Gaskins(@jgaskins):@fkchang Thanks! Maybe it's because I don't specifically mention Opal anywhere. ---------------------------------------------------------------------------------------------------- [22:16:45] Forrest Chang(@fkchang):could be, maybe I should try that ---------------------------------------------------------------------------------------------------- [22:25:07] Mitch VanDuyn(@catmando):@fkchang @jgaskins that is what I have been doing... for one thing it seems to help make the point that its just ruby, which Opal really is for all practical purposes. ---------------------------------------------------------------------------------------------------- [23:18:50] Jamie Gaskins(@jgaskins):I actually didn't know my blog post was in Ruby Weekly until a friend tweeted about it. :-) ---------------------------------------------------------------------------------------------------- ############################## [2016-03-04] ############################## [02:09:12] Jamie Gaskins(@jgaskins):@jiayp Here's how I would render that (guessing on a few things): https://gist.github.com/jgaskins/489ef7abeeaac91f6658 ---------------------------------------------------------------------------------------------------- [02:10:09] Jamie Gaskins(@jgaskins):The `Clearwater::CachedRender` mixin checks the `should_render?` method to determine whether or not it should re-render or use the previous rendered version. ---------------------------------------------------------------------------------------------------- [02:11:53] jiayp(@jiayp):@jgaskins And every cell have a Input, the value you inputed may cause others Task change. ---------------------------------------------------------------------------------------------------- [02:12:33] Jamie Gaskins(@jgaskins):By default, `should_render?` returns false (always reuse the cached version). You just need to compare it to the previous rendered instance of that component to determine whether it needs to re-render. For the task, you check whether it's rendering the same task as the previous component. For the list, you check whether the array is the same. For the chart, you might check the tasks array and any other metadata. ---------------------------------------------------------------------------------------------------- [02:13:42] jiayp(@jiayp):@jgaskins Thanks,I will try it. ---------------------------------------------------------------------------------------------------- [02:14:41] Jamie Gaskins(@jgaskins):One thing to note is that I used `.equal?` to compare the models in `should_render?`. That compares object identity, which is super fast, but assumes you're using immutable models. You may need different cache invalidation. ---------------------------------------------------------------------------------------------------- [02:16:39] jiayp(@jiayp):@jgaskins So I will call Component.call when I need rerender? Or some thing else? ---------------------------------------------------------------------------------------------------- [02:17:32] Jamie Gaskins(@jgaskins):@jiayp How are you managing your app state? ---------------------------------------------------------------------------------------------------- [02:17:48] Jamie Gaskins(@jgaskins):Are you using `grand_central`? ---------------------------------------------------------------------------------------------------- [02:19:21] jiayp(@jiayp):@jgaskins No, I just try to import Clearwater,I just want use the View/Component now.And maybe the others after. ---------------------------------------------------------------------------------------------------- [02:20:14] Jamie Gaskins(@jgaskins):@jiayp That's totally fine. :-) So you're storing the app state in components or in some kind of repository objects? ---------------------------------------------------------------------------------------------------- [02:22:07] jiayp(@jiayp):@jgaskins I have the some pure ruby object like Project, Task. ---------------------------------------------------------------------------------------------------- [02:22:42] jiayp(@jiayp):Thay store the state ---------------------------------------------------------------------------------------------------- [02:22:58] Jamie Gaskins(@jgaskins):The reason I ask is that if you're using some sort of repository objects to store your app state, you can have them rerender your app whenever you change state through them. Like this: ```ruby class TaskRepository def initialize(app) @app = app end # ... def update(model, new_attributes) model.update(new_attributes) @app.render model end end ``` ---------------------------------------------------------------------------------------------------- [02:24:37] jiayp(@jiayp):@jgaskins This is helpful, my Project should do this. thanks. ---------------------------------------------------------------------------------------------------- [02:24:50] Jamie Gaskins(@jgaskins):@jiayp Right, but I mean, where do those models get stored? Is the canonical app state just stored in components? It's okay if it is, I'm just trying to figure out how best to do it for your setup :-) ---------------------------------------------------------------------------------------------------- [02:25:04] Jamie Gaskins(@jgaskins):It changes things a bit if you're using repository objects vs storing state in components. :-) ---------------------------------------------------------------------------------------------------- [02:41:03] Jamie Gaskins(@jgaskins):If you're storing the app state within your components, then yes, you'll need to call `Component#call` (you don't have to do `Clearwater::Component.call` if you include the module as a mixin). ---------------------------------------------------------------------------------------------------- [18:58:28] Jamie Gaskins(@jgaskins):I really like all the buzz Clearwater has been getting lately. It seems like I've been talking to at least 1-2 people a day about it. ---------------------------------------------------------------------------------------------------- [18:59:10] Jamie Gaskins(@jgaskins):Apparently, people like being told they can write actual Ruby on the front end with performance that surpasses React and Turbolinks. ;-) ---------------------------------------------------------------------------------------------------- [19:25:17] Forrest Chang(@fkchang):@jgaskins looks like you are getting good press, hopefully u'll be able to bring some good attention to Opal and it's possibilities - something I've tried for years to mixed results, congrats ---------------------------------------------------------------------------------------------------- [01:31:32] jiayp(@jiayp):@jgaskins I have a complex component that contains many html element,I want to update a part of it when the related model changed. ---------------------------------------------------------------------------------------------------- [01:54:05] Jamie Gaskins(@jgaskins):@jiayp What's wrong with rendering all of it? ---------------------------------------------------------------------------------------------------- [01:59:01] Jamie Gaskins(@jgaskins):@jiayp This is an honest question. If you've run benchmarks and your app is slow while rendering everything, maybe there's something else we can figure out for your use case. But our real-time order dashboard at work renders at 60fps in Clearwater with almost 2000 active orders and 1000 drivers online to deliver them. Rendering top-down is plenty fast. :-) ---------------------------------------------------------------------------------------------------- [02:02:51] jiayp(@jiayp):@jgaskins I work on a gantt chart with grid on left.There maybe thousands of tasks in it. ---------------------------------------------------------------------------------------------------- [02:03:46] Jamie Gaskins(@jgaskins):@jiayp So maybe a `GanttChart` component with a `TaskList` component inside? ---------------------------------------------------------------------------------------------------- [02:06:41] jiayp(@jiayp):@jgaskins Yes,and Task components in it. ---------------------------------------------------------------------------------------------------- ############################## [2016-03-05] ############################## [01:35:24] jiayp(@jiayp):@jgaskins I have some problem when using Clearwater and JQuery Spliter.I use JQuery Spilter to add the spliter after my Clearwater components rendered.After this when I update the model and rerender the whole app, the spliter's right panel is do not update. I debuged it and found the spliter add a
in the dom and cause the virtualDom.patch can't find the actual node after the added
and can't patch it . ---------------------------------------------------------------------------------------------------- [01:39:36] jiayp(@jiayp):Is there any suggest? @jgaskins ---------------------------------------------------------------------------------------------------- [02:58:50] Jamie Gaskins(@jgaskins):@jiayp When the virtual DOM does its diffing/patching cycle, it's comparing the previous virtual DOM, not what's actually rendered to the DOM. So if you modify the DOM after it's been rendered, the virtual DOM will not know what to do with it. It needs to own all descendant nodes. ---------------------------------------------------------------------------------------------------- [03:14:57] Jamie Gaskins(@jgaskins):@jiayp There is one exception: the `BlackBoxNode`. It tells the virtual DOM that it doesn't own this node or any of its child nodes. I've mainly been using it to render Google Maps since I do a lot of them. Here's an idea of how we do real-time delivery tracking: ```ruby require 'clearwater/black_box_node' require 'google_maps' class DeliveryMap include Clearwater::BlackBoxNode include GoogleMaps attr_reader :map, :driver_marker, :restaurant_marker, :customer_marker def initialize(driver, delivery) @driver = driver @delivery = delivery end # Instead of `render`, you use `node`. def node Clearwater::Component.div(width: '600px', height: '600px') end def mount(node) @map = Map.new(node, center: LatLng.new(0, 0), zoom: 13) @driver_marker = Marker.new(map: @map, position: driver.location, icon: driver.marker_url) @restaurant_marker = Marker.new(map: @map, position: delivery.restaurant_location, icon: RESTAURANT_MARKER_URL) @customer_marker = Marker.new(map: @map, position: delivery.customer_location, icon: CUSTOMER_MARKER_URL) end def update(previous, node) @driver_marker = previous.driver_marker @restaurant_marker = previous.restaurant_marker @customer_marker = previous.customer_marker # Update driver's location. The others are static. driver_marker.position = driver.location end end ``` ---------------------------------------------------------------------------------------------------- [03:37:00] jiayp(@jiayp):My situation like this: ```` div({class: 'container'}, [div({class: left}), div({class:right})]) ```` `left` and `right` is normal Clearwator Component. And `container` will be inserted a `
` between `left` and `right`. If `container` use BlackBoxNode, the `left` and `right` will still auto diff and patch? ---------------------------------------------------------------------------------------------------- [04:16:23] Jamie Gaskins(@jgaskins):@jiayp They won't be able to regardless of whether you use `BlackBoxNode`. If you want auto diffing and patching, you can't modify the DOM after it's rendered. ---------------------------------------------------------------------------------------------------- [04:17:22] Jamie Gaskins(@jgaskins):You have to either declare _all_ of the DOM nodes you want in the virtual DOM or you have to handle updating the DOM node yourself. ---------------------------------------------------------------------------------------------------- [04:18:19] Jamie Gaskins(@jgaskins):If you modify the DOM on your own, the diff won't know about it because it doesn't diff against rendered DOM. That's too slow. ---------------------------------------------------------------------------------------------------- [04:18:32] Jamie Gaskins(@jgaskins):It has to diff against virtual DOM nodes instead. ---------------------------------------------------------------------------------------------------- [04:18:39] Jamie Gaskins(@jgaskins):… which aren't modified by your jQuery plugin ---------------------------------------------------------------------------------------------------- [05:46:02] jiayp(@jiayp):@jgaskins Yes, I modify the jQuery plugin and handle the html element myself. thanks. ---------------------------------------------------------------------------------------------------- ############################## [2016-03-07] ############################## [05:37:41] jiayp(@jiayp):@jgaskins How should I handle the "data-*" html attributes? ```` ul({ class: 'dropdown-menu', attributes: {role: 'menu', 'aria-labelledby': options[:id]} }, content) ```` This will get correct result.but a little ugly. ---------------------------------------------------------------------------------------------------- [05:41:24] jiayp(@jiayp):Maybe we build a html properties white list like svg and others put into `attributes'?So we can write like this: ```` ul({ class: 'dropdown-menu', role: 'menu', aria_labelledby: options[:id] }, content) ```` ---------------------------------------------------------------------------------------------------- [09:48:25] jiayp(@jiayp):@jgaskins I found a wired problem.I turn on the `debug` flag and found the app sometimes slow.So I start profile in chrome and the speed is fast again.Then I stop the profile the speed is keeping fast. ---------------------------------------------------------------------------------------------------- [09:49:38] jiayp(@jiayp):It always heppen when I change the Clearwater source. ---------------------------------------------------------------------------------------------------- [13:16:12] Jamie Gaskins(@jgaskins):@jiayp Because we're setting properties on DOM nodes directly, you specify `data-*` attributes by passing a hash to the `dataset` property: `div(dataset: { foo: 'bar' })`. I'm not sure what the JS DOM API properties are called for ARIA, though. They're rarely needed when using semantic tags, so I haven't checked them out yet. ---------------------------------------------------------------------------------------------------- [13:17:21] Jamie Gaskins(@jgaskins):@jiayp Do you mean the app *starts* slow or *runs* slow? If it's just starting slow it's probably due to recompiling. ---------------------------------------------------------------------------------------------------- ############################## [2016-03-08] ############################## [01:42:53] jiayp(@jiayp):@jgaskins runing slow sometimes. ---------------------------------------------------------------------------------------------------- [04:56:34] Jamie Gaskins(@jgaskins):@jiayp I wonder if it's the SVG attribute sanitization. You're right that we do it differently there — specifically, we do it in a way that's kinda slow and memory-intensive. Granted, it's the safest way (duplicating the hash that's passed in), but it's in a _really_ hot spot that we should optimize as much as possible, even if it means mutating an argument that was given to us. ---------------------------------------------------------------------------------------------------- [04:59:15] Jamie Gaskins(@jgaskins):The difference between mutating the attributes hash and creating a new one with updated attributes was a difference of 66% in peak memory usage (53 vs 32 MB, I think) in the Clearwater DBMon app. Hashes are a little expensive, so if we don't have to create a new one for every single node, that would be a massive performance boost. ---------------------------------------------------------------------------------------------------- [04:59:33] Jamie Gaskins(@jgaskins):That is, if we don't have to duplicate them for every node … ---------------------------------------------------------------------------------------------------- [05:00:29] Jamie Gaskins(@jgaskins):Creating one for every node is fine. But creating 2-3 for each node is a lot. :-\ ---------------------------------------------------------------------------------------------------- [05:28:54] Jamie Gaskins(@jgaskins):@jiayp Regarding #41, I'm very curious about your use case. I've never needed DOM subtree updating, even with the highest-performance-requirement app I've ever worked on (thousands of drivers delivering thousands of orders at a time) — `CacheRender` has always been enough. ---------------------------------------------------------------------------------------------------- [05:30:54] Jamie Gaskins(@jgaskins):It's possible that there's a use case I just haven't seen, but I also wonder if there's a better way to manage your app state to allow for better `CachedRender` usage. ---------------------------------------------------------------------------------------------------- [05:34:46] Jamie Gaskins(@jgaskins):I also need to write more about the Clearwater architecture, how I use it, how to use `CachedRender` effectively, all kinds of things. ---------------------------------------------------------------------------------------------------- [05:35:11] Jamie Gaskins(@jgaskins):I've been talking about making screencasts for a long time. I just haven't gotten to it. They take so long! :-) ---------------------------------------------------------------------------------------------------- [05:35:58] Jamie Gaskins(@jgaskins):Anyway, bedtime… ---------------------------------------------------------------------------------------------------- [05:36:24] Colin Gunn(@balmoral):@jgaskins a few clear and comprehensive examples is often enough :smile: ---------------------------------------------------------------------------------------------------- [14:18:19] jiayp(@jiayp):@jgaskins using CachedRender,Should I cache the CachedComponent's instance? ---------------------------------------------------------------------------------------------------- [14:26:18] Jamie Gaskins(@jgaskins):@jiayp Nope. Using `should_render?(previous)`, you can check the current instance against the previously rendered instance. ---------------------------------------------------------------------------------------------------- [14:27:15] Jamie Gaskins(@jgaskins):For example: ```ruby class ArticleDetail include Clearwater::Component attr_reader :article def initialize(article) @article = article end def should_render?(previous) !article.equal?(previous.article) end def render # ... end end ``` ---------------------------------------------------------------------------------------------------- [14:33:53] jiayp(@jiayp):@jgaskins Thanks,I found that. ---------------------------------------------------------------------------------------------------- [14:38:11] Jamie Gaskins(@jgaskins):The vdom diffing will check the `should_render?` method to see if it should actually generate the new vdom. No need to store the child component anywhere. :-) ---------------------------------------------------------------------------------------------------- [14:40:47] Jamie Gaskins(@jgaskins):I've gotten a few questions about whether reusing component instances is a good idea and it almost never is. It can actually cause problems if you reuse a `CachedRender` component because it will _never_ invalidate the cache. ---------------------------------------------------------------------------------------------------- [14:55:33] jiayp(@jiayp):Yes, I meet the problem,and it confuse me a lot. ---------------------------------------------------------------------------------------------------- [15:02:55] Jamie Gaskins(@jgaskins):That's how Clearwater used to do render caching. ---------------------------------------------------------------------------------------------------- [15:03:50] Jamie Gaskins(@jgaskins):That changed in #24 ---------------------------------------------------------------------------------------------------- ############################## [2016-03-09] ############################## [01:19:55] Colin Gunn(@balmoral):@jgaskins is it ok to store the root component instance and have somehing like this: ``` class RootComponent include Clearwater::Component include Clearwater::CachedRender def initialize invalidate! end def invalidate! @invalid = true end def should_render?(_) @invalid end def render @invalid = false # ... end end ``` ---------------------------------------------------------------------------------------------------- [04:39:15] Jamie Gaskins(@jgaskins):@balmoral That's a good question. Unfortunately, no. :-) Your root component and routing targets stay around for the life of the app, so you run into the same problem that @jiayp asked about with caching `CachedRender` components above. ---------------------------------------------------------------------------------------------------- [04:40:37] Jamie Gaskins(@jgaskins):I've found the root component and routing targets to be very good at being "smart components" whose primary job is to figure out what data to use and to dish that out into other components. They're basically like controllers in an MVC pattern. ---------------------------------------------------------------------------------------------------- [04:42:13] Jamie Gaskins(@jgaskins):I've been treating the other components that these "smart components" delegate to as presenters. They simply receive some number of objects and render some UI (including other components) to present those objects. ---------------------------------------------------------------------------------------------------- [04:43:11] Jamie Gaskins(@jgaskins):The funny thing is that once I discovered that sort of architecture, I found out that the React Router folks have been recommending the same thing. ---------------------------------------------------------------------------------------------------- [04:49:27] Jamie Gaskins(@jgaskins):@balmoral I wrote an article a couple weekends ago where I [compared Turbolinks to Clearwater](http://jgaskins.org/blog/2016/02/28/turbolinks-vs-the-virtual-dom). It took 8ms (on my 4-year-old iMac) in the [Clearwater example](https://turbolinks-vs-clearwater.herokuapp.com/clearwater/articles) to re-render after transitioning to the new route, despite instantiating a component for the entire list of 2000 articles. Caching high up the tree is a good idea (and nested caching is fantastic and space-efficient), but root components and routing targets do very well without being cached. If you _do_ want to cache them, I recommend delegating to a presenter-like component that can include the `CachedRender` mixin. ---------------------------------------------------------------------------------------------------- [04:50:10] Jamie Gaskins(@jgaskins):Clearwater really should invoke a warning inside the `Application` and `Router` if you try to use a `CachedRender` component. ---------------------------------------------------------------------------------------------------- [04:54:34] Jamie Gaskins(@jgaskins):#43 filed so we can try to handle this. ---------------------------------------------------------------------------------------------------- ############################## [2016-03-10] ############################## [05:27:30] jiayp(@jiayp):@jgaskins Can we cache the render result in `Component.sanitize_content` like this ```` if !content.cached_node || content.$should_render?(content.cached_state) content.cached_node = self.$sanitize_content(content.$render()) end content.cached_state = content.$save_state() return content.cached_node ```` ---------------------------------------------------------------------------------------------------- [05:30:02] jiayp(@jiayp):This will call `should_render?` if people cached the Component instance,and render correctly. ---------------------------------------------------------------------------------------------------- [05:31:19] jiayp(@jiayp):Current CachedRender request you must not "cached" the Component instance.It's wired. ---------------------------------------------------------------------------------------------------- [17:07:42] Jamie Gaskins(@jgaskins):Responded on #43. ---------------------------------------------------------------------------------------------------- [22:22:14] Colin Gunn(@balmoral):@jgaskins thanks for all the pointers. BTW your link above to the Clearwater example took me to a page full of Latin :smile: ---------------------------------------------------------------------------------------------------- [23:53:42] Jamie Gaskins(@jgaskins):lol ---------------------------------------------------------------------------------------------------- [23:55:03] Jamie Gaskins(@jgaskins):@balmoral Yeah, the Clearwater example is my Turbolinks vs Clearwater app I blogged about :-) ---------------------------------------------------------------------------------------------------- ############################## [2016-03-11] ############################## [02:27:49] jiayp(@jiayp):@jgaskins why event.target is `#@native.currentTarget`, https://github.com/clearwater-rb/bowser/blob/master/opal/bowser/event.rb#L37-L39 ---------------------------------------------------------------------------------------------------- [03:12:32] Mitch VanDuyn(@catmando):MN BM ik. ---------------------------------------------------------------------------------------------------- ############################## [2016-03-12] ############################## [00:32:47] Jamie Gaskins(@jgaskins):@jiayp There are `currentTarget`, `target`, and `srcElement`. I chose `currentTarget` completely arbitrarily. :-) ---------------------------------------------------------------------------------------------------- [00:36:02] Jamie Gaskins(@jgaskins):That is, native browser events have those 3 properties and they all appear to be the same (even on websocket events). I couldn't find anything about historical browser support for each one, but `target` and `currentTarget` seemed to be supported well enough so I just chose `currentTarget`. ---------------------------------------------------------------------------------------------------- [00:37:44] Jamie Gaskins(@jgaskins):If I'm mistaken and it should be something else, feel free to let me know. Most of my JS DOM event experience was through jQuery for so long that the JS DOM events API was always encapsulated for me. ---------------------------------------------------------------------------------------------------- ############################## [2016-03-14] ############################## [12:23:48] jiayp(@jiayp):@jgaskins why `animation_frame` delay 0.16s?why not more shorter?0.001s? ---------------------------------------------------------------------------------------------------- [12:25:22] jiayp(@jiayp):or should be 0.16s for 60 fps? ---------------------------------------------------------------------------------------------------- [14:36:30] Jamie Gaskins(@jgaskins):@jiayp Is it `0.16`? I meant to make it `0.016`. :-) But yes, that's 60 FPS. It only uses that delay anyway if the browser doesn't support `requestAnimationFrame`. If it does support `requestAnimationFrame` (IE 10+), it'll use that instead. ---------------------------------------------------------------------------------------------------- ############################## [2016-03-16] ############################## [00:06:33] Jamie Gaskins(@jgaskins):Corrected to be 60 fps in https://github.com/clearwater-rb/bowser/commit/c438e16710f5f68d939760f75fb57f14af9ede1a ---------------------------------------------------------------------------------------------------- ############################## [2016-03-18] ############################## [04:45:55] Colin Gunn(@balmoral):@jgaskins Just to say I’m making some good progress with Clearwater in Volt in a real application. Looks very promising so far :smile: ---------------------------------------------------------------------------------------------------- ############################## [2016-03-19] ############################## [03:37:06] Jamie Gaskins(@jgaskins):@balmoral That's awesome! If you're able to share any of the code (with proprietary stuff removed, of course) or blog about the experience, I'd _love_ to read it! ---------------------------------------------------------------------------------------------------- [07:17:11] Colin Gunn(@balmoral):@jgaskins happy to share as much as I can when working. Still getting my head around this virtual dom paradigm. In many ways it’s back-to-front compared to other frameworks - rendering everything rather than what’s changed still messes with my mind :smile: In an attempt to deal with this can you advise whether this makes sense: ``` class Node < Volt::VirtualDOM::Component attr_reader :tag_name, :attributes, :content, :model def initialize(tag_name, attributes: nil, content: nil, model: nil, dom_id: nil) super(dom_id: dom_id) @tag_name = tag_name @attributes = attributes @content = content @model = model @is_reactive = Proc === @content || Proc === @attributes || Proc === @tag_name @cached_tag = @is_reactive ? nil : render_tag end def render if @is_reactive render_tag else @cached_tag end end def reactive? @is_reactive end def render_tag tag( resolve(@tag_name), resolve(@attributes), resolve(@content) ) end private def resolve(thing) Proc === thing ? thing.call : thing end end ``` The idea is to only re-render stuff that might have changed (if a proc generates content), otherwise you hang on to the previously rendered virtual dom node. It’s not so much whether the virtual dom is efficient, but trying to eliminate running the domain logic unnecessarily. ---------------------------------------------------------------------------------------------------- [14:36:14] Jamie Gaskins(@jgaskins):@balmoral Have you tried using `Clearwater::CachedRender`? ---------------------------------------------------------------------------------------------------- [14:37:17] Jamie Gaskins(@jgaskins):Oh wait, are these nodes reused between renders? ---------------------------------------------------------------------------------------------------- [14:38:43] Jamie Gaskins(@jgaskins):Essentially, you've recreated some of that functionality here, which is why I ask. :-) Your implementation looks good if you have to reuse instances of this `Node` class. ---------------------------------------------------------------------------------------------------- [14:40:41] Jamie Gaskins(@jgaskins):Otherwise, using `CachedRender` is pretty awesome. It hooks into the virtual DOM engine to let you compare two completely different instances of a component between renders that would otherwise not even know about each other. And you can just check that the inputs to the components (or at least the attributes you care about) are the same. ---------------------------------------------------------------------------------------------------- [14:41:28] Jamie Gaskins(@jgaskins):https://github.com/clearwater-rb/clearwater/wiki/Rendering-from-the-top-down ---------------------------------------------------------------------------------------------------- [14:41:35] Jamie Gaskins(@jgaskins):^^ A bit of documentation on how it works ---------------------------------------------------------------------------------------------------- ############################## [2016-03-21] ############################## [22:59:39] Colin Gunn(@balmoral):@jgaskins thanks again for helpful guidance! I’ve been running into problems using components with CachedRender and spent a couple of days going in circles through my code thinking I’ve been doing something dumb. I think I’ve finally tracked the problem down to `#sanitize_content` in Clearwater::Component and raised issue #45. I’m no javascript expert so not sure what I’m doing here, but it seems to work. ---------------------------------------------------------------------------------------------------- ############################## [2016-03-22] ############################## [02:53:23] Jamie Gaskins(@jgaskins):Cool, still having a look. Regardless of whether or not it's a good idea, it's not exactly a great error message because Clearwater has no concept of "thunks". ;-) It's returned directly from the vdom engine, and as much as possible I'd like to insulate people from errors happening at that level while still keeping performance high. ---------------------------------------------------------------------------------------------------- [03:17:29] Colin Gunn(@balmoral):@jgaskins not being js literate - what is a thunk? ---------------------------------------------------------------------------------------------------- [03:18:06] Jamie Gaskins(@jgaskins):@balmoral A value to be computed later. In FP terms, thunks are usually functions. ---------------------------------------------------------------------------------------------------- [03:18:53] Colin Gunn(@balmoral):or function pointer? ---------------------------------------------------------------------------------------------------- [03:20:09] Jamie Gaskins(@jgaskins):But in the `virtual-dom` library, a thunk is an object whose `render` function is calculated at diff/patch time, rather than generating the vdom nodes up front and doing the diff/patch irrelevant of current conditions. ---------------------------------------------------------------------------------------------------- [03:20:40] Jamie Gaskins(@jgaskins):Yes, a function pointer. ---------------------------------------------------------------------------------------------------- [03:21:43] Jamie Gaskins(@jgaskins):Thunks are used a lot in JS libraries, where you can pass a function _or_ a value. If you give it a function, it just calls the function. ---------------------------------------------------------------------------------------------------- [03:22:22] Jamie Gaskins(@jgaskins):They're great for lazy computation or when you don't have all the information up front. ---------------------------------------------------------------------------------------------------- [03:22:48] Colin Gunn(@balmoral):got it - thanks. Same as I was using procs as content in Node example we discussed earlier. ---------------------------------------------------------------------------------------------------- [03:23:43] Jamie Gaskins(@jgaskins):@balmoral Bingo. That's basically a thunk. ---------------------------------------------------------------------------------------------------- [03:24:55] Jamie Gaskins(@jgaskins):In our case, we're using the component instance as a thunk during the diff/patch process so we can determine whether the previous instance of the same component rendered the same thing we will be. ---------------------------------------------------------------------------------------------------- [03:29:33] Colin Gunn(@balmoral):@jgaskins so it’s assumed that the same component (object identity) will always render the same content? Which is why a CachedRender must always be a different instance? ---------------------------------------------------------------------------------------------------- [03:31:04] Jamie Gaskins(@jgaskins):@balmoral Yes, exactly. It's an assumption made below Clearwater's level. The vdom engine won't even talk to us if we give it the same component twice. ---------------------------------------------------------------------------------------------------- [03:31:40] Jamie Gaskins(@jgaskins):That is, even `should_render?` won't be invoked. ---------------------------------------------------------------------------------------------------- [03:35:28] Colin Gunn(@balmoral):@jgaskins which explains a lot about where I’ve been going wrong! Old habits have inclined me to caching (hanging on to instances) of components in an attempt to make things faster. But making progress learning the new way, and much appreciate your generous support. :smile: ---------------------------------------------------------------------------------------------------- [03:37:24] Jamie Gaskins(@jgaskins):@balmoral No worries! Memoizing component instances used to be how Clearwater caching worked. It was much less fun because it meant parent components had to know their children needed caching and you had to cache component instances all the way through the component ancestors up to the nearest routing target or application root. ---------------------------------------------------------------------------------------------------- [03:37:53] Jamie Gaskins(@jgaskins):If any link in that chain was broken, so was the cache. :-) ---------------------------------------------------------------------------------------------------- [03:38:33] Jamie Gaskins(@jgaskins):@balmoral #46 fixes the issue, but I wanted to have some conversation about it. It's late here, though, so I'm gonna head to bed. Looking forward to chatting more about this later! ---------------------------------------------------------------------------------------------------- [03:41:31] Colin Gunn(@balmoral):@jgaskins will check out #46 and see whether I can add anything useful to the conversation :smile: ---------------------------------------------------------------------------------------------------- [21:19:16] ylluminate(@ylluminate):it might be nice to see clearwater up on https://github.com/TechEmpower/FrameworkBenchmarks ---------------------------------------------------------------------------------------------------- [21:19:56] ylluminate(@ylluminate):i threw out a suggestion that kemal for crystal put up a benchmark back in february and someone got that merged: https://github.com/sdogruyol/kemal/issues/83 ---------------------------------------------------------------------------------------------------- [21:20:46] ylluminate(@ylluminate):here's the pr for that: https://github.com/TechEmpower/FrameworkBenchmarks/pull/1938 ---------------------------------------------------------------------------------------------------- [21:29:57] ylluminate(@ylluminate):and this pr was the last one from kemal creator that fixed an issue: https://github.com/TechEmpower/FrameworkBenchmarks/pull/1973 ---------------------------------------------------------------------------------------------------- [21:30:53] ylluminate(@ylluminate):interesting stuff and would give clearwater a little more facetime ---------------------------------------------------------------------------------------------------- [02:43:26] Jamie Gaskins(@jgaskins):@balmoral Decided to jump on the computer because it's gonna bug me if I don't check this out. :-) ---------------------------------------------------------------------------------------------------- [02:44:11] Colin Gunn(@balmoral):@jgaskins let me know how you go or if I can help ---------------------------------------------------------------------------------------------------- [02:44:31] Jamie Gaskins(@jgaskins):@balmoral Will do :-) ---------------------------------------------------------------------------------------------------- [02:45:52] Jamie Gaskins(@jgaskins):@balmoral To clarify, is the error you're seeing `thunk did not return a valid node`? ---------------------------------------------------------------------------------------------------- [02:46:53] Jamie Gaskins(@jgaskins):It looks like that's happening for me when I return a `CachedRender` directly from a `CachedRender`. ---------------------------------------------------------------------------------------------------- [02:47:01] Jamie Gaskins(@jgaskins):But that's the only way I can reproduce it ---------------------------------------------------------------------------------------------------- [02:48:29] Colin Gunn(@balmoral):@jgaskins line 1457 in the js code. Think it was also the same condition for me - nested CachedRenders (not necessarily smart :smile: ) ---------------------------------------------------------------------------------------------------- [02:48:43] Colin Gunn(@balmoral):@jgaskins got to go - back shortly ---------------------------------------------------------------------------------------------------- ############################## [2016-03-23] ############################## [01:21:40] Colin Gunn(@balmoral):@jgaskins you were right about the patch circumventing CachedRender :smile: Now that I’ve finally got all that working well (thanks to your advice) I’ve had to remove the patch, and avoid nested CachedRender’s. Which is ok for now, but I’m pretty sure I’ll need them future. My thinking here is that a CachedRender is blind to anything other than whether there’s a difference in state/content between it and a previous instance. Likewise, I think it needs to be blind to whether something it renders is also a CachedRender. Hope it can be implemented without adverse performance hit. PS CachedRender is as awesome as you suggest. Getting rid of memo-ised components and focusing on state management instead has simplified my code considerably, and is probably faster to boot! ---------------------------------------------------------------------------------------------------- [02:37:10] Jamie Gaskins(@jgaskins):@ylluminate That's a good idea. Thanks! ---------------------------------------------------------------------------------------------------- [02:39:17] Jamie Gaskins(@jgaskins):@balmoral You can nest `CachedRender` components, but there has to be a plain vdom layer between them, so in my reproduction in #45 (https://github.com/clearwater-rb/clearwater/issues/45#issuecomment-199603518), if you implement `Foo#render` as `div(Bar.new)` (just wrap the component in a `div`), it'll work just fine. ---------------------------------------------------------------------------------------------------- [04:12:25] ylluminate(@ylluminate)::thumbsup: @jgaskins ---------------------------------------------------------------------------------------------------- ############################## [2016-03-24] ############################## [23:44:13] Colin Gunn(@balmoral):@jgaskins I’m getting an error loading the clearwater gem in volt. I’ve just refactored my vdom stuff into a gem which specifies `'clearwater', '~> 1.0.0.beta5’` as a dependency. When I load my gem `vdom-rb`via Opal.use_gem I get this error: ``` Gem::Specification.find_by_name(clearwater) [ERROR] # /Users/col/.rvm/gems/ruby-2.2.1/gems/opal-0.8.1/lib/opal/paths.rb:36:in `require_paths_for_gem' /Users/col/.rvm/gems/ruby-2.2.1/gems/opal-0.8.1/lib/opal/paths.rb:37:in `block in require_paths_for_gem' /Users/col/.rvm/gems/ruby-2.2.1/gems/opal-0.8.1/lib/opal/paths.rb:36:in `each' /Users/col/.rvm/gems/ruby-2.2.1/gems/opal-0.8.1/lib/opal/paths.rb:36:in `require_paths_for_gem' /Users/col/.rvm/gems/ruby-2.2.1/gems/opal-0.8.1/lib/opal/paths.rb:27:in `use_gem' /Users/col/dev/workspace/tbs/tbs-volt/config/initializers/load_gems.rb:6:in `block in ' /Users/col/dev/workspace/tbs/tbs-volt/config/initializers/load_gems.rb:4:in `each' /Users/col/dev/workspace/tbs/tbs-volt/config/initializers/load_gems.rb:4:in `' /Users/col/.rvm/gems/ruby-2.2.1/gems/volt-0.9.6/lib/volt/volt/server_setup/app.rb:101:in `require' /Users/col/.rvm/gems/ruby-2.2.1/gems/volt-0.9.6/lib/volt/volt/server_setup/app.rb:101:in `block in run_app_and_initializers' /Users/col/.rvm/gems/ruby-2.2.1/gems/volt-0.9.6/lib/volt/volt/server_setup/app.rb:100:in `each' /Users/col/.rvm/gems/ruby-2.2.1/gems/volt-0.9.6/lib/volt/volt/server_setup/app.rb:100:in `run_app_and_initializers' /Users/col/.rvm/gems/ruby-2.2.1/gems/volt-0.9.6/lib/volt/volt/app.rb:88:in `initialize' /Users/col/.rvm/gems/ruby-2.2.1/gems/volt-0.9.6/lib/volt/boot.rb:21:in `new' /Users/col/.rvm/gems/ruby-2.2.1/gems/volt-0.9.6/lib/volt/boot.rb:21:in `boot' /Users/col/.rvm/gems/ruby-2.2.1/gems/volt-0.9.6/lib/volt/server.rb:43:in `boot_volt' /Users/col/.rvm/gems/ruby-2.2.1/gems/volt-0.9.6/lib/volt/server/forking_server.rb:76:in `start_child' /Users/col/.rvm/gems/ruby-2.2.1/gems/volt-0.9.6/lib/volt/server/forking_server.rb:37:in `initialize' /Users/col/.rvm/gems/ruby-2.2.1/gems/volt-0.9.6/lib/volt/server.rb:79:in `new' /Users/col/.rvm/gems/ruby-2.2.1/gems/volt-0.9.6/lib/volt/server.rb:79:in `app' /Users/col/.rvm/gems/ruby-2.2.1/gems/volt-0.9.6/lib/volt/cli.rb:75:in `server' /Users/col/.rvm/gems/ruby-2.2.1/gems/thor-0.19.1/lib/thor/command.rb:27:in `run' /Users/col/.rvm/gems/ruby-2.2.1/gems/thor-0.19.1/lib/thor/invocation.rb:126:in `invoke_command' /Users/col/.rvm/gems/ruby-2.2.1/gems/thor-0.19.1/lib/thor.rb:359:in `dispatch' /Users/col/.rvm/gems/ruby-2.2.1/gems/thor-0.19.1/lib/thor/base.rb:440:in `start' /Users/col/.rvm/gems/ruby-2.2.1/gems/volt-0.9.6/lib/volt/cli.rb:182:in `' /Users/col/.rvm/gems/ruby-2.2.1/gems/volt-0.9.6/bin/volt:4:in `require' /Users/col/.rvm/gems/ruby-2.2.1/gems/volt-0.9.6/bin/volt:4:in `' /Users/col/.rvm/gems/ruby-2.2.1/bin/volt:23:in `load' /Users/col/.rvm/gems/ruby-2.2.1/bin/volt:23:in `
' /Users/col/.rvm/gems/ruby-2.2.1/bin/ruby_executable_hooks:15:in `eval' /Users/col/.rvm/gems/ruby-2.2.1/bin/ruby_executable_hooks:15:in `
’ ``` bundle in my gem and the app is showing the right clearwater version as installed, so I’m at a bit of a loss. ---------------------------------------------------------------------------------------------------- [23:46:05] Colin Gunn(@balmoral):^^first line above is a debug trace in `opal/paths.rb` ---------------------------------------------------------------------------------------------------- ############################## [2016-03-25] ############################## [01:02:31] Colin Gunn(@balmoral):@jgaskins if I take the clearwater dependency out of my gem, and instead explicitly specify bowser and clearwater in my Volt gemfile, then all works ok. Also, I have a few other gems which I have to explicitly get Opal to load via `Opal.use_gem` when my Volt app loads. However I don’t need to do this for clearwater and bowser. Is it the opal dependency that tells opal a gem should be loaded by opal? ---------------------------------------------------------------------------------------------------- [01:33:03] Jamie Gaskins(@jgaskins):@balmoral `Opal.use_gem` just adds the gem's `lib` directory (and other load paths, I assume) into Opal's load path, as well. Clearwater doesn't need to do this because only a subset of its code is intended to be run on Opal, so it uses `Opal.append_path` explicitly on the server. Same with Bowser. ---------------------------------------------------------------------------------------------------- [01:34:07] Jamie Gaskins(@jgaskins):@balmoral But this is cool because it lets you load gems that know nothing about Opal in your client-side app. ---------------------------------------------------------------------------------------------------- [01:34:40] Jamie Gaskins(@jgaskins):That's about the only thing `Opal.use_gem` is really good for. If the gem knows about Opal, it should use `Opal.append_path` directly. ---------------------------------------------------------------------------------------------------- [01:38:30] Jamie Gaskins(@jgaskins):Speaking of which, this reminds me I wanted to check that the `hamster` gem can be used now through `Opal.use_gem`. It would be the perfect state container for a GrandCentral store. ---------------------------------------------------------------------------------------------------- [01:47:42] Jamie Gaskins(@jgaskins):Oh, right. I forgot Hamster uses `undef :"<=>"`. I spent a lot of time in the Opal compiler trying to fix that and my conclusion was that I know very little about compilers. ---------------------------------------------------------------------------------------------------- [01:49:17] Colin Gunn(@balmoral):@jgaskins thanks for clarifying that. Some of my gems have no knowledge of Opal so I guess I’ll need `Opal.use_gem` for them. Will try `append_path` for the others. ---------------------------------------------------------------------------------------------------- [01:50:39] Jamie Gaskins(@jgaskins):@balmoral The fact that it exists is pretty great. It could be documented better how to use it, but then so could literally everything in Clearwater. ;-) ---------------------------------------------------------------------------------------------------- [01:53:48] Colin Gunn(@balmoral):@jgaskins probably more about Opal than Clearwater :smile: ---------------------------------------------------------------------------------------------------- [01:55:42] Jamie Gaskins(@jgaskins):@balmoral Just making a joke about how bad Clearwater's docs are. It's basically a readme. :-) ---------------------------------------------------------------------------------------------------- [01:57:50] Colin Gunn(@balmoral):@jgaskins code first, document at leisure :smile: ---------------------------------------------------------------------------------------------------- ############################## [2016-03-27] ############################## [04:52:29] Colin Gunn(@balmoral):@jgaskins can jquery elements be used in virtual dom? ---------------------------------------------------------------------------------------------------- [05:01:07] Colin Gunn(@balmoral):I’m using bootstrap-select which is a jquery-dependent component. The following works in html: ``` ``` but the following is not working in the virtual dom: ``` select( { class: 'selectpicker'}, [ option('Option 1’), … ] ) ``` ---------------------------------------------------------------------------------------------------- [05:01:44] Colin Gunn(@balmoral):If I remove `class: ‘selectpicker` it works as a standard select. ---------------------------------------------------------------------------------------------------- [19:58:07] Jamie Gaskins(@jgaskins):@balmoral It might work, but there isn't much of a guarantee there. The problem is that since the DOM is meant to be derived from the vdom, so it's not intended to be modified directly. If you modify the DOM on your own, when the vdom engine tries to patch the DOM, the elements won't be in the same structure it expects. The good news is that there's a `BlackBoxNode` mixin that might help you. It tells the vdom engine _not_ to diff/patch there, which is useful if it's something you're creating on your own: ```ruby require 'clearwater/black_box_node' class SelectPicker include Clearwater::BlackBoxNode attr_reader :options def initialize(options) @options = options end # This method is what creates the element. def node Clearwater::Component.select({ class: 'selectpicker' }, options.map { |o| option(o.name) }) end # This method gets called when the element is created but before it is added to the DOM def mount element `$.selectPicker(element)` end def update previous, element # Run any updates on the element. end def unmount element # Clean up after yourself here, if necessary. Usually not needed. end end ``` ---------------------------------------------------------------------------------------------------- ############################## [2016-03-30] ############################## [03:59:22] Jamie Gaskins(@jgaskins):@/all I've heard whispers that Matz mentioned Clearwater and Volt by name in his keynote at RubyConfIndia a couple weeks ago. Just checked with the conference and their videos should be out by mid-April. ---------------------------------------------------------------------------------------------------- [03:59:29] Jamie Gaskins(@jgaskins):Super excited to hear about that! ---------------------------------------------------------------------------------------------------- [04:06:21] Mitch VanDuyn(@catmando):congrats! ---------------------------------------------------------------------------------------------------- [05:32:40] Forrest Chang(@fkchang):@jgaskins good deal! Hopefully we can get other parts of Opal some screen time ---------------------------------------------------------------------------------------------------- [07:23:38] Colin Gunn(@balmoral):@jgaskins Couldn’t get the SelectPicker to work. I’m wondering whether virtual dom isn’t appropriate for form based stuff. ---------------------------------------------------------------------------------------------------- [14:33:31] Jamie Gaskins(@jgaskins):@balmoral I get it working with stuff like this all the time, it can work. :-) If you want, we could pair on it. ---------------------------------------------------------------------------------------------------- [23:47:15] Colin Gunn(@balmoral):@jgaskins thanks for the offer :smile: In your example above, are you assuming a function in select picker `$.selectPicker(element)` or is that a generalised jquery type call? There’s nothing the selectpicker docs specifying such a function. In non vdom you’d just create the element as in your `node `method` with no further mounting required. Re the options passed in as content for the select - does it make any difference that these are generated by the virtual dom interface? And a more general question - have you had success with dynamic forms, i.e. the form dynamically changes according to changes in input/select states? Sorry for dumb questions. Much appreciate your support. ---------------------------------------------------------------------------------------------------- ############################## [2016-03-31] ############################## [15:08:09] Jamie Gaskins(@jgaskins):@balmoral I have no idea how the select picker works. That was total pseudocode. :-) Re: the options passed into the select, you can set up the node however you like. It'll get turned into a normal DOM node as usual. But it doesn't have the DSL, so you have to namespace them as `Clearwater::Component.select` and `Clearwater::Component.option`. Or you could include the `Clearwater::Component` mixin (I think you need to include it _before_ `BlackBoxNode`). Dynamically rendered forms are absolutely doable. Once I get some free time (I'm moving this weekend, so I've got no free time for the next couple weeks), I'll post an example. ---------------------------------------------------------------------------------------------------- [20:07:54] Colin Gunn(@balmoral):@jgaskins thanks. Will keep tinkering. ---------------------------------------------------------------------------------------------------- ############################## [2016-04-29] ############################## [21:35:38] Jamie Gaskins(@jgaskins):[![matz_mentions_clearwater.jpg](https://files.gitter.im/clearwater-rb/clearwater/kqYh/thumb/matz_mentions_clearwater.jpg)](https://files.gitter.im/clearwater-rb/clearwater/kqYh/matz_mentions_clearwater.jpg) ---------------------------------------------------------------------------------------------------- [21:35:59] Jamie Gaskins(@jgaskins):Matz mentions Clearwater in his keynote at RubyConf India ---------------------------------------------------------------------------------------------------- ############################## [2016-05-17] ############################## [22:15:37] Forrest Chang(@fkchang):@jgaskins what r using to query the dom in clearwater, I expected to find some of that in bowser but didnt' ---------------------------------------------------------------------------------------------------- [22:53:49] Jamie Gaskins(@jgaskins):@fkchang It uses `Bowser.document[css_selector]`. ---------------------------------------------------------------------------------------------------- [22:54:13] Jamie Gaskins(@jgaskins):Similar to `$document[css_selector]` in `opal-browser`. ---------------------------------------------------------------------------------------------------- [22:56:41] Jamie Gaskins(@jgaskins):The API isn't 100% like `opal-browser`, but I did want it to be able to do most things you're likely to need because you _can_ get references to DOM elements and I didn't want it to be just a native pass-through. ---------------------------------------------------------------------------------------------------- [23:24:47] Forrest Chang(@fkchang):@jgaskins thx ---------------------------------------------------------------------------------------------------- [23:42:46] Jamie Gaskins(@jgaskins):@fkchang testing Opal Hot Reloader on Clearwater? ---------------------------------------------------------------------------------------------------- ############################## [2016-05-18] ############################## [02:58:32] Jamie Gaskins(@jgaskins):@fkchang Here's the Clearwater Hot Loader I was telling you about: https://github.com/clearwater-rb/clearwater-hot_loader It's got a couple rough edges, but it works pretty well. ---------------------------------------------------------------------------------------------------- [04:16:19] LeoDaoTao(@LeoDaoTao):@jgaskins just what I needed :-) ---------------------------------------------------------------------------------------------------- [04:17:38] Jamie Gaskins(@jgaskins):@LeoDaoTao :+1: Awesome! I wrote it a long time ago, but it never left my machine until this evening. ---------------------------------------------------------------------------------------------------- [04:17:57] Jamie Gaskins(@jgaskins):I kept forgetting about it ---------------------------------------------------------------------------------------------------- [22:11:29] LeoDaoTao(@LeoDaoTao):@jgaskins I’m working on framework for building opiniated apps using Clearwater based on Material Design. Currently working on getting all the CSS and HTML code prepared for all the components. Will be starting on Clearwater work next week. I’m going to have a bunch of questions for you :-) befere I fully undestand how Clearwater works :-) I’ll push some code up to GitHub when it starts looking like something decent :-) ---------------------------------------------------------------------------------------------------- [22:54:41] Jamie Gaskins(@jgaskins):@LeoDaoTao Awesome! Feel free to ask anything. I've been working on a docs site for ages that I keep getting distracted from, too. :-) ---------------------------------------------------------------------------------------------------- ############################## [2016-05-19] ############################## [00:03:26] Forrest Chang(@fkchang):@jgaskins I like a number of things in your router, I never considered the rack mounted approach, I could make that an option ---------------------------------------------------------------------------------------------------- [00:55:17] Jamie Gaskins(@jgaskins):@fkchang Yeah, I like the idea of making optimizations for Rails, but I'm a fan of trying to make it usable for other frameworks and Rack was the common denominator there. A lot of people using Clearwater at the moment are people experimenting with things outside of mainstream Ruby web dev, including myself. ;-) ---------------------------------------------------------------------------------------------------- [17:00:29] Forrest Chang(@fkchang):@jgaskins yeah, I'm trying to make opal-hot-reloader serve as a tool that will work for all opal projects, in the most common backend server scenarios (naturally targeting rails and sinatra as 1st targets), but something that worked even if you didn't have a ruby backend (thus the standalone app). I think I will include clearwater support just to flesh out the autodetect/extend with your framework API, but I imagine clearwater-hot_loader might be a better choice for clearwater apps, though I'll have css hot reloading very soon ---------------------------------------------------------------------------------------------------- [17:01:43] Forrest Chang(@fkchang):I'm looking to make it even less work to include because I should autodetect common setups - i.e. rails project, reactrb or clearwater already included etc. ---------------------------------------------------------------------------------------------------- ############################## [2016-05-20] ############################## [03:16:53] Jamie Gaskins(@jgaskins)::+1: ---------------------------------------------------------------------------------------------------- ############################## [2016-05-27] ############################## [18:32:08] LeoDaoTao(@LeoDaoTao):I’m trying to get a grasp of styling components. From previous discussions, I gathered that the preferred way is to use styles within the components as a snake_cased style hash. However, that produces an inline style. All is good but in that case I can't use pseudo elements or media queries in my style declaration. Any good solution to that besides using an external stylesheet? But that defeats the purpose of having the style in the component in the first place. ---------------------------------------------------------------------------------------------------- ############################## [2016-05-28] ############################## [16:04:47] Jamie Gaskins(@jgaskins):@LeoDaoTao That's the main downside of using self-contained styles. It's not unique to Clearwater, though; even React suffers this same problem. The only way to use pseudo elements and media queries is to use an external stylesheet. :-\ ---------------------------------------------------------------------------------------------------- [16:05:40] Jamie Gaskins(@jgaskins):Same with CSS animations. You can _use_ an animation from an inline style, but the animation has to be *defined* in CSS. ---------------------------------------------------------------------------------------------------- [16:12:11] Jamie Gaskins(@jgaskins):For media queries, I've gotten around it by branching on `window.innerWidth`: ```ruby class Foo include Clearwater::Component def render div({ style: Style.foo }, stuff) end module Style module_function def foo { display: 'inline-block', width: foo_width, } end def foo_width case `window.innerWidth` when 0...640 then '50px' when 640...720 then '75px' else '100px' end end end end ``` ---------------------------------------------------------------------------------------------------- [20:02:14] LeoDaoTao(@LeoDaoTao):@jgaskins thank you for your input. Going to have to play a bit with various cases to see which will work better. I like your `window.innerWidth` solution for media queries. ---------------------------------------------------------------------------------------------------- ############################## [2016-06-01] ############################## [00:45:09] Forrest Chang(@fkchang):@jgaskins you don't happen to have a "smallest clearwater project" repo handy? I want to build in support for clearwater into opal-hot-reloader and need a test bed ---------------------------------------------------------------------------------------------------- [00:46:13] Forrest Chang(@fkchang):I'm almost thinking I should pitch opal-hot-reloader for hot css reloading in rails alone, bound to get more attention than it has... ---------------------------------------------------------------------------------------------------- [02:06:04] Jamie Gaskins(@jgaskins):@fkchang In a Rails app? I can make one real quick. ---------------------------------------------------------------------------------------------------- [02:15:08] Jamie Gaskins(@jgaskins):@fkchang https://github.com/clearwater-rb/clearwater_rails_starter_kit ---------------------------------------------------------------------------------------------------- [02:15:40] Jamie Gaskins(@jgaskins):The Clearwater app is in the usual `app/assets/javascripts` directory, but linked in the Readme for convenience. ---------------------------------------------------------------------------------------------------- [02:19:54] Jamie Gaskins(@jgaskins):Thanks for checking it against Clearwater, though! I really appreciate it. To re-render Clearwater apps on a file change, you can call `Clearwater::Application.render`. It will re-render all Clearwater apps (as many as there are on the page) that have been invoked with `Clearwater::Application#call`. ---------------------------------------------------------------------------------------------------- [02:20:17] Jamie Gaskins(@jgaskins):It maintains a registry of all mounted apps specifically so it can re-render all of them on demand. ---------------------------------------------------------------------------------------------------- [04:58:58] Forrest Chang(@fkchang):@jgaskins thanks, I would've been fine w/sinatra or roda also. I'm trying to add in some auto detecting of frameworks so users can do even less to get started. I'd like to do the same on the server too, but I think the best I can do is assume directories, w/Rails that's easier, w/other rack frameworks, it's all up in the air ---------------------------------------------------------------------------------------------------- ############################## [2016-06-02] ############################## [18:27:09] Jamie Gaskins(@jgaskins):@fkchang `Clearwater::HotLoader` listens to `app/assets/**/*.rb` and `assets/**/*.rb` (if they exist) by default, I think. That covers Rails, Roda, and probably whatever Sinatra uses for asset compilation. I don't know how Hanami structures directories yet, but I'll probably check that this weekend. ---------------------------------------------------------------------------------------------------- [23:27:25] Jamie Gaskins(@jgaskins):@jdickey Thanks for your comment on the Reddit thread. I'm really glad you're finding Clearwater useful! ---------------------------------------------------------------------------------------------------- ############################## [2016-06-03] ############################## [04:32:10] Jeff Dickey(@jdickey):@jgaskins Glad to; that thread was accumulating enough more-hipster-than-thou dissing that simply wasn't warranted IMO ---------------------------------------------------------------------------------------------------- [17:16:23] Jamie Gaskins(@jgaskins):There were definitely some skeptics there. There's definitely a problem in the industry with people talking down about compile-to-JS languages out of fear of the unknown or in a "get off my lawn" kind of way. The funny thing is, just as people are telling us "just write JS", people told Grace Hopper to "just write machine/assembly code" when she invented the compiler. History is repeating itself. ---------------------------------------------------------------------------------------------------- [17:22:16] Jeff Dickey(@jdickey):Very true. Grace Hopper is high on the list of my career heroes/heroines. It just boggles my mind what they had to work with, and I go back far enough to have some appreciation, I think (the youngest guy the State of California ever paid to operate one of the IBM 704 should-have-been-museum-pieces-15-years-before). Anybody can be young and stupid; to be (relatively) young and brilliant is *much* harder. ---------------------------------------------------------------------------------------------------- [17:23:19] Jeff Dickey(@jdickey):another reason why Gamergate et al just grind my gears, but oh well ---------------------------------------------------------------------------------------------------- [17:26:21] Jeff Dickey(@jdickey):sorry, folks; tonight's a long fortnight ---------------------------------------------------------------------------------------------------- [17:27:34] Jamie Gaskins(@jgaskins):No need to apologize. You're good. :beers: ---------------------------------------------------------------------------------------------------- [17:30:13] Jeff Dickey(@jdickey):thanks. It's 0130 over here, and I think I'm going to actually go to bed _before_ my eyes fall out for once. Thanks for the shout, and enjoy your weekend ---------------------------------------------------------------------------------------------------- [17:30:53] Jamie Gaskins(@jgaskins):You too, @jdickey. G'nite! ---------------------------------------------------------------------------------------------------- ############################## [2016-06-05] ############################## [07:23:04] Jamie Gaskins(@jgaskins):Just added automatic hydration for server-rendered Clearwater apps in #48. Would love feedback on it. This should give better first-interaction times for server-rendered apps. :-D ---------------------------------------------------------------------------------------------------- ############################## [2016-06-26] ############################## [07:10:32] Jamie Gaskins(@jgaskins):Added routing hooks in #52 and was able to add an awesome UX to an app in a particular scenario for which Clearwater doesn't currently work well. Feedback welcome! ---------------------------------------------------------------------------------------------------- ############################## [2016-06-27] ############################## [22:33:12] Jamie Gaskins(@jgaskins):I think that for sufficiently underpowered devices, you'd run into memory issues just as fast as you'd run into runtime issues. A list of 5k items (a total of 30k elements, for a total of about 50k nodes including text nodes) renders from scratch in a couple hundred milliseconds on my phone. However, instant rendering is better than waiting at all. :-) ---------------------------------------------------------------------------------------------------- [17:23:08] Forrest Chang(@fkchang):@jgaskins updates look cool from the descriptions. I'm curious as to the "awesome UX" situation ---------------------------------------------------------------------------------------------------- [22:29:40] Jamie Gaskins(@jgaskins):@fkchang Navigating to a page with a lot of content on it currently renders everything in one pass. If this generates a massive diff, the UI is blocked for as long as it takes to patch the DOM. If it takes several seconds, the UX is a train wreck. The way to fix that is for a routing target to know that it is running its first render (rather than updating itself) so it can just render a small chunk of its content up front instead of naively shoving everything into the DOM, but Clearwater didn't have a way to do that until #52. I don't think lifecycle hooks are a great way to handle a lot of things in Clearwater (they're okay in React, but Clearwater components are _very_ different), but I couldn't come up with another solution for this scenario. ---------------------------------------------------------------------------------------------------- ############################## [2016-07-01] ############################## [19:24:40] Torsten Rüger(@dancinglightning):@jgaskins just had an idea while reading about #51 and #52 and considering the docs: A non-trivial example app, where those kind of issues would actually come into play. I've been wanting to work on an opal presentation, so i could sink a little time (1 hour a day say) into this. That way i would be asking stupid beginners questions. If you were to answer those, they could make up documentation. (I could help with that too). ---------------------------------------------------------------------------------------------------- [23:36:04] Jamie Gaskins(@jgaskins):@dancinglightning Yeah, I've been thinking of setting up a nontrivial app that showed off things like state management and handling events. The TodoMVC app is a decent app to show off rendering, but it's not great to show state management because you're just shoving everything into `localStorage`. ---------------------------------------------------------------------------------------------------- [23:36:44] Jamie Gaskins(@jgaskins):It'd be better to have an app that showed idioms for communicating with an API ---------------------------------------------------------------------------------------------------- ############################## [2016-07-03] ############################## [18:25:02] Forrest Chang(@fkchang):@jgaskins cool u got the doc site up. Curious as to why you didn't do a github.io site? ---------------------------------------------------------------------------------------------------- [19:54:45] Jamie Gaskins(@jgaskins):@fkchang I've just never set one up before. :-) ---------------------------------------------------------------------------------------------------- [19:56:20] Jamie Gaskins(@jgaskins):Also, don't you have to manually compile assets to push them to a github.io site? ---------------------------------------------------------------------------------------------------- [20:11:53] Forrest Chang(@fkchang):@jgaskins I've never set one up from scratch, just tinkered or copied others, but basically for any repo, what ever is on your gh-pages branch becomes the the .github.io site, github supports jekyll and things based on jekyll ---------------------------------------------------------------------------------------------------- [20:21:14] Jamie Gaskins(@jgaskins):@fkchang Ah, okay. I haven't used Jekyll in a while. I built this site on Roda (and extracted a [`roda-opal_assets` gem](https://github.com/clearwater-rb/roda-opal_assets) to make working with Roda easier) just because it's so easy to pass everything through to a front-end app. The entire docs site is a Clearwater app so I can show off some of the things Clearwater does. I'll probably set it up to be server-rendered, as well. ---------------------------------------------------------------------------------------------------- [20:21:58] Jamie Gaskins(@jgaskins):I need to add a better readme for that gem, though. ---------------------------------------------------------------------------------------------------- ############################## [2016-07-09] ############################## [15:58:17] Jamie Gaskins(@jgaskins):https://twitter.com/rubygems/status/751806288716234752 ---------------------------------------------------------------------------------------------------- [16:01:00] Jamie Gaskins(@jgaskins):[Changelog](https://github.com/clearwater-rb/clearwater/blob/master/CHANGELOG.md#version-100rc2) — [Diff from 1.0.0.rc1](https://github.com/clearwater-rb/clearwater/compare/v1.0.0.rc1...v1.0.0.rc2) ---------------------------------------------------------------------------------------------------- [18:57:35] Forrest Chang(@fkchang):@jgaskins nice! ---------------------------------------------------------------------------------------------------- ############################## [2016-07-10] ############################## [12:41:43] Elia Schito(@elia):@jgaskins couldn't find a url for the docs, are those published somewhere? ---------------------------------------------------------------------------------------------------- [19:39:04] Jamie Gaskins(@jgaskins):@elia I'm still working on them: https://clearwater-docs.herokuapp.com/ ---------------------------------------------------------------------------------------------------- [19:39:49] Jamie Gaskins(@jgaskins):It's slow going because I'm terrible at writing docs. I get caught up in the minutiae. :-) But they'll be ready before I release 1.0. ---------------------------------------------------------------------------------------------------- [19:46:53] Jamie Gaskins(@jgaskins):If you're looking for it for this: https://gitter.im/opal/opal?at=57827ac1b79455146f860eb8 That's where they'll be when they're finished. :-) ---------------------------------------------------------------------------------------------------- ############################## [2016-07-18] ############################## [23:46:41] LeoDaoTao(@LeoDaoTao):Hi, so if I wanted to write a front-end only clearwater app (no server side framework) how how I go about it? ---------------------------------------------------------------------------------------------------- [23:56:00] Jamie Gaskins(@jgaskins):@LeoDaoTao You mean just to compile the Clearwater app to JS? ---------------------------------------------------------------------------------------------------- [23:56:17] Jamie Gaskins(@jgaskins):Or do you still want to serve it up but just not have a full server-side app? ---------------------------------------------------------------------------------------------------- [23:56:22] LeoDaoTao(@LeoDaoTao):@jgaskins I think that would be the best way to describe it ---------------------------------------------------------------------------------------------------- [23:56:49] LeoDaoTao(@LeoDaoTao):@jgaskins have to make an app that will work with an API and want to give clearwater a shot with it ---------------------------------------------------------------------------------------------------- [23:57:43] LeoDaoTao(@LeoDaoTao):@jgaskins have the app in jquery now but it’s painfully slow ---------------------------------------------------------------------------------------------------- [23:57:56] Jamie Gaskins(@jgaskins):@LeoDaoTao I've done `bundle exec ruby -rclearwater -S opal -c assets/js/app.rb > public/js/app.js`, but that's clunky and I'm not even sure it works. ---------------------------------------------------------------------------------------------------- [23:59:16] Jamie Gaskins(@jgaskins):Yeah, we're having similar problems at my new job. We have a legacy jQuery front-end app we're looking to convert. We're looking at Clearwater as a replacement. ---------------------------------------------------------------------------------------------------- ############################## [2016-07-19] ############################## [00:00:25] LeoDaoTao(@LeoDaoTao):@jgaskins how about making the app with a simple roda backend to serve it up and just copy the compiled assets when app is ready to go ready. That should work right? ---------------------------------------------------------------------------------------------------- [00:02:24] Jamie Gaskins(@jgaskins):@LeoDaoTao Indeed. I'm working on [`roda-opal_assets`](https://github.com/clearwater-rb/roda-opal_assets) to help with this. It's a bit smoother than the `Opal::Builder` idea [here](https://github.com/jeremyevans/roda-opal-example/blob/master/config.ru#L4-L5). It uses Sprockets so you don't have to wait 2 seconds to recompile every time you update. ---------------------------------------------------------------------------------------------------- [00:03:56] LeoDaoTao(@LeoDaoTao):@jgaskins Ok great will try that. Finally, I have the time to spend a week or two with clearwater :-) ---------------------------------------------------------------------------------------------------- [00:04:04] Jamie Gaskins(@jgaskins):Awesome! :+1: ---------------------------------------------------------------------------------------------------- [00:05:38] Jamie Gaskins(@jgaskins):I need to add a way to output the compiled JS to make it easy to add a `rake assets:precompile`-like task for it. ---------------------------------------------------------------------------------------------------- [00:06:43] LeoDaoTao(@LeoDaoTao):That would be cool. I plan on using clearwater for a hybrid phone app and that may come in handy :-) ---------------------------------------------------------------------------------------------------- [00:10:02] Jamie Gaskins(@jgaskins):Sweet! My Clearwater apps have been mainly desktop web apps (internal, so we didn't have to focus on mobile usability), but I've tried a few contrived, performance-intensive apps on my iPhone and they've still performed very well. I'd be interested to see its performance on Android (typically lower throughput per core), but I don't have any Android devices. ---------------------------------------------------------------------------------------------------- [00:10:31] Jamie Gaskins(@jgaskins):Despite that, I still focus hard on performance because I really like fast apps. ---------------------------------------------------------------------------------------------------- [00:11:37] LeoDaoTao(@LeoDaoTao):Yeah, that is what convinced me to try Clearwater, that and my hate for JS :-) ---------------------------------------------------------------------------------------------------- [00:12:44] Jamie Gaskins(@jgaskins):hehe ---------------------------------------------------------------------------------------------------- [00:15:18] LeoDaoTao(@LeoDaoTao):so far it looks really cool but have no idea how to even do basic things in Clearwater yet :-) ---------------------------------------------------------------------------------------------------- [00:15:49] Jamie Gaskins(@jgaskins):Yeah, that's what I'm hoping to fix with the Clearwater docs site, but it's still very much WIP: https://clearwater-docs.herokuapp.com ---------------------------------------------------------------------------------------------------- [00:17:29] Jamie Gaskins(@jgaskins):That's a Clearwater app on Roda using the `Roda::OpalAssets`gem to compile. ---------------------------------------------------------------------------------------------------- [00:17:45] LeoDaoTao(@LeoDaoTao):is the ToDo MVC demo app a good place to start? ---------------------------------------------------------------------------------------------------- [00:18:21] Jamie Gaskins(@jgaskins):Possibly. I can't remember if it's up-to-date. Lemme check. ---------------------------------------------------------------------------------------------------- [00:19:06] Jamie Gaskins(@jgaskins):Yeah, looks like it's in pretty good shape. It's on 1.0.0.rc1. ---------------------------------------------------------------------------------------------------- [00:19:20] LeoDaoTao(@LeoDaoTao):Cool will start with that then, thank you! ---------------------------------------------------------------------------------------------------- [00:19:47] Jamie Gaskins(@jgaskins):No worries, lemme know if you've got any more questions ---------------------------------------------------------------------------------------------------- ############################## [2016-07-22] ############################## [18:45:47] Forrest Chang(@fkchang):@jgaskins so in doing roda-opal_assets, have you learned enough about sprockets to apply it to something not ruby based, i.e. been interested in doing some messing around kemal/opal both for performance, and built in websocket support ---------------------------------------------------------------------------------------------------- ############################## [2016-07-23] ############################## [21:10:45] Jamie Gaskins(@jgaskins):@fkchang I've been wondering about things like this, too, to be able to compile your client-side Ruby assets from outside your running server-side Ruby process. If you're outside the process, compilation can be a one-line command: `ruby #{gems.map { |gem_name| "-r#{gem_name} " }.join} -S opal #{asset_paths.map { |path| "-I#{path} " }.join} -c #{app_file} > #{output_file}` ---------------------------------------------------------------------------------------------------- [21:16:08] Jamie Gaskins(@jgaskins):However, to make use of Sprockets file caching (the `tmp/cache/sprockets` directory in Rails apps) to speed up subsequent compilation in development, that's a bit more involved. Sprockets defaults to an in-memory cache, so once the app reboots (in the case of a CLI app, this would be every single compilation), the cache is empty and every single asset would be recompiled along with all of its dependencies. I'm working on adding a feature to `Roda::OpalAssets` to be able to use a file cache, but I haven't seen any first-compile performance improvements yet. ---------------------------------------------------------------------------------------------------- ############################## [2016-07-24] ############################## [22:20:11] Elia Schito(@elia):@jgaskins @fkchang I'm in the process of extracting sprockets to opal-sprockets to better support different versions and update the core more rapidly, that's FYI – also if you think there's something that can be added or can improve the CLI (eg. caching) let me know ---------------------------------------------------------------------------------------------------- [22:31:19] Jamie Gaskins(@jgaskins):@elia Cool deal, thanks. Does this mean that we won't be able to assume that if Opal is loaded that Sprockets is also loaded? ---------------------------------------------------------------------------------------------------- [22:33:52] Jamie Gaskins(@jgaskins):Just trying to figure out if I'll realistically need to update anything. ---------------------------------------------------------------------------------------------------- [22:41:12] Elia Schito(@elia):yeah, the basic idea is that you'll have to require `opal/sprockets` too ---------------------------------------------------------------------------------------------------- [22:43:11] Elia Schito(@elia):I'd like to push a patch release of 0.10 that will complaint unless `opal-sprockets` (the gem) is available and have a empty version of that, so everyone has a chance to be ready for 0.11 ---------------------------------------------------------------------------------------------------- [22:45:43] Jamie Gaskins(@jgaskins):Cool. Am I right in assuming that this is only if we're doing our own compilation? That is, if I'm using `opal-rails`, will that take care of loading `opal-sprockets` for me? ---------------------------------------------------------------------------------------------------- [22:46:21] Elia Schito(@elia):that's for sure, yeah, only if you're using opal directly ---------------------------------------------------------------------------------------------------- [22:46:48] Elia Schito(@elia):ideally that should open for opal-webpack etc. ---------------------------------------------------------------------------------------------------- [23:04:16] Jamie Gaskins(@jgaskins)::+1: ---------------------------------------------------------------------------------------------------- ############################## [2016-07-27] ############################## [22:42:27] HereC(@ericbeland):@jgaskins I've been looking at Clearwater and I'm trying to find an example app that helps me understand how to use Clearwater with Rails with real data coming from activerecord. Is there something I can look at in this regard? ---------------------------------------------------------------------------------------------------- [23:27:16] Jamie Gaskins(@jgaskins):@ericbeland Getting started with Rails is quite simple, but you can't get data directly from ActiveRecord into a Clearwater app. It's just like retrieving data from any API: fetch some JSON via AJAX, parse it, store it somewhere, then re-render. I usually use a [`GrandCentral`](https://github.com/clearwater-rb/grand_central) store to keep track of models in my Clearwater apps, but you could use a hash or component state (for the root component and routing targets only). Here's an example Clearwater app to fetch data from the GitHub API: https://gist.github.com/jgaskins/da9fa65ac20809f17db58024197797f0 ---------------------------------------------------------------------------------------------------- [23:30:27] Jamie Gaskins(@jgaskins):Fetching data from a remote API is very simple in Clearwater: `Bowser::HTTP.fetch(url).then { |response| store(Model.new(response.json)) }` and re-render with `app.render` or just `call` within a component once you've stored it. ---------------------------------------------------------------------------------------------------- ############################## [2016-07-28] ############################## [09:21:09] Torsten Rüger(@dancinglightning):@elia related that opal-sprockts, would it be easy to make a path option where the client code lives? Especially in rails, spread out under app/assets/xxx makes it so second class. ---------------------------------------------------------------------------------------------------- [13:57:42] Jamie Gaskins(@jgaskins):@dancinglightning In Rails, you can do `Opal.append_path 'client'` in an initializer or something. I'm not sure if you can do that after the change because it might change how the Sprockets integration is loaded, but it's something you can do currently. I've put shared client/server code in `app/shared` before and added that to the Opal path that way. ---------------------------------------------------------------------------------------------------- [14:05:06] Jamie Gaskins(@jgaskins):But I've seen a lot of people put client-side apps in a `client` directory under the app root directory in both Node and Rails and I think it's a pretty good idea. ---------------------------------------------------------------------------------------------------- [14:29:11] Torsten Rüger(@dancinglightning):@jgaskins yes. I had no doubt it was possible ---------------------------------------------------------------------------------------------------- [14:30:29] Torsten Rüger(@dancinglightning):I meant to suggest some kind of convention. As in the rails way, convention over configuration. ---------------------------------------------------------------------------------------------------- [15:23:36] HereC(@ericbeland):@jgaskins Thanks a lot for the example--it helps a lot! Also the tip on how to re-render helps as well. As the number of clearwater models grow, is there a convention on where to put them? ---------------------------------------------------------------------------------------------------- [15:28:03] HereC(@ericbeland):I have a rails/ember app at the moment, and I find it a pain to work with/maintain. My dream is to use clearwater, eagerly load most models into the datastore in the background on first load, and keep a websocket open to invalidate/reload them if some external change updates one. Not sure on the plans for the rails demo app, but that's my dream. ---------------------------------------------------------------------------------------------------- ############################## [2016-07-29] ############################## [04:23:28] Jamie Gaskins(@jgaskins):@dancinglightning Totally, I would love to see a convention for Rails apps for that. Calling it `assets/javascripts` is awkward if you're not writing JavaScript for it. :-) And since it's an entirely different app from your back end, it makes sense to keep it in a separate place. I think `client` makes sense since Rails already claims the `app` directory. ---------------------------------------------------------------------------------------------------- [04:28:22] Jamie Gaskins(@jgaskins):@ericbeland I've done some eager loading (via `gon`) and websocket stuff with `opal-pusher` (full disclosure, I wrote `opal-pusher`). It can be pretty sweet. Regular WebSocket support is also available in 'bowser`. I'm working on a docs site for some of these things, as well. ---------------------------------------------------------------------------------------------------- [18:08:54] Torsten Rüger(@dancinglightning):@jgaskins i think client is a good name too, let’s hope elia is still listening :-) ---------------------------------------------------------------------------------------------------- [18:13:31] Torsten Rüger(@dancinglightning):About pusher: Saw a demo at Brighton ruby and was impressed, sounds like a very good way to go for chat / message sending. Bowser seems also nice, especially the mimimal aspect. Would be nice to have size figures about browser/bowser/opal-jquery (are there others?) ---------------------------------------------------------------------------------------------------- ############################## [2016-07-30] ############################## [01:30:40] Mitch VanDuyn(@catmando):Reactive-record has a default pusher configuration. Pusher us pretty cool ---------------------------------------------------------------------------------------------------- [02:01:12] Jamie Gaskins(@jgaskins):@dancinglightning Here's a quick size comparison of `opal-browser` vs `bowser`: ``` -rw-r--r-- 1 jamie staff 47K Jul 29 21:59 opal-browser.js.gz -rw-r--r-- 1 jamie staff 6.1K Jul 29 21:55 bowser.js.gz ``` That's each library's base install, minified and gzipped. ---------------------------------------------------------------------------------------------------- [02:05:55] Jamie Gaskins(@jgaskins):`opal-browser`'s base payload is 7.7x the size of `bowser` across the wire in production. Doesn't mean it's bad, it's just a much richer set of APIs than you need in a virtual-DOM-based app. The amount of direct interaction you end up actually doing with the DOM in a Clearwater app is minimal, but it does support what you're likely to need and uses `method_missing` to proxy calls to native JS DOM and event APIs for what it doesn't support. ---------------------------------------------------------------------------------------------------- [02:07:32] Jamie Gaskins(@jgaskins):I haven't checked `opal-jquery` in a long time, but given that you have to load the jQuery JS in addition to its Ruby bindings, it's likely to be even larger. ---------------------------------------------------------------------------------------------------- [02:37:22] Jamie Gaskins(@jgaskins):@dancinglightning Regarding Pusher, when I was at [OrderUp](https://orderup.com), we used Pusher for damn near everything we did because food delivery is a very real-time business. One of our front-end apps let you watch your delivery driver's location in real time on a Google Map, a lot like how with Uber you can see your driver on their way to pick you up. When I ported it from the original Backbone we wrote it in over to Clearwater, it resulted in less code, _clearer_ code, faster rendering, better UX (CSS transitions we didn't realize weren't working suddenly started working), etc. ---------------------------------------------------------------------------------------------------- [05:27:56] Jeff Dickey(@jdickey):@jgaskins that's pretty amazing. I used to call that "elated embarrassment", when things you didn't realise weren't working suddenly did. Couple funny stories there about why that's in the order it is, but oh well. The last time I hit that personally, it was the final straw that allowed us to implement end-to-end TDD over a very TDD-hostile CTO. Clearwater looks great and continues to improve; *excited!* ---------------------------------------------------------------------------------------------------- [16:34:04] Jamie Gaskins(@jgaskins):@jdickey Thanks! I'm really glad you're enjoying it. ---------------------------------------------------------------------------------------------------- [16:36:54] Jamie Gaskins(@jgaskins):In our case, the transitions we didn't realize weren't working was caused by Backbone replacing entire DOM nodes, whereas Clearwater can just update their content and attributes. So the transitions the designer wrote never worked at all, so we didn't even know they were there. :-) ---------------------------------------------------------------------------------------------------- [16:39:28] Jamie Gaskins(@jgaskins):They weren't an important part of the UI, just for a little finesse between state transitions, so it never really caught anyone's attention. ---------------------------------------------------------------------------------------------------- ############################## [2016-07-31] ############################## [15:02:46] Jeff Dickey(@jdickey):@jgaskins oh, $h!t; that would piss off the designer and the customer who believed the song and dance that the designer performed for him, I should think. You've given me a nice howitzer shell for my ongoing discussion with a quasi-technical stakeholder about "why don't you just use Backbone for everything?" I could see how that "never really caught anyone's attention" would work; many times, people are just thrilled to have something that does _something._ Thanks again. ---------------------------------------------------------------------------------------------------- [17:11:07] Jamie Gaskins(@jgaskins):lol ---------------------------------------------------------------------------------------------------- [17:23:36] Jamie Gaskins(@jgaskins):Yeah, when you have to manage all your own UI mutation with Backbone, getting the same UX that Clearwater gives you for free takes a lot more manual effort (IME, about 1.5-2x in the short term, much higher long-term). :-) ---------------------------------------------------------------------------------------------------- ############################## [2016-08-01] ############################## [02:20:02] Keenan Brock(@kbrock):@jgaskins in your clearwater projects, do you tend to have html (e.g.: navigation) in your `application.html.erb`? Or does it tend to just be: `<%= yield %>` (with application js tag in the head) ---------------------------------------------------------------------------------------------------- [02:36:24] Mitch VanDuyn(@catmando):@jdickey don't know if you saw this little slide that @fkchang posted with results from catprint.com where we have increased our functionality a lot, while reducing our code base a lot, and simplifying our lives by doing every thing in ruby. https://slides.com/mitchvanduyn/deck-6/live#/ This was all reactrb, but honestly it would apply to clearwater as well. Maybe it can help make your case... ---------------------------------------------------------------------------------------------------- [07:34:22] Jeff Dickey(@jdickey):@catmando thanks; this does look very helpful. I've been dreaming for 37 years of working in a shop that Gets It On (Almost) Everything; by the process of elimination, amassing an argument that I'm going to have to build such a beast myself :P ---------------------------------------------------------------------------------------------------- [13:17:05] Jamie Gaskins(@jgaskins):@kbrock I usually put the JS tag inside the body instead of the head so the element I want to render into exists when it executes. Otherwise, I think it depends on the app. At OrderUp, we already had a lot of layout templates done server-side, so we kept them and the Clearwater app root components were pretty simple — they just delegated to other components and the routing `outlet`. It's probably a good idea to indicate to the user in the HTML that the app is loading, either with a loading message or "splash screen" kind of thing. Parse/execute takes 70-90ms in Safari on my machine (a fair bit higher in Chrome), but it still has to be downloaded unless cached. ---------------------------------------------------------------------------------------------------- [13:18:25] Jamie Gaskins(@jgaskins):If you're preloading some of your app state with something like `gon`, I'd _definitely_ add a loading indicator because that adds even more time before the app gets loaded. ---------------------------------------------------------------------------------------------------- [14:01:12] Keenan Brock(@kbrock):@jgaskins thanks ---------------------------------------------------------------------------------------------------- [14:29:02] Jamie Gaskins(@jgaskins):@catmando @fkchang That's a pretty nice chart. It's pretty great when you end up with less code. Every JS app I've ported to Clearwater has resulted in significantly less code, both LoC in the front-end app than the JS version and in overall JS payload size, and has taken significantly less time to write. ---------------------------------------------------------------------------------------------------- [15:21:35] Mitch VanDuyn(@catmando):Absolutely ---------------------------------------------------------------------------------------------------- ############################## [2016-08-02] ############################## [02:04:53] Keenan Brock(@kbrock):@jgaskins I was looking at https://gist.github.com/jgaskins/da9fa65ac20809f17db58024197797f0 and wondering, why did you have a method `user_list` instead of having that as a clearwater component? ---------------------------------------------------------------------------------------------------- [12:08:30] Jamie Gaskins(@jgaskins):@kbrock Because it was ---------------------------------------------------------------------------------------------------- [12:08:35] Jamie Gaskins(@jgaskins):gah ---------------------------------------------------------------------------------------------------- [12:08:52] Jamie Gaskins(@jgaskins):@kbrock because it made the demo easier to read :-) ---------------------------------------------------------------------------------------------------- [12:09:45] Jamie Gaskins(@jgaskins):realistically, i would have a UserList component for the list itself and a UserListItem for each element in the list. ---------------------------------------------------------------------------------------------------- [12:10:15] Jamie Gaskins(@jgaskins):that also makes caching at multiple levels of granularity easy ---------------------------------------------------------------------------------------------------- [12:12:34] Jamie Gaskins(@jgaskins):but for demo/example code, having multiple classes kinda clutters things a bit. The extracted method is much less noisy. ---------------------------------------------------------------------------------------------------- [14:09:55] Keenan Brock(@kbrock):@jgaskins thanks so much. Was wondering if there was some other issue I was missing. Still new with this stuff ---------------------------------------------------------------------------------------------------- [18:59:18] Jamie Gaskins(@jgaskins):@kbrock All good. Mostly, I try to apply typical Ruby refactoring techniques — extract methods, classes, method objects, etc. Then I can also ensure that I meet caching needs by extracting other components from that, as well. ---------------------------------------------------------------------------------------------------- ############################## [2016-08-03] ############################## [22:39:37] Elia Schito(@elia):@dancinglightning @jgaskins was reading about putting opal stuff in `client/` and it's not a problem, under rails it's enough to add `Rails.root.join('client').to_s` to sprockets path, you only need to be aware that if you instead put stuff in `app/something` those dirs may fall under eagerloading in production/test and try to require all your opal files that end in `.rb`. ---------------------------------------------------------------------------------------------------- ############################## [2016-08-05] ############################## [01:41:32] Jamie Gaskins(@jgaskins):Good point. ---------------------------------------------------------------------------------------------------- ############################## [2016-08-07] ############################## [16:53:56] Jamie Gaskins(@jgaskins):Just added asset precompilation for `Roda::OpalAssets` in https://github.com/clearwater-rb/roda-opal_assets/pull/2. I ported the [Clearwater docs site](https://clearwater-docs.herokuapp.com) to use that branch and it loads _a lot_ faster on first request. ---------------------------------------------------------------------------------------------------- ############################## [2016-08-08] ############################## [22:35:11] Jamie Gaskins(@jgaskins):It's still not _quite_ as trivial to use as the Rails asset pipeline, but it's not far behind it. You still have to add your own `assets:precompile` Rake task, for example, but it's easy to get it going in development. ---------------------------------------------------------------------------------------------------- ############################## [2016-08-16] ############################## [03:54:34] Jamie Gaskins(@jgaskins):I rewatched [DHH's ActionCable video](https://www.youtube.com/watch?v=n0WUjGkDFS0) last night and today had a go at implementing it with Clearwater. I managed to do it much more cleanly and with less code. I'll try to remember to post it tomorrow. ---------------------------------------------------------------------------------------------------- ############################## [2016-08-18] ############################## [15:17:47] Jamie Gaskins(@jgaskins):I tried recording a screencast about it last night but I kept screwing up. I'll try again tonight. ---------------------------------------------------------------------------------------------------- [15:26:03] Torsten Rüger(@dancinglightning):I'm definitely interested. I also watched the cable video and while i think it's nice that rails is making an effort on the client, i couldn't shake the feeling of clunkyness. Looking forward to your video, and seeing a better way. ---------------------------------------------------------------------------------------------------- [16:25:49] Forrest Chang(@fkchang):@jgaskins I too want to encourage you to make it, both curious myself as to how the code would look and also hoping it makes for something that will get the word out on clearwater and opal in general, though in general I'm rather discouraged on evangelism these dayss ---------------------------------------------------------------------------------------------------- ############################## [2016-08-19] ############################## [04:01:21] Jamie Gaskins(@jgaskins):Alrighty, [screencast is up](https://youtu.be/tSuEuPzkxaU)! @dancinglightning @fkchang ---------------------------------------------------------------------------------------------------- [07:24:55] Torsten Rüger(@dancinglightning):@jgaskins that’s great. Nice and clean. And even with the redis pub/sub. really is not much code is it :-) ---------------------------------------------------------------------------------------------------- [07:27:34] Torsten Rüger(@dancinglightning):Slight editing would make a relatively big difference: cutting the first minute, the breathing at minute 4 and the debugging at 8. But great to see how easy it is. ---------------------------------------------------------------------------------------------------- [11:53:50] Jamie Gaskins(@jgaskins):Crap, i uploaded the unedited version. I'll swap it out later. ---------------------------------------------------------------------------------------------------- [11:55:39] Jamie Gaskins(@jgaskins): ---------------------------------------------------------------------------------------------------- [11:56:01] Jamie Gaskins(@jgaskins): ---------------------------------------------------------------------------------------------------- [11:59:46] Jamie Gaskins(@jgaskins):Oh, damn. That's the one I didn't want to upload because I kept screwing up. ---------------------------------------------------------------------------------------------------- [12:00:02] Jamie Gaskins(@jgaskins):I'm uploading the right one now. ---------------------------------------------------------------------------------------------------- [12:02:32] Jamie Gaskins(@jgaskins):It'll be available at [this new link](https://youtu.be/_ycYRs3EWCE) ---------------------------------------------------------------------------------------------------- [15:36:22] Jamie Gaskins(@jgaskins):@dancinglightning @fkchang The correct video is up now ---------------------------------------------------------------------------------------------------- [15:40:18] Torsten Rüger(@dancinglightning):@jgaskins yes, thanks. Just on the road, but will watch later ---------------------------------------------------------------------------------------------------- [15:47:56] Jamie Gaskins(@jgaskins)::+1: ---------------------------------------------------------------------------------------------------- [16:33:12] Jeff Dickey(@jdickey):@jgaskins, nice videos…one thing I am noticing with all your videos, though, is that your volume is really, really low. I have to turn my volume up to ~90% to even hear your words clearly, which makes any other notification sounds (like Gitter) just blast out everybody around. You may want to pay attention to that in future. Nice introduction to Clearwater+Websockets+Redis+Sidekiq, though; it's going to help me scratch a few itches here shortly :) ---------------------------------------------------------------------------------------------------- [16:55:00] Jamie Gaskins(@jgaskins):@jdickey Awesome. I wonder if my mic is just too low for normal chatter. It's been used almost exclusively for gaming, during which I'm usually a lot more enthusiastic so I've had to keep it low. :-) I'll keep it in mind. I also didn't do any editing. I think YouTube has some editing/normalization tools, so maybe I can edit it without reuploading. ---------------------------------------------------------------------------------------------------- [16:56:26] Jamie Gaskins(@jgaskins):I'm glad you like the video, though. I'll try to make some more. A couple friends are looking into Clearwater to help out with documentation. ---------------------------------------------------------------------------------------------------- [16:56:34] Jamie Gaskins(@jgaskins):So some of this is for them as well, but I like showing off realistic apps with Clearwater so people know it's not just a toy. ---------------------------------------------------------------------------------------------------- [16:59:45] Jeff Dickey(@jdickey):I agree that that "showing off…so people know it's not just a toy" is important. There have been far too many promising tools in the Ruby community (among others, no doubt) over the years that have had one or two great releases and then fallen into the Great Abyss. Once I get my present workload re-calibrated (or go find a new workload), I'd love to help out too. The Node people are right about one thing: being able to use the same language *effectively* through your entire stack just makes life _so_ much easier. ---------------------------------------------------------------------------------------------------- [17:05:40] Mitch VanDuyn(@catmando):that is our experience too, *and* ruby makes it even better... ---------------------------------------------------------------------------------------------------- [18:04:05] Jamie Gaskins(@jgaskins):One thing I've noticed is that when a Rubyist is learning front-end development, they have to learn JS _and_ a framework _and_ the browser APIs, which is massive cognitive load all at once. Letting them learn front-end development in a language they already know has _huge_ benefits. ---------------------------------------------------------------------------------------------------- [18:06:23] Jamie Gaskins(@jgaskins):And with Clearwater, you can start writing apps with no knowledge needed of front-end development, browser APIs, or anything but a little bit of Ruby and a passing familiarity with HTML (basically, how tags are structured and what some of their names are). ---------------------------------------------------------------------------------------------------- [18:06:53] Mitch VanDuyn(@catmando):yes! We have a relatively new apprentice with no former SW experience, and I think she would agree that just learning one language, one standard library, and one framework has flattened the learning curve. ---------------------------------------------------------------------------------------------------- [18:07:18] Mitch VanDuyn(@catmando):I think we forget how big a part the standard library plays in day to day development. ---------------------------------------------------------------------------------------------------- [18:07:19] Mitch VanDuyn(@catmando):sure ---------------------------------------------------------------------------------------------------- [18:08:12] Mitch VanDuyn(@catmando):```ruby def foo(blat) blat + blat * 52 end ``` ---------------------------------------------------------------------------------------------------- [18:08:19] Mitch VanDuyn(@catmando):doesn't look a whole lot different from ---------------------------------------------------------------------------------------------------- [18:08:58] Mitch VanDuyn(@catmando):```javascript var foo = function(blat) { blat + blat * 52; } ``` ---------------------------------------------------------------------------------------------------- [18:09:10] Mitch VanDuyn(@catmando):but what if you need to do this: ---------------------------------------------------------------------------------------------------- [18:12:01] Mitch VanDuyn(@catmando):```ruby def every_nth_item(n) (n - 1).step(a.size - 1, n).map { |i| a[i] } end ``` ---------------------------------------------------------------------------------------------------- [18:12:10] Mitch VanDuyn(@catmando):I guess it looks about like this? ---------------------------------------------------------------------------------------------------- [18:17:04] Mitch VanDuyn(@catmando):```javascript var every_nth_item = function(n) { var result = [] for(var i=n-1;i`) and simply delegate to the native version for the rest with `method_missing` after camelCasing the method name, which is perfect for properties that return primitives. ---------------------------------------------------------------------------------------------------- ############################## [2016-09-09] ############################## [23:34:20] LeoDaoTao(@LeoDaoTao):@jgaskins have you seen this: http://stack.formidable.com/radium/ I wonder if something similar could be utilized with Clearwater for component styling. ---------------------------------------------------------------------------------------------------- ############################## [2016-09-10] ############################## [00:08:17] Jamie Gaskins(@jgaskins):@LeoDaoTao I've thought about that a lot. I do all my styles in Ruby and not being able to use native hover styles is sometimes pretty frustrating. Implementing hover state in Ruby involves reimplementing what the browser already does. It seems that Radium wraps the component class in a higher-order component that modifies the `render` return value of the wrapped component, updating its own component state with `onMouseEnter` / `onMouseLeave` events. ---------------------------------------------------------------------------------------------------- [00:11:14] LeoDaoTao(@LeoDaoTao):@jgaskins so what’s your solution for hover styles? Do you just use external CSS for that? ---------------------------------------------------------------------------------------------------- [00:11:59] Jamie Gaskins(@jgaskins):It's doable in Clearwater, but will require a little extra hackery because Clearwater components don't re-render themselves on their own; the entire app has to re-render. We can use a combination of `BlackBoxNode` and Clearwater's support for multiple apps on a page to make it work, though. Basically, a Clearwaterized Radium component would be a `BlackBoxNode` that renders a nested Clearwater app. ---------------------------------------------------------------------------------------------------- [00:12:18] Jamie Gaskins(@jgaskins):I usually just use real CSS for that, yeah. :-\ ---------------------------------------------------------------------------------------------------- [00:12:53] LeoDaoTao(@LeoDaoTao):I wonder if that hackery would be worth it though, it’s extra overhead ---------------------------------------------------------------------------------------------------- [00:13:28] Jamie Gaskins(@jgaskins):It is, but if we did the `BlackBoxNode` approach, it could re-render that component on its own. :-) ---------------------------------------------------------------------------------------------------- [00:14:11] LeoDaoTao(@LeoDaoTao):something for version 2.0 then :-) ---------------------------------------------------------------------------------------------------- [00:14:39] Jamie Gaskins(@jgaskins):lol Yeah, I'd definitely like to try it out. ---------------------------------------------------------------------------------------------------- [00:16:06] LeoDaoTao(@LeoDaoTao):Now I’m wondering if I should put all my CSS in external stylesheets, or just the pseudoclass stuff :-) I do like keeping the style with the component though for isolation. ---------------------------------------------------------------------------------------------------- [00:17:40] Jamie Gaskins(@jgaskins):I love keeping everything self-contained. It means everything that has to do with that component is right there in the same file. The only things I put in CSS (and I document them in the component class' `Style` module) are pseudo classes and `@keyframes` animations. ---------------------------------------------------------------------------------------------------- [00:18:24] LeoDaoTao(@LeoDaoTao):I think I’ll do the same ---------------------------------------------------------------------------------------------------- [00:18:32] LeoDaoTao(@LeoDaoTao):Thank you again for all your help over the last few days, I’m slowly starting to understand Clearwater :-) ---------------------------------------------------------------------------------------------------- [00:19:43] Jamie Gaskins(@jgaskins):If you have any extra insight or if you find another way of organizing things like that, feel free to discuss it here. I mainly know only what I've tried, so hearing other people's experiences is helpful! :-) ---------------------------------------------------------------------------------------------------- [00:20:45] Jamie Gaskins(@jgaskins):Granted, I've tried a _lot_ of things with Clearwater over the past nearly 2 years, but I'm not foolish enough to believe I know every use case. ---------------------------------------------------------------------------------------------------- [00:20:47] LeoDaoTao(@LeoDaoTao):sure will do :-) have a few more projects coming up and I will use Clearwater for them, so I’m sure to have some input ---------------------------------------------------------------------------------------------------- [00:20:53] Jamie Gaskins(@jgaskins):Awesome! ---------------------------------------------------------------------------------------------------- ############################## [2016-09-14] ############################## [16:05:25] Jamie Gaskins(@jgaskins):@johnsusi Like what? ---------------------------------------------------------------------------------------------------- [16:05:37] Jamie Gaskins(@jgaskins):Honest question, I'd like to know what the pain points are. :-) ---------------------------------------------------------------------------------------------------- [16:07:04] John Susi(@johnsusi):the main issue is with responsiveness. if i click a button something has to happen fast but if a view takes say 3-400ms to render then it's way to slow so we hide it by doing a two-step update, first something that is fast and then load the real view in a second render ---------------------------------------------------------------------------------------------------- [18:41:33] Jamie Gaskins(@jgaskins):@johnsusi That depends on what's taking all that time. Is it just the rendering step of the new state or is it the calculation of that new state? ---------------------------------------------------------------------------------------------------- [18:55:44] Jamie Gaskins(@jgaskins):You can check how long the app took to generate new vdom nodes and how long it took to diff/patch by calling `debug!` on your `Application` instance. If rendering itself is slow, there may be a few things that can help. I need to document them better (if at all), but they may help: - provide a `key` property to lists of child nodes (or a `key` method for `CachedRender` components) if they are frequently sorted or filtered (otherwise, it's potentially slower because DOM nodes can't be reused by other components). For example: `ul(sorted_items.map { |item| li({ key: item.id }, item.name) })`. With this defined, it can just reorder the child nodes and doesn't need to patch every DOM node. - use immutable models ([`GrandCentral` provides these](https://github.com/clearwater-rb/grand_central#models)) to store your app state — invalidation of render caches can be just an identity check on components using immutable models ---------------------------------------------------------------------------------------------------- [20:22:18] Jamie Gaskins(@jgaskins):If it takes a long time to render simply because the diff from state A to state B is huge (thousands of nodes created on first render, for example), that's annoying, definitely. I wonder if there's a good way to do partial diffing that would work with Clearwater's render caching and be completely transparent. I'll add an issue for that because I'm actually pretty interested in this problem. ---------------------------------------------------------------------------------------------------- [14:12:21] John Susi(@johnsusi):@jgaskins: you mentioned using BlackBoxNode for rerendering parts of the application. Is that something you would recommend or is it just an idea? ---------------------------------------------------------------------------------------------------- [14:12:50] John Susi(@johnsusi):I'm looking for something similiar to container components in react/redux ---------------------------------------------------------------------------------------------------- [15:17:58] Jamie Gaskins(@jgaskins):@johnsusi Hmm, I thought I wrote about it here. It's probably sitting unsent in a text box in a forgotten browser tab on my machine at home. Anyway, it turns out it's not a very simple process to re-render just a single component (and its subtree) in Clearwater. I really like the idea of re-rendering everything when something changes for several reasons but I don't want it to be enforced, just encouraged. Clearwater has relatively few opinions until I'm confident enough that I've found the best patterns for most apps. Although I've found some great patterns for a lot of apps, they're still just ones _I've_ been using and maybe not discussing enough with other people who might've found other ways to do things. I haven't found I need anything like container components to store state other than in my routing targets and root component, but your use case is also very different from all of mine — all of my Clearwater apps just run in a browser. :-) I don't think `BlackBoxNode` is the best idea for rendering subtrees, at least not directly. I tried it and it's really gnarly. I'd like to provide a better abstraction for it (it could probably be simplified a _lot_), but I probably won't be able to get to it until this weekend. ---------------------------------------------------------------------------------------------------- [16:04:51] John Susi(@johnsusi):Yeah i see your point. Ideally everything should be rerendered from top to bottom but I see more and more 'hacks' to hide latency while rendering in our app. ---------------------------------------------------------------------------------------------------- ############################## [2016-09-15] ############################## [04:18:47] Jonas Tehler(@jegt):@jgaskins One scenario is that we use tabs (similar to browser tabs) in our app. When a user wants to switch from one tab to another and the new tab contains for example a large list of data then we need to first display a spinner and then do a second render or else there would be no immediate feedback from clicking on the new tab. ---------------------------------------------------------------------------------------------------- [05:14:41] LeoDaoTao(@LeoDaoTao):@jgaskins Any tips on seting up transition effects? For example if I want to fade out a removed DOM node? ---------------------------------------------------------------------------------------------------- [07:25:41] John Susi(@johnsusi):@jgaskins Good pointers, I'm a big fan of immutable data but as @jegt said, our main problem is when being hit by a large amount of new nodes to render. I guess caching could remove the need for "local" rerenders but we still have to stagger the amount of changes we do on a render somehow. ---------------------------------------------------------------------------------------------------- [15:15:54] Jamie Gaskins(@jgaskins):@johnsusi @jegt Oh, definitely, navigation that causes a huge DOM change is rough. The good news is that that's the exact use case I was trying to solve with #52 — swapping between two tabs with a lot of DOM underneath them was rough, but allowing people to incrementalize those changes is a small step toward. I haven't cut a release with that change yet, so you may need to use a `github: 'clearwater-rb/clearwater'` source until I can. I remember you couldn't use the `Clearwater::Router` as written, but I don't think that change will affect your router modifications (speaking of which, maybe we should include a `Clearwater::HashRouter`with your changes to be able to support Electron and older IE?). ---------------------------------------------------------------------------------------------------- [15:21:05] Jamie Gaskins(@jgaskins):@LeoDaoTao There's no first-class way of doing this yet, but it's something I'd like to add if it doesn't impose any assumptions on components. Usually I do this as two renders: one to mark the item as being deleted, the second render deletes it: ```ruby def render ul(items.map { |item| if deleting? item DeletingListItem.new(item) else ListItem.new(item) end }) end def delete(item) mark_as_deleting item call # Re-render # Run the deletion after the fade completes Bowser.window.delay(fade_duration) do actually_delete item call end end ``` ---------------------------------------------------------------------------------------------------- [15:24:21] Jamie Gaskins(@jgaskins):@LeoDaoTao It's one of those things where Clearwater renders the current state of the app, and you don't go straight from existing->deleted. You go from exists->deleting->deleted, so it's really a multi-phase process. This could be automated better, and I've got ideas for how to do that easily with GrandCentral if you'd like to chat about that. Unfortunately there's nothing great built into Clearwater to call a chain of state transitions in the UI. ---------------------------------------------------------------------------------------------------- [17:08:49] LeoDaoTao(@LeoDaoTao):@jgaskins I think this will work great for my current situation. I would love to talk to you about your GrandCentral solution for my next app. It will have much more transitions to work with. ---------------------------------------------------------------------------------------------------- ############################## [2016-09-16] ############################## [13:15:49] Jamie Gaskins(@jgaskins):@LeoDaoTao Awesome, looking forward to it! ---------------------------------------------------------------------------------------------------- [14:17:54] John Susi(@johnsusi):@jgaskins I'm playing around with webpack and opal-webpack and it has some issues when requiering native javascript libraries. Perhaps virtual_dom.js could be optional or I could submit a PR that works with webpack ---------------------------------------------------------------------------------------------------- [14:22:43] Jamie Gaskins(@jgaskins):@johnsusi Interesting. Is it possible that `virtual_dom.js` being built with Browserify instead of Webpack could be causing that? If so, I did a bunch of work in #48 to Webpackify it all so another JS library could be used along with `virtual-dom`. I might go ahead and port it all over. ---------------------------------------------------------------------------------------------------- [14:22:50] Mitch VanDuyn(@catmando):We have pretty good success auto importing webpack stuff into reactrb if you want to look at the sources there ---------------------------------------------------------------------------------------------------- [14:23:08] Jamie Gaskins(@jgaskins):I only used Browserify from the start because it didn't require any config. ---------------------------------------------------------------------------------------------------- [14:23:45] John Susi(@johnsusi):basicly I had to do this to get it working at runtime %x{ global.virtualDom = require('./virtual_dom/js/virtual_dom.js'); } ---------------------------------------------------------------------------------------------------- [14:25:12] John Susi(@johnsusi):@jgaskins: we have problems with more libraries so I don't think it's a problem on your end. Could be that the libraries detect "node" when run through webpack and don't export globals then ---------------------------------------------------------------------------------------------------- [14:27:30] John Susi(@johnsusi):@catmando: will take a look, I'm using a fork of zetachang's opalrb-loader after all :) ---------------------------------------------------------------------------------------------------- [14:28:27] Jamie Gaskins(@jgaskins):@johnsusi Possible. This is an interesting problem, though. I'll give it a look, as well. It's been a while since I played with Webpack and Opal together. For the most part, just been using Sprockets. :-) ---------------------------------------------------------------------------------------------------- [14:28:36] Mitch VanDuyn(@catmando):Moved on a long way but yeah... It's a file called native library ---------------------------------------------------------------------------------------------------- [14:28:54] Mitch VanDuyn(@catmando):Should be adaptable to your needs ---------------------------------------------------------------------------------------------------- [14:30:12] Mitch VanDuyn(@catmando):Basically monkey patches to const and method missing that brings the JS objects into Opal name space ---------------------------------------------------------------------------------------------------- [14:32:48] John Susi(@johnsusi):working with ruby and not being a rails developer is hard... sigh :) ---------------------------------------------------------------------------------------------------- [14:33:11] Jamie Gaskins(@jgaskins):lol ---------------------------------------------------------------------------------------------------- [14:36:43] Mitch VanDuyn(@catmando):What r using for back end? ---------------------------------------------------------------------------------------------------- [14:36:56] John Susi(@johnsusi):nothing :) ---------------------------------------------------------------------------------------------------- [14:38:47] John Susi(@johnsusi):I'm just trying to figure out a way to use opal and clearwater in a single page app with working source maps etc ---------------------------------------------------------------------------------------------------- [14:40:41] Jamie Gaskins(@jgaskins):Oh, right, since you're not using Sprockets to compile, do source maps not work by default? ---------------------------------------------------------------------------------------------------- [14:41:58] John Susi(@johnsusi):yeah, we have not gotten that to work well yet. We do some manual rewriting of the source maps in production to get decent stack-traces but it would be nice if it just worked with the compiler out of the box. ---------------------------------------------------------------------------------------------------- [14:47:09] Jamie Gaskins(@jgaskins):Yeah, I've noticed when concatenating my compiled assets in dev even with Sprockets, I lose source map support. I wonder if that's related to what you're seeing. This was the default in Opal 0.7, I think, and it was reverted in 0.8. ---------------------------------------------------------------------------------------------------- [15:16:44] John Susi(@johnsusi):@jgaskins: Have you ever tried to use the chrome debugger with opal/clearwater? ---------------------------------------------------------------------------------------------------- [15:17:43] Jamie Gaskins(@jgaskins):All the time :-) ---------------------------------------------------------------------------------------------------- [15:18:30] John Susi(@johnsusi):do you know if it's possible to step over ruby code without being dropped into the generated javascript? ---------------------------------------------------------------------------------------------------- [15:20:11] John Susi(@johnsusi):perhaps this is related to my broken source maps. It sort of works now but feels a bit off :) ---------------------------------------------------------------------------------------------------- [15:20:41] Jamie Gaskins(@jgaskins):Good question. I don't know if its step functionality takes source maps into consideration. I don't use breakpoints much. I usually use it when trying to understand an exception. ---------------------------------------------------------------------------------------------------- [15:21:07] Jamie Gaskins(@jgaskins):Stepping isn't useful when the next statement breaks the app :-) ---------------------------------------------------------------------------------------------------- [15:21:11] John Susi(@johnsusi)::) ---------------------------------------------------------------------------------------------------- [15:21:29] John Susi(@johnsusi):debugger; is my favourite javascript oneliner ---------------------------------------------------------------------------------------------------- [15:21:32] Jamie Gaskins(@jgaskins):lol ---------------------------------------------------------------------------------------------------- [15:21:58] John Susi(@johnsusi):breakpoints seem to work at least, thats nice ---------------------------------------------------------------------------------------------------- [15:22:05] Jeff Dickey(@jdickey):mine too, at least until `dwim` gets implemented in ES71 ---------------------------------------------------------------------------------------------------- [15:22:24] John Susi(@johnsusi):lol ---------------------------------------------------------------------------------------------------- [15:22:26] Jamie Gaskins(@jgaskins):I think the Opal compiler passes through a `debugger` line directly into JS. ---------------------------------------------------------------------------------------------------- [15:22:48] Mitch VanDuyn(@catmando):yes recent versions (0.9 and 0.10 do) ---------------------------------------------------------------------------------------------------- [15:24:31] Jamie Gaskins(@jgaskins):It's kinda nice that it doesn't try to compile it to `self.$debugger()`. :-) ---------------------------------------------------------------------------------------------------- [15:25:44] Jamie Gaskins(@jgaskins):@jdickey Googling that seems to show that DWIM is the safe-navigation / `try` operator? ---------------------------------------------------------------------------------------------------- [15:26:27] Jamie Gaskins(@jgaskins):I hadn't heard the term before, so I'm just checking to see I'm on the same page. :-) ---------------------------------------------------------------------------------------------------- [15:27:26] Jeff Dickey(@jdickey):I don't know how to do it in current JS, so just do what I mean anyway, blastit :D ---------------------------------------------------------------------------------------------------- [15:27:45] Jeff Dickey(@jdickey):isn't that how your SO thinks you work? ---------------------------------------------------------------------------------------------------- [15:28:09] Jamie Gaskins(@jgaskins):lol ---------------------------------------------------------------------------------------------------- [15:29:35] Jeff Dickey(@jdickey):I'm having a Friday to dismember; not sure whether the root problem is a clueless boss or tool writers that neither think through the implications nor provide easy hooks for those who do. Present company not included, of course :) ---------------------------------------------------------------------------------------------------- [15:30:03] Jeff Dickey(@jdickey):so if my sense of humour is a bit twisted, apologies ---------------------------------------------------------------------------------------------------- [15:30:38] Jeff Dickey(@jdickey):but yeah, that's how _my_ SO emulates thinking :P ---------------------------------------------------------------------------------------------------- [15:42:45] Jamie Gaskins(@jgaskins):Oh, I could very well be a clueless tool writer. ;-) The good news is that if you don't think Clearwater (or related gems) provides good ways to work around problems, I'd love to know what the friction is and help figure out a solution. :-D ---------------------------------------------------------------------------------------------------- [15:58:44] Jeff Dickey(@jdickey):Clearwater isn't my problem now, Jamie; the relatively limited poking I've done at it to date has been extremely positive. I won't hesitate to unload any frustrations I run into, don't worry :D ---------------------------------------------------------------------------------------------------- [15:59:11] Jamie Gaskins(@jgaskins):lol ---------------------------------------------------------------------------------------------------- [15:59:16] Jamie Gaskins(@jgaskins):Good to hear! ---------------------------------------------------------------------------------------------------- ############################## [2016-09-20] ############################## [01:40:23] Jamie Gaskins(@jgaskins):I wrote a gem to generate a Clearwater app running on top of a Roda backend to get up and running quickly: https://github.com/clearwater-rb/clearwater-roda ---------------------------------------------------------------------------------------------------- [01:42:46] LeoDaoTao(@LeoDaoTao):@jgaskins sweet!!! I was about to ask you what is your Roda-Clearwater setup :) ---------------------------------------------------------------------------------------------------- [01:45:05] Jamie Gaskins(@jgaskins):@LeoDaoTao I've been using Roda for a lot of stuff lately. It's just so easy to add API endpoints. It makes Rails feel like a whole lot of ceremony, which is odd. Rails was created to escape that kind of ceremony. :-) ---------------------------------------------------------------------------------------------------- [01:47:11] LeoDaoTao(@LeoDaoTao):@jgaskins agreed! ---------------------------------------------------------------------------------------------------- [01:49:47] Jamie Gaskins(@jgaskins):I might add [Clearwater::HotLoader](https://github.com/clearwater-rb/clearwater-hot_loader) in there to make it work similarly to how `create-react-app` does for React apps. ---------------------------------------------------------------------------------------------------- [01:50:41] LeoDaoTao(@LeoDaoTao):That would be cool. ---------------------------------------------------------------------------------------------------- [01:51:25] LeoDaoTao(@LeoDaoTao):What do you use for persistence in Roda? ---------------------------------------------------------------------------------------------------- [01:54:18] Jamie Gaskins(@jgaskins):Mostly ActiveRecord. If it's a greenfield app I might use Sequel. I'd love to use ROM for some things, but I need to play with it a bit more. I feel bad for not having done much with it because the author is a really good friend of mine. ---------------------------------------------------------------------------------------------------- [01:57:27] LeoDaoTao(@LeoDaoTao):Yeah, I'm looking into ROM myself too. I used to live in the same city as Piotr but didn't have a chance to meet him then. ---------------------------------------------------------------------------------------------------- [01:58:53] Jamie Gaskins(@jgaskins):Really? Where was this? He kinda lives all over the place. :-) ---------------------------------------------------------------------------------------------------- [13:03:35] LeoDaoTao(@LeoDaoTao):Krakow, Poland ---------------------------------------------------------------------------------------------------- [15:37:37] Jamie Gaskins(@jgaskins):Nice, last I knew he wasn't even living in Poland anymore, but I think he moved back now — he doesn't talk about it much and I'm not even on that continent so it's hard for me to keep track. :-D But he and I were driving through Washington DC one time and he was like "these houses look really nice, maybe I could move here". He loves to move around a lot I guess. :-) ---------------------------------------------------------------------------------------------------- ############################## [2016-09-21] ############################## [03:03:31] Jamie Gaskins(@jgaskins):Added `ServiceWorker` and `Geolocation` to `bowser` in [`bowser#5`](https://github.com/clearwater-rb/bowser/pull/5) and [`bowser#6`](https://github.com/clearwater-rb/bowser/pull/6). ---------------------------------------------------------------------------------------------------- ############################## [2016-09-23] ############################## [23:06:52] LeoDaoTao(@LeoDaoTao):This may be an Opal question, but how can I read a JS variable from outside a Clearwater app? ---------------------------------------------------------------------------------------------------- [23:08:02] Mitch VanDuyn(@catmando):Use back ticks or ---------------------------------------------------------------------------------------------------- [23:08:52] LeoDaoTao(@LeoDaoTao):I did try that but I get Uncaught ReferenceError ---------------------------------------------------------------------------------------------------- [23:09:01] Mitch VanDuyn(@catmando):%x{ ---------------------------------------------------------------------------------------------------- [23:09:09] Mitch VanDuyn(@catmando):} ---------------------------------------------------------------------------------------------------- [23:09:23] Mitch VanDuyn(@catmando):Should work ---------------------------------------------------------------------------------------------------- [23:09:30] Mitch VanDuyn(@catmando):Do this ---------------------------------------------------------------------------------------------------- [23:09:35] Mitch VanDuyn(@catmando):Add ---------------------------------------------------------------------------------------------------- [23:09:59] Mitch VanDuyn(@catmando):`debugger` ---------------------------------------------------------------------------------------------------- [23:10:17] Mitch VanDuyn(@catmando):Where ever you want to get something ---------------------------------------------------------------------------------------------------- [23:10:35] Mitch VanDuyn(@catmando):Then when it hit the breakpoint ---------------------------------------------------------------------------------------------------- [23:11:00] Mitch VanDuyn(@catmando):Whatever you can type in the console ---------------------------------------------------------------------------------------------------- [23:11:12] Mitch VanDuyn(@catmando):Will work in back ticks ---------------------------------------------------------------------------------------------------- [23:12:27] LeoDaoTao(@LeoDaoTao):OK LOL typo :-) ---------------------------------------------------------------------------------------------------- [23:12:43] LeoDaoTao(@LeoDaoTao):but learned about the debugger :-) never use it like that before :-) ---------------------------------------------------------------------------------------------------- [23:13:08] Mitch VanDuyn(@catmando):Be careful ---------------------------------------------------------------------------------------------------- [23:13:47] Mitch VanDuyn(@catmando):This does not compile `{debugger} ---------------------------------------------------------------------------------------------------- [23:14:28] Mitch VanDuyn(@catmando):This does `{debugger; nil}` ---------------------------------------------------------------------------------------------------- [23:14:52] Mitch VanDuyn(@catmando):Debugger cannot be the last method in a block ---------------------------------------------------------------------------------------------------- [23:15:06] Mitch VanDuyn(@catmando):Because it's not really a method ---------------------------------------------------------------------------------------------------- [23:15:19] LeoDaoTao(@LeoDaoTao):hmm, will play with it ---------------------------------------------------------------------------------------------------- [23:15:58] LeoDaoTao(@LeoDaoTao):thank you! ---------------------------------------------------------------------------------------------------- ############################## [2016-09-26] ############################## [20:00:05] LeoDaoTao(@LeoDaoTao):@jgaskins BTW why the Clearwater name? I like it, I’m just curious :-) I’ve been thinking about a logo for the project since the guys at reactrb are getting all fancy :-P ---------------------------------------------------------------------------------------------------- ############################## [2016-09-27] ############################## [19:18:17] LeoDaoTao(@LeoDaoTao):Is there any way to render HTML with Clearwater? I have html coming in in a JSON feed. Do I need to create some type of parser to create the correct nodes? ---------------------------------------------------------------------------------------------------- ############################## [2016-09-28] ############################## [01:48:08] Jamie Gaskins(@jgaskins):@LeoDaoTao To render raw HTML, you can set the `innerHTML` property: `div(innerHTML: html_text)`. There isn't a snake-cased version of it because it shouldn't be used often. :-) ---------------------------------------------------------------------------------------------------- [02:04:55] Jamie Gaskins(@jgaskins):@balmoral The `BlackBoxNode` may be what you're looking for. Here's a simple Google Maps example: ```ruby class Map include Clearwater::BlackBoxNode attr_reader :map, :location def initialize(location) @location = `new google.maps.LatLng(#{location.latitude}, #{location.longitude})` end # @param element [Bowser::Element] The element to render into. It defaults to a plain div, but can be customized by overriding the `node` method. def mount(element) @map = `new google.maps.Map(#{element.to_n}, { center: #@location, zoom: 13 })` end def update(previous) @map = previous.map # Copy from the previous instance `#@map.setCenter(#@location)` end def node # We don't include Component, so we have to prefix the `div` call with it. # You can include Component, but it must come before BlackBoxNode. Clearwater::Component.div(style: { width: '100%', height: '100vw' }) end end ``` You can use it in place of a component. Important to keep in mind that the `BlackBoxNode` doesn't get updated by Clearwater (it treats it as a black box, just sending it the `update` message if it's already mounted), put it as far down the tree as you can unless you're okay with handling updates yourself. In this case, it just moves the map around with whatever location is passed into the constructor on each render. ---------------------------------------------------------------------------------------------------- [06:38:37] Colin Gunn(@balmoral):@jgaskins Many thanks. Looks just what’s needed. ---------------------------------------------------------------------------------------------------- [07:06:41] Colin Gunn(@balmoral): ---------------------------------------------------------------------------------------------------- [00:54:25] Colin Gunn(@balmoral):Are there any examples available of how to render a pure javascript widget/componet in Clearwater? ---------------------------------------------------------------------------------------------------- [01:08:53] Colin Gunn(@balmoral):The JS component needs an existing div to render to. ---------------------------------------------------------------------------------------------------- [01:46:10] Jamie Gaskins(@jgaskins):@LeoDaoTao It's is the name of a city I lived in when I was a kid. :-) ---------------------------------------------------------------------------------------------------- ############################## [2016-09-29] ############################## [01:05:59] Colin Gunn(@balmoral):@jgaskins BlackBoxNode did the trick pretty much per your example :smile:. Thanks! ---------------------------------------------------------------------------------------------------- [01:09:58] Colin Gunn(@balmoral):@jgaskins fyi I’ve wrapped Highcharts javascript (a really nice charting component) in Ruby `opal-highcharts` and wanted to try using it in a clearwater + roda app. ---------------------------------------------------------------------------------------------------- [02:39:55] Jamie Gaskins(@jgaskins):@balmoral Nice! Using a chart library was actually the reason I added the BlackBoxNode in the first place. A friend needed to use charts in their app. I use the maps example a lot because that's what I ended up doing with it. The idea was that anything that does its own rendering into a DOM node just uses the BlackBoxNode. :-) ---------------------------------------------------------------------------------------------------- [02:43:52] Jamie Gaskins(@jgaskins):Because then Clearwater stays out of it ---------------------------------------------------------------------------------------------------- [18:54:50] LeoDaoTao(@LeoDaoTao):How can I make a div change it’s ‘position’ to fixed when while scrolling it reaches the top of browser window? ---------------------------------------------------------------------------------------------------- [21:36:14] Jamie Gaskins(@jgaskins):@LeoDaoTao That's such a pain in the ass. WebKit gives you the `position: sticky` CSS attribute, which is basically the best thing ever, but no other browser supports it. ---------------------------------------------------------------------------------------------------- [21:38:31] Jamie Gaskins(@jgaskins):(okay, so it's not the best thing _ever_, but hyperbole is fun) ---------------------------------------------------------------------------------------------------- [21:40:20] Jamie Gaskins(@jgaskins):The only truly cross-browser way that I know of is to use a scroll event on the document (which has several drawbacks) that checks the position of the element using `element.offset_height` (assuming it's not a `position: absolute` child of a `position: relative` ancestor, in which case, you have to walk `offset_parent` elements all the way up to the document itself), then find out the `scroll_top` of the document, and if one is greater than the other, you set your computer on fire and walk away. ---------------------------------------------------------------------------------------------------- [21:46:03] LeoDaoTao(@LeoDaoTao):@jgaskins thank you I will try this :) was thinking about sticky as well but need better browser suport ---------------------------------------------------------------------------------------------------- [21:49:54] Jamie Gaskins(@jgaskins):Oh, I take that back, it looks like Firefox supports it now. ---------------------------------------------------------------------------------------------------- [21:50:13] Jamie Gaskins(@jgaskins):So, y'know, two of the least used browsers in the world have it. Faaaantastic. :-) ---------------------------------------------------------------------------------------------------- [22:05:02] LeoDaoTao(@LeoDaoTao):@jgaskins does not look like Chrome supports it yet though, I thought it did :-( ---------------------------------------------------------------------------------------------------- [22:07:55] LeoDaoTao(@LeoDaoTao):@jgaskins Oh I see your point about the two least used browsers :-) ---------------------------------------------------------------------------------------------------- [22:53:49] LeoDaoTao(@LeoDaoTao):@jgaskins how do even get the scroll event working with window with Clearwater/Opal? I tried using this in application.rb ``` Bowser.window.scroll do |event| puts ‘Scrolling...' end ``` but it does not seem to be working. All black magic still :-) ---------------------------------------------------------------------------------------------------- ############################## [2016-09-30] ############################## [00:19:43] Jamie Gaskins(@jgaskins):@LeoDaoTao Very close, it's `on :scroll`: ```ruby Bowser.window.on :scroll do |event| puts "scrolling!" end ``` ---------------------------------------------------------------------------------------------------- [00:20:49] Jamie Gaskins(@jgaskins):@LeoDaoTao Chrome does support `position: sticky`, but it's behind a feature flag, so you can't count on it actually being there. I think they had performance issues with it before, so they removed it entirely, and now it's back but still behind the flag. ---------------------------------------------------------------------------------------------------- [00:22:37] LeoDaoTao(@LeoDaoTao):@jgaskins oh I see makes total sense now that I see it! Thank you! ---------------------------------------------------------------------------------------------------- [00:59:46] Colin Gunn(@balmoral):@jgaskins I’m trying out hot loader and getting this error on client: ``` websocket.self-83f58ed….js?body=1:26 WebSocket connection to 'ws://localhost:9292/clearwater_hot_loader' failed: Error during WebSocket handshake: Unexpected response code: 200 ``` in `config.ru` I’ve got ``` require 'clearwater/hot_loader' puts "ENV['RACK_ENV']=#{ENV['RACK_ENV']}" if ENV['RACK_ENV'] == 'development' Clearwater::HotLoader.start end run MyApp::Roda ``` and in `app.rb` I’ve got ``` require 'opal' require 'clearwater' require 'clearwater/hot_loader' require 'components/layout' require 'components/charts' router = Clearwater::Router.new do route 'charts' => MyApp::Component::Charts.new end Clearwater::HotLoader.connect 9292 Clearwater::Application.new(component: Layout.new, router: router).call ``` Any suggestions? ---------------------------------------------------------------------------------------------------- [01:18:26] Jamie Gaskins(@jgaskins):@balmoral Your WebSocket request is getting a regular HTTP response, so you have to pass it off to `Clearwater::HotLoader`. Inside your Roda app, make sure you do this: ```ruby r.on('clearwater_hot_loader') { r.run Clearwater::HotLoader } ``` ---------------------------------------------------------------------------------------------------- [01:29:02] Jamie Gaskins(@jgaskins):I should add some info in the README for Roda like I did for Rails ---------------------------------------------------------------------------------------------------- [02:09:23] Colin Gunn(@balmoral):@jgaskins is that inside `route { |r| … }`block in Roda subclass? ---------------------------------------------------------------------------------------------------- [02:23:15] Colin Gunn(@balmoral):I’m getting ``` Rack::Lint::LintError: Status must be >=100 seen as integer ``` error now on server ---------------------------------------------------------------------------------------------------- [02:50:35] Jamie Gaskins(@jgaskins):@balmoral Hmm, does it look like this? ```ruby class MyApp route do |r| r.on('clearwater_hot_loader') { r.run Clearwater::HotLoader } end end ``` ---------------------------------------------------------------------------------------------------- [02:50:44] Jamie Gaskins(@jgaskins):(or something similar) ---------------------------------------------------------------------------------------------------- [02:56:12] Jamie Gaskins(@jgaskins):@balmoral Ohhh, are you running Puma? I forgot, you have to run a threaded webserver to be able to use web sockets ---------------------------------------------------------------------------------------------------- [02:56:32] Jamie Gaskins(@jgaskins):I should also add that to the readme ---------------------------------------------------------------------------------------------------- [02:57:17] Colin Gunn(@balmoral):yep - running puma ---------------------------------------------------------------------------------------------------- [02:57:55] Jamie Gaskins(@jgaskins):Ugh, one sec, checking it out locally. ---------------------------------------------------------------------------------------------------- [03:02:09] Colin Gunn(@balmoral):code is ``` module MyApp class Roda < ::Roda include MyApp::HTML payload = MyApp::Sprockets::Payload.new route do |r| r.on('clearwater_hot_loader') { r.run Clearwater::HotLoader } payload.route(r) html(payload) end end end ``` ---------------------------------------------------------------------------------------------------- [03:12:48] Jamie Gaskins(@jgaskins):@balmoral lol It's `Rack::Lint` itself. It doesn't handle async responses, so it can't be used with web sockets. ---------------------------------------------------------------------------------------------------- [03:13:03] Jamie Gaskins(@jgaskins):https://github.com/faye/faye/issues/25#issuecomment-1493735 ---------------------------------------------------------------------------------------------------- [03:14:01] Jamie Gaskins(@jgaskins):So if you run with `rackup -E production`, Rack will not inject `Rack::Lint` middleware. ---------------------------------------------------------------------------------------------------- [03:14:22] Jamie Gaskins(@jgaskins):I swear I've seen it work without having to use production mode, though. So weird. ---------------------------------------------------------------------------------------------------- [03:14:40] Jamie Gaskins(@jgaskins): ---------------------------------------------------------------------------------------------------- [03:17:35] Colin Gunn(@balmoral):@jgaskins hot loading is kinda nice in development with source maps, etc :smile: ---------------------------------------------------------------------------------------------------- [03:20:32] Jamie Gaskins(@jgaskins):@balmoral Yeah, I'm really confused about this. I'm sure I've used it in development mode with Roda. Lemme see if I can figure it out. ---------------------------------------------------------------------------------------------------- [03:20:57] Colin Gunn(@balmoral):I’ve been spoilt by Volt which refreshed the browser whenever code changed, and did a lot of other nice magic things. ---------------------------------------------------------------------------------------------------- [03:22:22] Colin Gunn(@balmoral):@jgaskins Hot loading would be nice to have, but don’t prioritize on my account ---------------------------------------------------------------------------------------------------- [03:24:03] Jamie Gaskins(@jgaskins):Yeah, Volt's magic is pretty convenient. I've tried to add conveniences into Clearwater wherever it doesn't make things difficult to debug when things break. :-) ---------------------------------------------------------------------------------------------------- [03:24:24] Jamie Gaskins(@jgaskins):That's the hard part, though. Magic is frequently difficult to debug. ---------------------------------------------------------------------------------------------------- [03:26:31] Jamie Gaskins(@jgaskins):that awkward moment when I google `"Rack::Lint" roda` and get my own issue report to Roda from last year: https://github.com/jeremyevans/roda/issues/44 ---------------------------------------------------------------------------------------------------- [03:30:57] Colin Gunn(@balmoral):to be honest, the magic is great until it isn’t! What I like about Clearwater is it’s relative transparency (no pun intended). thanks for checking this out ---------------------------------------------------------------------------------------------------- [03:33:24] Jamie Gaskins(@jgaskins):@balmoral No worries. I want C::HotLoader to be easy to use. Friction like this can cause people checking it out to give up entirely. ---------------------------------------------------------------------------------------------------- [03:40:33] Mitch VanDuyn(@catmando):saw you guys chatting ---------------------------------------------------------------------------------------------------- [03:41:13] Mitch VanDuyn(@catmando):do you know a sure fire way to convert an arbitrary js object (that came from json) into a opal object? ---------------------------------------------------------------------------------------------------- [03:41:21] Mitch VanDuyn(@catmando):I can do ---------------------------------------------------------------------------------------------------- [03:42:22] Mitch VanDuyn(@catmando): ---------------------------------------------------------------------------------------------------- [03:42:34] Mitch VanDuyn(@catmando):```ruby JSON.parse(`JSON.stringify(x)`) ``` ---------------------------------------------------------------------------------------------------- [03:42:49] Mitch VanDuyn(@catmando):but that seems a bit too hard... ---------------------------------------------------------------------------------------------------- [03:43:19] Mitch VanDuyn(@catmando):`Hash.new(x)` works only for some cases... ---------------------------------------------------------------------------------------------------- [03:49:41] Jamie Gaskins(@jgaskins):@catmando `Hash.new(js_obj)` should work as long as you `require 'native'` ---------------------------------------------------------------------------------------------------- [03:51:20] Mitch VanDuyn(@catmando):nope ---------------------------------------------------------------------------------------------------- [03:51:22] Mitch VanDuyn(@catmando):well ---------------------------------------------------------------------------------------------------- [03:51:26] Mitch VanDuyn(@catmando):somewhat but ---------------------------------------------------------------------------------------------------- [03:53:55] Mitch VanDuyn(@catmando):```json {"event":"change","data":{"broadcast_id":"70295259989200-1475207607.980994","channels":["TestApplication"],"klass":"TestModel","channel":"TestApplication","record":{"id":1,"test_attribute":"model 1","completed":true,"created_at":"2016-09-30T03:53:27.976Z","updated_at":"2016-09-30T03:53:27.976Z"},"previous_changes":{"id":[null,1],"test_attribute":[null,"model 1"],"completed":[null,true],"created_at":[null,"2016-09-30T03:53:27.976Z"],"updated_at":[null,"2016-09-30T03:53:27.976Z"]}},"channel":"private-synchromesh-TestApplication"} ``` ---------------------------------------------------------------------------------------------------- [03:56:15] Jamie Gaskins(@jgaskins):@catmando There was a bug back in Opal 0.8 or so where it didn't recurse, but I fixed that for 0.9. https://github.com/opal/opal/pull/1120 ---------------------------------------------------------------------------------------------------- [03:56:25] Mitch VanDuyn(@catmando):```json { "event":"change", "data": { "broadcast_id":"70295259989200-1475207607.980994", "channels":["TestApplication"], "klass":"TestModel", "channel":"TestApplication", "record":{"id":1,"test_attribute":"model 1","completed":true,"created_at":"2016-09-30T03:53:27.976Z","updated_at":"2016-09-30T03:53:27.976Z"}, "previous_changes":{ "id":[null,1], "test_attribute":[null,"model 1"], "completed":[null,true], "created_at":[null,"2016-09-30T03:53:27.976Z"], "updated_at":[null,"2016-09-30T03:53:27.976Z"]}}, "channel":"private-synchromesh-TestApplication"} ``` ---------------------------------------------------------------------------------------------------- [03:57:00] Mitch VanDuyn(@catmando):the arrays inside of previous_changes do not get converted... ---------------------------------------------------------------------------------------------------- [03:57:24] Mitch VanDuyn(@catmando):running 0.10.2 ---------------------------------------------------------------------------------------------------- [03:59:19] Jamie Gaskins(@jgaskins):Yeah I just ran that through on my machine, too. I wonder if it's actually the `null` itself not getting converted. ---------------------------------------------------------------------------------------------------- [03:59:36] Mitch VanDuyn(@catmando):hmmm... ---------------------------------------------------------------------------------------------------- [04:05:21] Mitch VanDuyn(@catmando):indeed ---------------------------------------------------------------------------------------------------- [04:05:38] Mitch VanDuyn(@catmando):does not convert null's to nil but JSON.parse does... ---------------------------------------------------------------------------------------------------- [04:05:42] Mitch VanDuyn(@catmando):oh well ---------------------------------------------------------------------------------------------------- [04:07:04] Jamie Gaskins(@jgaskins):I found it. It doesn't convert nulls in arrays, but will convert nulls as hash values. I'll add a PR for that now. ---------------------------------------------------------------------------------------------------- [04:09:23] Mitch VanDuyn(@catmando):thanks... probably a nice easy one. ---------------------------------------------------------------------------------------------------- [04:10:08] Jamie Gaskins(@jgaskins):It is. It's just a slight addition to that PR I submitted before. ---------------------------------------------------------------------------------------------------- [04:10:42] Mitch VanDuyn(@catmando):makes sense as this is unusual use case where I am picking up stuff already parsed by JS routines (i.e. pusher and action-cable drivers) where normally we are are parsing the incoming string using opal JSON.parse ---------------------------------------------------------------------------------------------------- [04:11:25] Mitch VanDuyn(@catmando):maybe I can find some lower level way to get the string before the driver parses it... ---------------------------------------------------------------------------------------------------- [04:11:58] Mitch VanDuyn(@catmando):what is the PR # please ---------------------------------------------------------------------------------------------------- [04:13:07] Jamie Gaskins(@jgaskins):I haven't submitted it yet. I've got the failing test case, just need to get it passing.. ---------------------------------------------------------------------------------------------------- [04:14:15] Mitch VanDuyn(@catmando):sorry its late I was thinking issue # not pr # ---------------------------------------------------------------------------------------------------- [04:14:19] Mitch VanDuyn(@catmando):thanks! ---------------------------------------------------------------------------------------------------- [04:28:30] Jamie Gaskins(@jgaskins):@catmando Tagged you in the PR so you should get notifications. You may want to ask to get it backported into 0.10 so you don't have to wait for 0.11 to be released. ---------------------------------------------------------------------------------------------------- [04:30:12] Mitch VanDuyn(@catmando):thanks again! ---------------------------------------------------------------------------------------------------- [13:24:32] Jamie Gaskins(@jgaskins)::+1: ---------------------------------------------------------------------------------------------------- [13:30:02] Jamie Gaskins(@jgaskins):@balmoral I'll look at the `Rack::Lint` thing again tonight. I couldn't figure out last night where it was happening. I checked the code for Roda, Puma, Rack, and anything else I could find and none of them were injecting that middleware, but I'll investigate again when I get a chance tonight. ---------------------------------------------------------------------------------------------------- [13:33:49] Jamie Gaskins(@jgaskins):ugh, never mind, Rack injects it by default in the development environment: https://github.com/rack/rack/blob/7dd7646a932419f4d308bf2fbc91f4e77edfd4cb/lib/rack/server.rb#L241 ---------------------------------------------------------------------------------------------------- [13:35:33] Jamie Gaskins(@jgaskins):Hilariously, you can use any other environment name and you won't get `Rack::Lint` injected into it in dev. `rackup -E lol` works… ---------------------------------------------------------------------------------------------------- [13:40:51] Jamie Gaskins(@jgaskins):Oh, now I see why it worked for me before without having to do anything special. `rackup` starts a `Rack::Server`. If you start your app with `puma` instead, you don't have that issue. ---------------------------------------------------------------------------------------------------- [13:42:15] Elia Schito(@elia):> @catmando Tagged you in the PR so you should get notifications. You may want to ask to get it backported into 0.10 so you don't have to wait for 0.11 to be released. was going to ask if that's needed /cc @jgaskins ---------------------------------------------------------------------------------------------------- [13:43:44] Jamie Gaskins(@jgaskins):@elia Yeah, that bug was added in 0.9 with the rest of the array recursion for JS->Ruby conversion. I'm surprised it took this long for anyone to discover it. ---------------------------------------------------------------------------------------------------- [13:44:35] Jamie Gaskins(@jgaskins):But I figure backporting to 0.9 when 0.10 is released is probably unnecessary ---------------------------------------------------------------------------------------------------- [15:29:09] Elia Schito(@elia):@jgaskins good to know, anyway seems tiny enough that backporting it wouldn't be a problem if needed by anyone ---------------------------------------------------------------------------------------------------- [15:42:20] Mitch VanDuyn(@catmando):@elia @jgaskins - the reason nobody has noticed is probably because its an obscure use case... how did you get this json like object? In most cases you have incoming json string, which you use opal to convert. No problem in that case. In my case I am building on top of pusher and action-cable so they are giving me pre-converted json. Plus you have to hit this null vs. nil thing. ---------------------------------------------------------------------------------------------------- [15:42:50] Elia Schito(@elia):👍🏼 ---------------------------------------------------------------------------------------------------- [15:43:34] Mitch VanDuyn(@catmando):its a tax on people who don't code isomorphically :-) ---------------------------------------------------------------------------------------------------- [15:43:48] Elia Schito(@elia)::smile: ---------------------------------------------------------------------------------------------------- [16:37:40] Jeff Dickey(@jdickey):Gimme a needle and I sew :P ---------------------------------------------------------------------------------------------------- [17:29:30] Jamie Gaskins(@jgaskins):But do you sew morphically? ---------------------------------------------------------------------------------------------------- [21:33:00] Colin Gunn(@balmoral):@jgaskins so for hotloader I should run puma direct, not via rackup option in config.ru? ---------------------------------------------------------------------------------------------------- [22:39:24] Jamie Gaskins(@jgaskins):@balmoral Seems that way ---------------------------------------------------------------------------------------------------- [22:40:09] Jamie Gaskins(@jgaskins):Because Puma won't inject that middleware, but Rack does with its default server. ---------------------------------------------------------------------------------------------------- ############################## [2016-10-01] ############################## [01:40:59] Jamie Gaskins(@jgaskins):hehe I didn't like putting things under `js` (or `javascripts` on Rails), but after a while I guess I became desensitized to that. I like the idea of using `server` and `client` directories for Roda apps, and I frequently use `shared` (or `app/shared` in Rails apps) for code common to both environments. ---------------------------------------------------------------------------------------------------- [01:43:29] Jamie Gaskins(@jgaskins):One of the cool things about sharing code is that `GrandCentral` works out of the box on both the client and the server, so you can use `GrandCentral::Model` subclasses to hold state on the server, too. In fact, a gem I'm working on for bidirectional Pusher-style WebSocket communication uses it on both sides for its `Message` class. ---------------------------------------------------------------------------------------------------- [01:58:08] Colin Gunn(@balmoral):I haven’t lived in rails world much, so never got used to its conventions. And don’t really want to go there. I’d been wondering if you’d extend GrandCentral across client-server. Would be really good to see. What do you currently use for (async) data requests from the client to the server? Is there anything nice and simple around without having to be swamped by some monolithic framework? ---------------------------------------------------------------------------------------------------- [03:03:28] Jamie Gaskins(@jgaskins):@balmoral I just use `GrandCentral` actions for fetching data. Here's a quick example: ```ruby Store = GrandCentral::Store.new(initial_state) do |state, action| case action when FetchUsers state.update(loading_users: true) when LoadUsers state.update(users: action.users, loading_users: false) else state end end FetchUsers = GrandCentral::Action.create do def promise Bowser::HTTP.fetch('/api/users') end end LoadUsers = GrandCentral::Action.with_attributes(:hashes) do def users hashes.map { |hash| User.new(hash) } end end class UserList include Clearwater::Component def render div([ button({ onclick: method(:get_users) }, 'Get users') ul(users.map { |user| li(user.name) }), ]) end def users Store.state.users end def get_users Store.dispatch(FetchUsers.new) .then { |response| Store.dispatch LoadUsers.new(response.json) } .then { |error| Store.dispatch ErrorLoadingUsers.new(error) } end end ``` ---------------------------------------------------------------------------------------------------- [03:10:53] Colin Gunn(@balmoral):@jgaskins and the (roda) router handles the ‘api’ fetch? (I’ve still got a lot to learn here :smile: ) ---------------------------------------------------------------------------------------------------- [03:11:05] Jamie Gaskins(@jgaskins):As an alternative to handling the promise resolution/rejection within the UI component, I've also been experimenting with consolidating all of my action handling that has side effects so that you don't have to dispatch actions when the promise is resolved, it happens automatically: ```ruby class UserList # ... def get_users Store.dispatch(FetchUsers.new) end end # All action dispatches that have side effects (anything other than synchronously # updating the store's state, that is, like HTTP requests, talking to `localStorage`, # `indexedDB`, etc) have those side effects managed here. Store.on_dispatch do |old_state, new_state, action| case action when FetchUsers action.promise .then { |response| Store.dispatch LoadUsers.new(response.json) } .then { |error| Store.dispatch ErrorLoadingUsers.new(error) } end end ``` ---------------------------------------------------------------------------------------------------- [03:13:00] Jamie Gaskins(@jgaskins):@balmoral Bingo. In your Roda app: ```ruby class MyApp < Roda plugin :json # Returning a hash/array automatically renders a JSON response route do |r| r.on 'api' do r.on 'users' do User.all.map(&:attributes) end end end end ``` ---------------------------------------------------------------------------------------------------- [03:15:36] Colin Gunn(@balmoral):@jgaskins :thumbsup: for promise handling - anything that makes that simpler is good! Really do appreciate your time and help. ---------------------------------------------------------------------------------------------------- [00:27:09] Colin Gunn(@balmoral):@jgaskins thanks for your help - hotloader running nicely under puma. Was wondering whether it would be possible to have a slightly more flexible directory setup for hotloader and road-opal_assets? They currently assume all ruby code will be in assets/js. I’m looking at putting all my ruby code in a lib directory (alongside assets), split into server, client and shared subdirectories. I’ve patched where necessary and all works ok. Hotloader just required adding `‘lib/**/*’` to candidate directories in Configuration initializer. ---------------------------------------------------------------------------------------------------- [01:27:28] Jamie Gaskins(@jgaskins):@balmoral I'm open to that. Right now, `Roda::OpalAssets` is using what Roda defaults to with Roda's built-in `:assets` plugin. `Clearwater::HotLoader` defaults to watching both that and Rails assets locations (if they exist). I haven't added much in the way of configuration to either of those two gems yet because, AFAIK, I was the only one using them. :-) ---------------------------------------------------------------------------------------------------- [01:37:06] Colin Gunn(@balmoral):@jgaskins just feels weird putting ruby code under js directory. But be warned, there may be at least two of us using these gems. :smile: I find your stuff easy to get my head around and really useful! I’m slowly trying to put together a kit which replaces Volt for me (I’ve actually got an app successfully in production under Volt, but alas will need to move it to another framework/toolkit as Volt’s no longer being developed). Currently trying to implmenet Volt-ulltra-light which strips out everything but the Task stuff so I can have a really simple data/state retrieval interface between the client and the server ---------------------------------------------------------------------------------------------------- ############################## [2016-10-02] ############################## [03:06:35] Colin Gunn(@balmoral):@jgaskins did you have any problem with the google map sizing properly in the black box node when initially rendered? My chart height is ok, but the width is beyond the right of the containing div until I resize the window. ---------------------------------------------------------------------------------------------------- [03:07:43] Colin Gunn(@balmoral):^manually resize the window ---------------------------------------------------------------------------------------------------- [03:23:59] Colin Gunn(@balmoral):@jgaskins nvm the problem is with the chart ---------------------------------------------------------------------------------------------------- [03:55:46] Jamie Gaskins(@jgaskins):@balmoral Yeah, usually the thing I forget to do with Gmaps is set the height of the map container. Rendering a Google map to an element doesn't change its dimensions and a `div` element with no children has a height of `0px`. :-) Other than that I don't generally have any issues. ---------------------------------------------------------------------------------------------------- [22:13:07] Jamie Gaskins(@jgaskins):@balmoral Also, some JS libraries require that the element already be fully rendered into the DOM before they can render into it. The `mount` method gets called after the element is created but layout hasn't been calculated yet. If that's an issue, you can delay the JS library's rendering until then by passing it through `Bowser.window.animation_frame`: ```ruby class Foo include Clearwater::BlackBoxNode def mount(element) Bowser.window.animation_frame { `js_lib.doYourThing(#{element.to_n})` } end end ``` ---------------------------------------------------------------------------------------------------- [22:14:05] Jamie Gaskins(@jgaskins):That might help keep rendering bugs like that from cropping up. A lot of JS libraries expect the element is already in the DOM because they were typically written to be jQuery plugins working with a server-rendered document. :-) ---------------------------------------------------------------------------------------------------- ############################## [2016-10-10] ############################## [00:41:35] Colin Gunn(@balmoral):@jgaskins I’m trying out material design for bootstrap (mdbootstrap) and having some trouble getting navbars and such to behave. Would you expect any issues around using Clearwater components to render bootstrap (4) elements? ---------------------------------------------------------------------------------------------------- [01:28:46] Jamie Gaskins(@jgaskins):@balmoral I don't think so. I haven't looked at Bootstrap 4 yet. Is it still just set up by class names? ---------------------------------------------------------------------------------------------------- [01:30:22] Colin Gunn(@balmoral):@jgaskins Yes, still mostly css based (I’m not using the javascript components yet). It’s probably a botched translation from html to clearwater on my part! ---------------------------------------------------------------------------------------------------- [01:31:23] Jamie Gaskins(@jgaskins):@balmoral Looking into it :-) ---------------------------------------------------------------------------------------------------- [01:31:58] Colin Gunn(@balmoral):@jgaskins don’t spend time on my account, unless useful to you :smile: ---------------------------------------------------------------------------------------------------- [01:36:56] Jamie Gaskins(@jgaskins):@balmoral All good. I've been wondering about Bootstrap stuff for a while. I was actually thinking of making a Bootstrap-like gem that was just a bunch of component classes with styles defined in Ruby. So there wouldn't be any CSS to install. ---------------------------------------------------------------------------------------------------- [01:41:06] Colin Gunn(@balmoral):@jgaskins that would be nice, but maybe it’s a bit of a moving target with boostrap 4 in alpha. And an awful lot of components to define. ---------------------------------------------------------------------------------------------------- [01:42:27] Jamie Gaskins(@jgaskins):Oh, it wouldn't be built on Bootstrap specifically. It'd be homegrown styles. ---------------------------------------------------------------------------------------------------- [01:44:50] Jamie Gaskins(@jgaskins):But this way, you could only include the styles you're using in your app: ```ruby require 'gem_name/nav_bar' ``` This would only load the `NavBar` component. So code for things like alerts and modals and whatever else never even gets loaded if you aren't explicitly requiring it. Keeps your JS payload small. ---------------------------------------------------------------------------------------------------- [01:46:53] Jamie Gaskins(@jgaskins):As it is, I'm thinking of including a `Form` component with Clearwater itself (like the `Link` component) because of how frequently it frustrates me to keep adding `event.prevent_default` inside every `form(onsubmit:)` handler. ---------------------------------------------------------------------------------------------------- [01:47:31] Jamie Gaskins(@jgaskins):I'm still trying to figure out good ways of removing friction to get going on an app. :-) ---------------------------------------------------------------------------------------------------- [01:50:01] Colin Gunn(@balmoral):Would be great to get bootstrap-like styling and behavior without all the css. Navbars always seem messy. I like how you’re always looking to reduce the friction, i.e. as much ruby as possible! :smile: ---------------------------------------------------------------------------------------------------- [02:19:25] Colin Gunn(@balmoral):Do element ids behave as normal in virtual DOM? EG if one element/component references another via id will behavior be same as non-virtual? ---------------------------------------------------------------------------------------------------- [02:34:19] Jamie Gaskins(@jgaskins):@balmoral I'm not sure I understand, but I have a feeling the answer is that it's not the same behavior. Do you have an example of what you're trying to do? ---------------------------------------------------------------------------------------------------- [02:39:48] Colin Gunn(@balmoral):I’m converting this html example to clearwater. Note how the collapse target works through an element id. ``` Ruby app detected -----> Compiling Ruby/Rack -----> Using Ruby version: ruby-2.3.3 -----> Installing dependencies using bundler 1.13.7 Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin -j4 --deployment Fetching gem metadata from https://rubygems.org/.............. Fetching version metadata from https://rubygems.org/. Using hike 1.2.3 Using sourcemap 0.1.1 Using concurrent-ruby 1.0.4 Using rack 1.6.5 Using tilt 2.0.6 Using execjs 2.7.0 Using bundler 1.13.7 Using sprockets 3.6.3 Using roda 2.22.0 Using uglifier 3.0.4 Using opal 0.10.3 Using bowser 0.3.0 Using roda-opal_assets 0.3.1 Using clearwater 1.0.0.rc4 Bundle complete! 6 Gemfile dependencies, 14 gems now installed. Gems in the groups development and test were not installed. Bundled gems are installed into ./vendor/bundle. Bundle completed (1.49s) Cleaning up the bundler cache. -----> Detecting rake tasks Could not detect rake tasks ensure you can run `$ bundle exec rake -P` against your app and using the production group of your Gemfile. bash: vendor/ruby-2.3.3/bin/rake: /app/vendor/ruby-2.3.3/bin/ruby: bad interpreter: No such file or directory -----> Discovering process types Procfile declares types -> web Default types for buildpack -> console, rake -----> Compressing... Done: 23.1M -----> Launching... Released v10 https://gunn-family.herokuapp.com/ deployed to Heroku Build finished Dismiss Personal apps xyz-app GITHUB xyz/xyz-app Manage REVIEW APPS Enable review apps to create apps for opened pull requests on GitHub. Learn more. Enable Review Apps... DEVELOPMENT Add app xyz-app Auto deploys master b916106 Deployed less than a minute ago STAGING Add app Staging apps can be used to preview code changes and features before being deployed to production. Add Existing App... PRODUCTION Add app Production apps run your customer facing code. We recommend promoting your code from a staging app that has been tested. Add Existing App... heroku.com Blogs Careers Documentation Support Terms of Service Privacy Cookies © 2017 Salesforce.com Jump to Favorites, Apps, Pipelines, Spaces… ``` ---------------------------------------------------------------------------------------------------- [01:51:32] Colin Gunn(@balmoral):ok - maybe I’ve changed something I shouldn’t have. Will start with a clean slate ---------------------------------------------------------------------------------------------------- [01:52:20] Jamie Gaskins(@jgaskins):Ooooh, I bet I have an idea. ---------------------------------------------------------------------------------------------------- [01:52:31] Jamie Gaskins(@jgaskins):Did you add any more front-end gems? ---------------------------------------------------------------------------------------------------- [01:52:31] Colin Gunn(@balmoral):BTW I’m doing this through auto-deploy from GitHub ---------------------------------------------------------------------------------------------------- [01:53:25] Colin Gunn(@balmoral):Gemfile is as generated (apart from ruby version): ``` ruby '2.3.3' source 'https://rubygems.org' gem 'opal' gem 'clearwater', '~> 1.0.0.rc4' gem 'roda' gem 'roda-opal_assets' group :development do gem 'rerun' gem 'rake’ end ``` ---------------------------------------------------------------------------------------------------- [01:53:33] Jamie Gaskins(@jgaskins):Well … shit. ---------------------------------------------------------------------------------------------------- [01:53:45] Colin Gunn(@balmoral):? ---------------------------------------------------------------------------------------------------- [01:53:46] Jamie Gaskins(@jgaskins):That was the only idea I had ---------------------------------------------------------------------------------------------------- [01:53:48] Jamie Gaskins(@jgaskins):lol ---------------------------------------------------------------------------------------------------- [01:54:37] Colin Gunn(@balmoral):the deploy log says `Could not detect rake tasks`. Shouldn’t it see the rake file? ---------------------------------------------------------------------------------------------------- [01:54:58] Jamie Gaskins(@jgaskins):It should. If you run `rake -T` in your app directory, does it trigger an error? ---------------------------------------------------------------------------------------------------- [01:55:21] Colin Gunn(@balmoral):get `rake assets:precompile # Precompile assets for production` ---------------------------------------------------------------------------------------------------- [01:55:38] Jamie Gaskins(@jgaskins):This is so weird. ---------------------------------------------------------------------------------------------------- [01:55:55] Jamie Gaskins(@jgaskins):Any chance it didn't get committed? ---------------------------------------------------------------------------------------------------- [01:56:15] Jamie Gaskins(@jgaskins):I mean, it should've because the generated app gets its first commit automatically. ---------------------------------------------------------------------------------------------------- [01:56:30] Jamie Gaskins(@jgaskins):… but I'm grasping at straws here ---------------------------------------------------------------------------------------------------- [01:56:56] Colin Gunn(@balmoral):everything is as it should be in github repo ---------------------------------------------------------------------------------------------------- ############################## [2017-02-13] ############################## [15:16:14] Adam Jahn(@ajjahn):Uh, how did I not know there was a Clearwater Gitter room? ---------------------------------------------------------------------------------------------------- [18:36:15] Jamie Gaskins(@jgaskins):You can blame it on someone not putting a link to it in the readme if you like. ---------------------------------------------------------------------------------------------------- [18:36:31] Adam Jahn(@ajjahn):Done. ---------------------------------------------------------------------------------------------------- [18:36:34] Jamie Gaskins(@jgaskins):lol ---------------------------------------------------------------------------------------------------- [18:45:35] Jamie Gaskins(@jgaskins):@ajjahn Did Gitter send you a notification that I'd mentioned you? ---------------------------------------------------------------------------------------------------- [18:47:21] Adam Jahn(@ajjahn):I didn’t get notified (I’m not sure what my notification settings currently are), but it did cause this room to show up in my list of conversations. Just happened to stumble upon it. ---------------------------------------------------------------------------------------------------- [18:56:01] Jamie Gaskins(@jgaskins):Ah, okay. That's interesting. I wondered how it treated mentions when the person wasn't in the room. ---------------------------------------------------------------------------------------------------- ############################## [2017-02-17] ############################## [02:54:39] Jamie Gaskins(@jgaskins):@jegt I remember you mentioning having some initial-render performance issues on large diffs. I've had that in mind for a while trying to come up with a solution for it. I just posted #72 which might help out a bit. ---------------------------------------------------------------------------------------------------- [02:56:20] Jamie Gaskins(@jgaskins):The idea is that you can stop initial rendering at a certain layer in your render tree and it will pick up again on the next frame. ---------------------------------------------------------------------------------------------------- ############################## [2017-03-05] ############################## [04:27:04] Jamie Gaskins(@jgaskins):Working on a styled component generator for Clearwater similar to https://styled-components.com. ---------------------------------------------------------------------------------------------------- [04:29:27] Jamie Gaskins(@jgaskins):Mostly because I really like the whole inline-style thing, but sometimes I need `hover`. The main difference from `styled-components` is that instead of ES6 template strings (because Ruby string interpolation doesn't work _quite_ like that), you can pass in hashes. ```ruby Button = Styled.button( font_size: '1em', border: '2px solid palevioletred', border_radius: '3px', background_color: ->props { props.primary && :palevioletred }, color: ->props { props.primary ? :white : :palevioletred }, '&:hover' => { font_size: '2em', background_color: ->props { props.primary && :green }, }, '&:active' => { color: 'blue', }, ) ``` ---------------------------------------------------------------------------------------------------- [04:31:56] Jamie Gaskins(@jgaskins):Note the `&:hover` and `&:active` pseudoelement styles. We can't get those with inline styles, so I'm trying this out. It works pretty well, I'll try to extract it and publish this weekend. ---------------------------------------------------------------------------------------------------- [04:34:07] Jamie Gaskins(@jgaskins):It's only 125 lines of the worst Ruby code you've ever seen. ---------------------------------------------------------------------------------------------------- [06:12:06] Jamie Gaskins(@jgaskins):I forgot, I've also built a Markdown parser gem that emits Clearwater components that I want to use for the [Clearwater docs site](http://clearwater-docs.herokuapp.com). I'll publish that one, too, when I get a chance. ---------------------------------------------------------------------------------------------------- ############################## [2017-03-06] ############################## [13:37:03] Adam Jahn(@ajjahn):@jgaskins I’m really interested to see how both of those work. ---------------------------------------------------------------------------------------------------- [14:10:58] Jamie Gaskins(@jgaskins):Just published https://github.com/clearwater-rb/clearwater-styled ---------------------------------------------------------------------------------------------------- [14:11:19] Jamie Gaskins(@jgaskins):I'll try to get the Markdown parser up tonight. ---------------------------------------------------------------------------------------------------- [14:11:43] Adam Jahn(@ajjahn):Cool! ---------------------------------------------------------------------------------------------------- [19:17:58] Forrest Chang(@fkchang):@jgaskins betcha I've seen worse code ---------------------------------------------------------------------------------------------------- [19:18:46] Forrest Chang(@fkchang):on a side note, did u find that indexedDB bowser code ? ---------------------------------------------------------------------------------------------------- [20:09:52] Jamie Gaskins(@jgaskins):@fkchang I didn't find it, no, so I rewrote it the other night. Here's what I've got: https://github.com/clearwater-rb/bowser/pull/22 ---------------------------------------------------------------------------------------------------- ############################## [2017-03-07] ############################## [14:45:14] Jamie Gaskins(@jgaskins):@ajjahn I published the Markdown parser: https://github.com/clearwater-rb/clearmarked The API is just `Clearmarked.call(markdown_text)` ---------------------------------------------------------------------------------------------------- [14:46:34] Jamie Gaskins(@jgaskins):Still needs a readme, but it really only has one usable method atm ---------------------------------------------------------------------------------------------------- [15:16:51] Adam Jahn(@ajjahn):@jgaskins Awesome! I’ll give it a look. ---------------------------------------------------------------------------------------------------- ############################## [2017-03-16] ############################## [15:14:37] Adam Jahn(@ajjahn):@jgaskins Would you care to share insight on any methods you’re using to test application components? Simulating or triggering UI events, verifying rendered output, etc. ---------------------------------------------------------------------------------------------------- [15:15:17] Adam Jahn(@ajjahn):@/all ^ Or anyone else for that matter. ---------------------------------------------------------------------------------------------------- [15:20:15] Elia Schito(@elia):I'm interested in that too ---------------------------------------------------------------------------------------------------- [16:22:59] Mitch VanDuyn(@catmando):@ajjahn @elia you guys might know this, but we are still testing isomorphically using rspec + capybara + hyperloop-spec . Details are in the hyperloop-spec readme. Rspec runs on the server, and using the helpers you can define additional components, harnessing, white box modifications, trigger, and record event responses, and do expectations on client side evaluations and promise results. ---------------------------------------------------------------------------------------------------- [16:24:21] Mitch VanDuyn(@catmando):We have about 300 + test specs using this methodology some are server only, some are client side. ---------------------------------------------------------------------------------------------------- [16:25:05] Mitch VanDuyn(@catmando):Plus there are about 500 (?) hyperloop gem specs written this way. ---------------------------------------------------------------------------------------------------- [16:27:11] Mitch VanDuyn(@catmando):I think you could fairly easily modify the hyperloop-spec gem to work outside of hyperloop. The main dependency is getting the top level component entry point, and responding to react call backs. ---------------------------------------------------------------------------------------------------- [16:29:00] Mitch VanDuyn(@catmando):The only negative we have is that it relies on selenium which is slow and has issues, the biggest of which is opal does not work with the chrome-driver. ---------------------------------------------------------------------------------------------------- [16:31:47] Mitch VanDuyn(@catmando):The plan is make a hyperloop capybara driver that allows capybara to interface into the hyperloop transport layer. I will try to make this not depend on anything in hyperloop except the client-server transport, so it should work okay with other frameworks. ---------------------------------------------------------------------------------------------------- [16:33:57] Mitch VanDuyn(@catmando):Here is a spec I just grabbed from catprint.com ---------------------------------------------------------------------------------------------------- [16:38:42] Mitch VanDuyn(@catmando):```ruby require 'spec_helper' describe 'Bleed component', js: true, group: 2 do before(:each) do size_window(:large) # using poltergeist you don't see a window, but for debug its handy... end after(:all) { restart_phantomjs } # this is due to bugginess of poltergeist etc. it 'displays No print to edge option selected (in danger-text) if no bleed is selected' do mount 'Bleed', bleed: nil page.should have_selector('.danger-text', text: 'No print to edge option selected') # binding.pry end it 'displays Full bleed if Bleed Option is Yes' do mount 'Bleed', bleed: FactoryGirl.create(:full_bleed_option, name: 'Yes') page.should_not have_content('No print to edge option selected', wait: 0) page.should have_content('Full Bleed', wait: 0) # binding.pry end it 'displays No bleed if Bleed Option is No' do mount 'Bleed', bleed: FactoryGirl.create(:full_bleed_option, name: 'No') page.should_not have_content('No print to edge option selected', wait: 0) page.should have_content('No Bleed (White Borders)', wait: 0) # binding.pry end it 'adds cursor pointer to danger text if No print to edge option selected' do mount 'Bleed', bleed: nil page.find('.danger-text')['outerHTML'].should include('cursor:pointer') # binding.pry end end ``` ---------------------------------------------------------------------------------------------------- [17:25:09] Elia Schito(@elia):@catmando thanks! ---------------------------------------------------------------------------------------------------- [17:42:34] Mitch VanDuyn(@catmando):notice in the above that we are creating the full bleed option to test in the DB using Factory girl, so the component is being exercised exactly as in the real app. No tricks. As they say in the aircraft world: Fly as you test, and test as you fly. ---------------------------------------------------------------------------------------------------- ############################## [2017-03-17] ############################## [01:47:19] Jamie Gaskins(@jgaskins):@ajjahn I unit-test non-`render` methods in components with RSpec server-side (same with my GrandCentral stores, with the exception of async actions) since they're just Ruby objects. For all UI interactions I've just been testing them through Poltergeist because I haven't figured out a decent way around that yet. ---------------------------------------------------------------------------------------------------- [01:49:20] Jamie Gaskins(@jgaskins):I'd love to try to figure out a way to mock out the DOM in MRI (using `DOMReference`s could help that a lot), but components that dip into JS wouldn't be able to make use of that. ---------------------------------------------------------------------------------------------------- [01:53:35] Jamie Gaskins(@jgaskins):I think running the UI interactions through at least a headless browser is still a good idea since they'd act as integration tests, while your unit tests can still check that component methods handle their own business and your store updates state appropriately in response to an action in faster server-side code. ---------------------------------------------------------------------------------------------------- [17:51:48] Adam Jahn(@ajjahn):@catmando That’s an interesting approach. I remember discussing it a while back. I think for me it seems like a lot of extra machinery involved than what I’m looking for. I’d like to unit test my components the same way I would with plain old ruby classes. But yeah, I’ll have a look at hyper-spec. @jgaskins I’m unit testing in MRI pretty much like you described. It’s browsery stuff, like `render` and ui-events that I haven’t found a great solution for. > For all UI interactions I've just been testing them through Poltergeist Do you mean just testing your components as part of a traditional integration test by going through you app’s full stack, or are you isolating them at all? I had experimented a while back with a PhantomJS driver that uses [onCallback](http://phantomjs.org/api/webpage/handler/on-callback.html) to send messages from opal specs out to PhantomJS to orchestrate UI interactions. I got far enough to convince myself it would work, but haven’t had time to flesh it out far enough to actually use it. Mocking out the DOM in MRI is interesting. Possibly an MRI Bowser as well? ---------------------------------------------------------------------------------------------------- [18:25:32] Mitch VanDuyn(@catmando):@ajjahn yeah we did discuss it, and u gave me some key ideas particularly​ about needing to modify class behavior for white box testing. As far as extra machinery.. well it's a bit but probably less than duplicating the whole of rspec on the client :-) ---------------------------------------------------------------------------------------------------- [18:28:02] Mitch VanDuyn(@catmando):However if u have a clear separation between client and server, hyperspec wouldn't make sense. But u might get a few ideas... ---------------------------------------------------------------------------------------------------- [18:29:59] Adam Jahn(@ajjahn):@catmando Yeah. A have a handful of components that fall into the UI toolkit category. They should be portable from app to app and have no notion of a server at all. ---------------------------------------------------------------------------------------------------- [18:34:34] Mitch VanDuyn(@catmando):Still reading your original question, a lot of that is covered by capybara, so perhaps it's worth a look.. ---------------------------------------------------------------------------------------------------- [23:42:40] Jamie Gaskins(@jgaskins):@ajjahn Yeah, traditional integration-test style. I don't do any UI interactions in isolation, but if anyone comes up with a backend-agnostic way to do that, I'm willing to experiment with it. ---------------------------------------------------------------------------------------------------- ############################## [2017-05-14] ############################## [04:35:34] Jamie Gaskins(@jgaskins):It's been kinda quiet in here, but I've been working on things quite a bit lately. I added some content to the API-reference section on the [Clearwater docs site](https://clearwater-docs.herokuapp.com/) (including standardizing that section on using `ClassDoc` and `MethodDoc` components). Finishing up that content will be great, then we can do a bit of styling and I'll go ahead and release Clearwater 1.0. ---------------------------------------------------------------------------------------------------- [04:37:30] Jamie Gaskins(@jgaskins):I've also released Bowser 0.4.0 that includes native delegation for `Bowser.window` and `Bowser.document` similar to how `Bowser::Element`s do. ---------------------------------------------------------------------------------------------------- [04:38:43] Jamie Gaskins(@jgaskins):`clearwater-hot_loader` has also gotten better error handling on both client and server sides. ---------------------------------------------------------------------------------------------------- ############################## [2017-05-15] ############################## [15:56:54] Forrest Chang(@fkchang):@jgaskins cool beans! ---------------------------------------------------------------------------------------------------- ############################## [2017-05-30] ############################## [03:19:22] Jamie Gaskins(@jgaskins):https://twitter.com/jamie_gaskins/status/869372378190671872 ---------------------------------------------------------------------------------------------------- [03:40:56] Jamie Gaskins(@jgaskins):I'm ridiculously happy with how well that turned out ^^ ---------------------------------------------------------------------------------------------------- [03:42:23] Jamie Gaskins(@jgaskins):And it's just under 300 lines of Ruby code. It'll be less once #70 is released in Clearwater because I had to reimplement it there. It's also what prompted me to merge #70 into `master`. ---------------------------------------------------------------------------------------------------- [04:29:41] Forrest Chang(@fkchang):@jgaskins congrats, I'll have to check it out ---------------------------------------------------------------------------------------------------- [23:06:16] Jamie Gaskins(@jgaskins):@fkchang You should still be able to use it even if you're not running Clearwater for your own app. It does run a Clearwater app of its own, but it just needs is a reference to your store. ---------------------------------------------------------------------------------------------------- ############################## [2017-07-04] ############################## [05:55:25] Jamie Gaskins(@jgaskins):I was just watching Ryan Florence's "Compound Components" talk (https://www.youtube.com/watch?v=hEGg-3pIHlE) ---------------------------------------------------------------------------------------------------- [05:56:01] Jamie Gaskins(@jgaskins):And it's a pretty great architecture, so I made a proof of concept (though not as well styled) in Clearwater: https://gist.github.com/jgaskins/47454f2b9f7030090dd701aa925c694e ---------------------------------------------------------------------------------------------------- [05:57:58] Jamie Gaskins(@jgaskins):I find this code a whole lot easier to read and work with than the `React.Children.map(this.props.children, child => React.cloneElement(child, { prop1 }))` dance he was doing in that video. ---------------------------------------------------------------------------------------------------- [06:01:59] Jamie Gaskins(@jgaskins):It always makes me happy when Clearwater has a better developer experience than React — a framework that prides itself on the developer experience. ---------------------------------------------------------------------------------------------------- [14:57:20] codem4ster(@codem4ster):hi folks, is there any example for the server side rendering on rails side? ---------------------------------------------------------------------------------------------------- ############################## [2017-07-05] ############################## [13:23:02] codem4ster(@codem4ster):I tried this without luck ---------------------------------------------------------------------------------------------------- [13:24:22] codem4ster(@codem4ster):test needs to be rendered as `Components::Pages::Test` but in the `Components::Layouts::Main` scope ---------------------------------------------------------------------------------------------------- [13:26:02] codem4ster(@codem4ster):I need something like this; ```ruby # Router Routes = proc do route 'admin' => Components::Layouts::Admin.new do route 'dashboard' => Components::Pages::Admin::Dashboard.new end route '/' => Components::Layouts::Main.new do route 'test' => Components::Pages::Test.new end end ``` ---------------------------------------------------------------------------------------------------- [22:13:31] Jamie Gaskins(@jgaskins):@codem4ster Can't do different layouts per top-level route. There are a couple ways you can achieve the same effect, though: - wrap the top-level routing target inside another component (this is one of the reasons routing targets are objects rather than classes) - make different apps for user-facing and admin — you should be able to reuse a lot of the same code if you manage dependencies well ---------------------------------------------------------------------------------------------------- [22:17:11] Jamie Gaskins(@jgaskins):When I say wrap the routing target, this is what I mean: ```ruby Routes = proc do route 'admin' => Layouts::Admin.new(Pages::Admin.new) do route 'dashboard' => Pages::Dashboard.new end route 'test' => Layouts::Main.new(Pages::Test.new) end class PassThrough include Clearwater::Component # Doesn't do anything but delegate to the outlet or to a default home page def render outlet || Layouts::Main.new(Pages::Home.new) end end ``` ---------------------------------------------------------------------------------------------------- [22:18:35] Jamie Gaskins(@jgaskins):And the layout components then take their default page (which you could call `@outlet` for consistency) ---------------------------------------------------------------------------------------------------- [22:43:46] Jamie Gaskins(@jgaskins):I've also played around with the idea of a React Router v4-like router (a lot like Roda's router, too, tbh) to use instead of Clearwater's default router. [Here's the code for it (no gem yet)](https://gist.github.com/jgaskins/7b4d2dda8b539f1ae43a6aaa04683a7f) with an example app showing its use. It decentralizes routing so that each routing target knows what its child routes are. ---------------------------------------------------------------------------------------------------- [11:32:09] codem4ster(@codem4ster):and in the wild this always happen ---------------------------------------------------------------------------------------------------- [11:32:27] Jamie Gaskins(@jgaskins):Yeah, I use it all the time. :-) ---------------------------------------------------------------------------------------------------- [11:33:03] codem4ster(@codem4ster):I learned this by the hard the way :( ---------------------------------------------------------------------------------------------------- [11:33:26] codem4ster(@codem4ster):closed my SPA blog :( ---------------------------------------------------------------------------------------------------- [11:33:35] Jamie Gaskins(@jgaskins):I've used an approach similar to the `gon` gem for that to send the data along with the initial payload. ---------------------------------------------------------------------------------------------------- [11:34:13] Jamie Gaskins(@jgaskins):So that the app didn't have to make an ajax request on load. ---------------------------------------------------------------------------------------------------- [11:35:24] codem4ster(@codem4ster):hmm, I hear this first time, I will look. ---------------------------------------------------------------------------------------------------- [11:37:23] Jamie Gaskins(@jgaskins):You can use the `gon` gem itself, but then in your client app you'll need to do something like `articles = %x{gon.articles}.map { |obj| Article.new(Hash.new(obj)) }`. I wanted to make a similar gem that would automatically set up everything for a Ruby client, but I just haven't gotten around to it yet. :-) ---------------------------------------------------------------------------------------------------- [11:38:41] codem4ster(@codem4ster):I think this gem write the data to js on the run ---------------------------------------------------------------------------------------------------- [11:38:47] Jamie Gaskins(@jgaskins):Basically, because `gon` gives you raw JS objects, you have to convert them to hashes before they're usable. ---------------------------------------------------------------------------------------------------- [11:38:49] Jamie Gaskins(@jgaskins):Yep ---------------------------------------------------------------------------------------------------- [11:38:51] codem4ster(@codem4ster):into the source ---------------------------------------------------------------------------------------------------- [11:39:04] codem4ster(@codem4ster):but I don't prefer this way also ---------------------------------------------------------------------------------------------------- [11:39:21] codem4ster(@codem4ster):there is uncompressed js code ---------------------------------------------------------------------------------------------------- [11:39:43] codem4ster(@codem4ster):and I personally hate inline js code :) ---------------------------------------------------------------------------------------------------- [11:40:14] codem4ster(@codem4ster):but it's pragmatic and practical ---------------------------------------------------------------------------------------------------- [11:41:17] Jamie Gaskins(@jgaskins):Yep. Unfortunately, if you server-render, you won't have the actual models for the client to render without something like that — it'll all just be in HTML markup. ---------------------------------------------------------------------------------------------------- [11:43:11] codem4ster(@codem4ster):Actually I have thought about a proxy class which works both in frontend and backend ---------------------------------------------------------------------------------------------------- [11:43:37] Jamie Gaskins(@jgaskins):The only way I've found that works well with server rendering is using something like `gon` alongside the server-rendered markup. Unfortunately, it means you're including the models 2x in the initial payload (once for the raw data and once in the rendered HTML). I'd love to see more people experimenting with it to find a good pattern. ---------------------------------------------------------------------------------------------------- [11:43:55] Jamie Gaskins(@jgaskins):Proxy class? This sounds interesting. ---------------------------------------------------------------------------------------------------- [11:44:18] codem4ster(@codem4ster):it simply return data from an action/operation like class ---------------------------------------------------------------------------------------------------- [11:45:24] codem4ster(@codem4ster):this action/operation like class has one responsibility and only returns a key value pair ---------------------------------------------------------------------------------------------------- [11:45:59] codem4ster(@codem4ster):proxy class is hybrid and in frontend it uses ajax or websocket to run the operation ---------------------------------------------------------------------------------------------------- [11:46:26] codem4ster(@codem4ster):and on the backend it uses simply run for the operation class ---------------------------------------------------------------------------------------------------- [11:46:58] codem4ster(@codem4ster):I'm looking for react, hyperloop, clearwater etc... ---------------------------------------------------------------------------------------------------- [11:47:11] codem4ster(@codem4ster):and I see that only missing part is this ---------------------------------------------------------------------------------------------------- [11:47:43] Jamie Gaskins(@jgaskins):That sounds interesting. Are you working on a gem or something for it? I'd be happy to see it and try it out. ---------------------------------------------------------------------------------------------------- [11:48:08] codem4ster(@codem4ster):I attempted to write this several times but ---------------------------------------------------------------------------------------------------- [11:48:33] codem4ster(@codem4ster):I don't have a parser like clearwater ---------------------------------------------------------------------------------------------------- [11:48:48] codem4ster(@codem4ster):so I came here and hyperloop chat rooms ---------------------------------------------------------------------------------------------------- [11:49:16] codem4ster(@codem4ster):you had done all the hard parts ---------------------------------------------------------------------------------------------------- [11:49:19] Jamie Gaskins(@jgaskins):lol ---------------------------------------------------------------------------------------------------- [11:49:41] codem4ster(@codem4ster):if I learn the clearwater or hyperloop ---------------------------------------------------------------------------------------------------- [11:50:02] codem4ster(@codem4ster):I want to add this feature ---------------------------------------------------------------------------------------------------- [11:50:37] codem4ster(@codem4ster):I succeed this concept with opal-slim parser ---------------------------------------------------------------------------------------------------- [11:51:33] codem4ster(@codem4ster):but that was so experimental and far away from a gem ---------------------------------------------------------------------------------------------------- [11:52:45] Jamie Gaskins(@jgaskins):You wrote something like `opal-slim`, too? ---------------------------------------------------------------------------------------------------- [11:52:52] codem4ster(@codem4ster):nope ---------------------------------------------------------------------------------------------------- [11:53:28] codem4ster(@codem4ster):I tried to write a full frontend framework with this feature ---------------------------------------------------------------------------------------------------- [11:53:28] Jamie Gaskins(@jgaskins):Oh, okay. I misunderstood. lol ---------------------------------------------------------------------------------------------------- [11:53:47] codem4ster(@codem4ster):but the hard parts was missing ---------------------------------------------------------------------------------------------------- [11:54:23] codem4ster(@codem4ster):like parser ---------------------------------------------------------------------------------------------------- [11:54:32] codem4ster(@codem4ster):so I decided to use opal-slim ---------------------------------------------------------------------------------------------------- [11:54:39] Jamie Gaskins(@jgaskins):Ahhh, okay ---------------------------------------------------------------------------------------------------- [11:54:51] codem4ster(@codem4ster):and achieve server-side rendering with it ---------------------------------------------------------------------------------------------------- [11:55:26] codem4ster(@codem4ster):slim code can be parsed on frontend and backend thanks to opal ---------------------------------------------------------------------------------------------------- [11:55:35] Jamie Gaskins(@jgaskins):I loved using `opal-slim` so much, I was mad I couldn't use it with Clearwater's virtual DOM. ---------------------------------------------------------------------------------------------------- [11:55:37] Jamie Gaskins(@jgaskins)::-) ---------------------------------------------------------------------------------------------------- [11:55:44] codem4ster(@codem4ster):you can use ---------------------------------------------------------------------------------------------------- [11:56:00] codem4ster(@codem4ster):I meet with clearwater 1,5 years ago ---------------------------------------------------------------------------------------------------- [11:56:31] Jamie Gaskins(@jgaskins):Right, when Clearwater used to render HTML, it was what I used. ---------------------------------------------------------------------------------------------------- [11:56:37] codem4ster(@codem4ster):and I didn't want to use because of slim or haml support missing ---------------------------------------------------------------------------------------------------- [11:56:53] codem4ster(@codem4ster):yes I know your first work :) ---------------------------------------------------------------------------------------------------- [11:56:58] Jamie Gaskins(@jgaskins)::-D ---------------------------------------------------------------------------------------------------- [11:57:42] codem4ster(@codem4ster):but now I found isomorphism is better ---------------------------------------------------------------------------------------------------- [11:58:26] Jamie Gaskins(@jgaskins):But since Clearwater moved to a virtual DOM, I haven't been able to make it work. I tried so hard for weeks to get it working, but I ended up having to just go with the Ruby DSL. I still like both ways, tbh. ---------------------------------------------------------------------------------------------------- [11:59:20] Jamie Gaskins(@jgaskins):Yeah, I think people can go too far with isomorphic code, but it's _definitely_ useful. ---------------------------------------------------------------------------------------------------- [12:01:09] Jamie Gaskins(@jgaskins):It's like functional programming or any new concept you learn, where you just want to apply it to _everything_ once you learn it because it's so much fun. :-) Hard to know when to stop. ---------------------------------------------------------------------------------------------------- [12:01:41] codem4ster(@codem4ster):yes ---------------------------------------------------------------------------------------------------- [12:01:58] codem4ster(@codem4ster):I have a question about server side rendering Jamie ---------------------------------------------------------------------------------------------------- [12:02:09] Jamie Gaskins(@jgaskins):Sure ---------------------------------------------------------------------------------------------------- [12:02:23] codem4ster(@codem4ster):```ruby # Main site pages class HomeController < ApplicationController def index @app = Clearwater::Application.new( component: Components::Layouts::Main.new, router: Clearwater::Router.new(location: request) ) end end ``` ---------------------------------------------------------------------------------------------------- [12:02:32] codem4ster(@codem4ster):I wrote this ---------------------------------------------------------------------------------------------------- [12:03:17] codem4ster(@codem4ster):in clearwater there is something named `outlet` ---------------------------------------------------------------------------------------------------- [12:03:54] codem4ster(@codem4ster):I used that in my layout like this; ---------------------------------------------------------------------------------------------------- [12:04:00] codem4ster(@codem4ster):```ruby require 'clearwater/component' module Components module Layouts # Main Layout class Main include Clearwater::Component def render div([ Components::Partials::Header.new, outlet, Components::Partials::Footer.new ]) end end end end ``` ---------------------------------------------------------------------------------------------------- [12:04:20] Jamie Gaskins(@jgaskins):Oh, right. The server-side router needs to know about all the routes, too. ---------------------------------------------------------------------------------------------------- [12:04:27] codem4ster(@codem4ster):yep ---------------------------------------------------------------------------------------------------- [12:04:48] codem4ster(@codem4ster):`/another-page` must be rendered inside layout ---------------------------------------------------------------------------------------------------- [12:04:57] Jamie Gaskins(@jgaskins):Now I remember, this was one of the major friction points of server-side rendering. ---------------------------------------------------------------------------------------------------- [12:05:10] Jamie Gaskins(@jgaskins):There are a couple ways to handle this that I've found: ---------------------------------------------------------------------------------------------------- [12:06:04] Jamie Gaskins(@jgaskins):Actually wait, no, one of them doesn't work because the router needs the request path on initialize. ---------------------------------------------------------------------------------------------------- [12:08:16] codem4ster(@codem4ster):so how can I achive this? ---------------------------------------------------------------------------------------------------- [12:08:36] Jamie Gaskins(@jgaskins):There's actually only one way I've found to make it work. :-D Set a `Routes` constant in an isomorphic file and use it as your route block: ```ruby Routes = proc do route 'articles' => ArticlesRoute.new end ``` Then in your server-side app: ```ruby @app = Clearwater::Application.new( component: Layout.new, router: Clearwater::Router.new(location: request, &Routes) ) ``` ---------------------------------------------------------------------------------------------------- [12:09:09] Jamie Gaskins(@jgaskins):Your client-side app would be done similarly, you just wouldn't have to specify the location for the router ---------------------------------------------------------------------------------------------------- [12:09:39] codem4ster(@codem4ster):ok I'm trying ---------------------------------------------------------------------------------------------------- [12:09:46] Jamie Gaskins(@jgaskins):It's the only way I know how to share routes between them. ---------------------------------------------------------------------------------------------------- [12:09:58] codem4ster(@codem4ster):not bad ---------------------------------------------------------------------------------------------------- [12:10:48] Jamie Gaskins(@jgaskins):Declaring the router globally doesn't work on the server because it has to have the path for the individual request, so it has to be instantiated per-request. ---------------------------------------------------------------------------------------------------- [12:11:06] Jamie Gaskins(@jgaskins):It's been a while since I've had to mess with this, so I'm going on foggy memories here. :-) ---------------------------------------------------------------------------------------------------- [12:11:32] codem4ster(@codem4ster):didn't you use this later? ---------------------------------------------------------------------------------------------------- [12:11:56] Jamie Gaskins(@jgaskins):Yeah, but once server rendering is setup, you don't need to mess with it much ---------------------------------------------------------------------------------------------------- [12:13:29] Jamie Gaskins(@jgaskins):It's just one of those things where you configure your app to do it once and probably never touch that configuration again. :-) ---------------------------------------------------------------------------------------------------- [12:15:16] Jamie Gaskins(@jgaskins):I'd like to make a Rails template to handle server-side rendering out of the box, as well as set up things like `Clearwater::HotLoader` (in dev) and `GrandCentral` for you. ---------------------------------------------------------------------------------------------------- [12:17:22] Jamie Gaskins(@jgaskins):I've also been thinking about that for the `clearwater-roda`gem. Most of my Clearwater app development is on a Roda back end, so I tried to make that easier to work with, too. ---------------------------------------------------------------------------------------------------- [12:19:15] codem4ster(@codem4ster):```ruby # Main site pages class HomeController < ApplicationController ROUTES = proc do route '/' => Components::Layouts::Main.new do route 'test' => Components::Pages::Test.new end end def index @app = Clearwater::Application.new( component: Components::Layouts::Main.new, router: Clearwater::Router.new(location: request, &ROUTES) ) end end ``` ---------------------------------------------------------------------------------------------------- [12:19:22] codem4ster(@codem4ster):I wrote this ---------------------------------------------------------------------------------------------------- [12:19:40] codem4ster(@codem4ster):```ruby module Components module Pages # Test page class Test include Clearwater::Component def render h1 'This is test page' end end end end ``` ---------------------------------------------------------------------------------------------------- [12:20:28] codem4ster(@codem4ster):```ruby require 'clearwater/component' module Components module Layouts # Main Layout class Main include Clearwater::Component def render div([ Components::Partials::Header.new, outlet, Components::Partials::Footer.new ]) end end end end ``` ---------------------------------------------------------------------------------------------------- [12:21:27] Jamie Gaskins(@jgaskins):Oh, you don't need the `route '/'`. That's implied. ---------------------------------------------------------------------------------------------------- [12:22:10] Jamie Gaskins(@jgaskins):That is, since you're passing the layout as the root component to your app, it will always be rendered and doesn't need to be passed to the router. ---------------------------------------------------------------------------------------------------- [12:32:32] codem4ster(@codem4ster):great ---------------------------------------------------------------------------------------------------- [12:32:34] codem4ster(@codem4ster):it worked ---------------------------------------------------------------------------------------------------- [12:32:47] codem4ster(@codem4ster):is this enough for client side also ---------------------------------------------------------------------------------------------------- [12:33:12] codem4ster(@codem4ster):do I need to do extra things ---------------------------------------------------------------------------------------------------- [12:45:20] Jamie Gaskins(@jgaskins):Yes, it should work client-side, too. If you define `ROUTES` somewhere that can be loaded on both the client and server, you can just edit it in one place. ---------------------------------------------------------------------------------------------------- [13:00:09] codem4ster(@codem4ster):I want to use a different layout for /admin/* ---------------------------------------------------------------------------------------------------- [13:00:20] codem4ster(@codem4ster):and /* ---------------------------------------------------------------------------------------------------- [13:00:26] codem4ster(@codem4ster):is this possible ---------------------------------------------------------------------------------------------------- [13:22:55] codem4ster(@codem4ster):```ruby # Router Routes = proc do route 'admin' => Components::Layouts::Admin.new do route 'dashboard' => Components::Pages::Admin::Dashboard.new end route 'test' => Components::Layouts::Main.new end ``` ---------------------------------------------------------------------------------------------------- [03:05:10] Jamie Gaskins(@jgaskins):@codem4ster I just hacked together a quick server-rendered example. Links to specific files are in the readme: https://github.com/jgaskins/server_rendered_clearwater_example ---------------------------------------------------------------------------------------------------- [03:05:20] Jamie Gaskins(@jgaskins):That app will render even with JS disabled ---------------------------------------------------------------------------------------------------- [03:06:30] Jamie Gaskins(@jgaskins):If you're storing state in a [Grand Central store](https://github.com/clearwater-rb/grand_central), it, its actions, and its models can all be used on the server as well as the client. ---------------------------------------------------------------------------------------------------- [03:07:58] Jamie Gaskins(@jgaskins):@codem4ster I'm happy to see people looking at server rendering, though. I spent a long time making it work! :-D ---------------------------------------------------------------------------------------------------- [03:08:40] Jamie Gaskins(@jgaskins):If there's anything unclear about that example app, let me know. I made the mistake of writing the readme for it _after_ I wrote the code so I may not have added all of the steps to it. ---------------------------------------------------------------------------------------------------- [06:12:50] codem4ster(@codem4ster):Without server side rendering SPAs can only be used as admin panel like projects. ---------------------------------------------------------------------------------------------------- [06:13:40] codem4ster(@codem4ster):if you want Google parse your page you must use server side rendering. So this is important :( ---------------------------------------------------------------------------------------------------- [06:47:50] codem4ster(@codem4ster):I tried your example and it works great, I'm very impressed. Thanks for your work. :D ---------------------------------------------------------------------------------------------------- [06:50:11] codem4ster(@codem4ster):I will try to build a simple blog with clearwater ---------------------------------------------------------------------------------------------------- [07:41:24] codem4ster(@codem4ster):I think hot loader doesn't work with hybrid (server + client) components. Changes on the layout is not reflecting to browser without refresh. And a note for your example; If you use $LOAD_PATH instead of rails autoload paths, page refresh doesn't reflect changes on shared components ~it needs server restart~. So I added `shared` to autoload paths instead of $LOAD_PATH. ---------------------------------------------------------------------------------------------------- [11:20:29] Jamie Gaskins(@jgaskins):Ah, good point. ---------------------------------------------------------------------------------------------------- [11:21:52] Jamie Gaskins(@jgaskins):Yeah, HotLoader is hardcoded to use `app/assets` and `assets` right now, I think. I'd like to add the ability to add others, I just haven't gotten to it yet. :-) Would you mind opening an issue? ---------------------------------------------------------------------------------------------------- [11:24:59] Jamie Gaskins(@jgaskins):> if you want Google parse your page you must use server side rendering This was true for a long time, but Google can indeed handle SPAs now: https://webmasters.googleblog.com/2015/10/deprecating-our-ajax-crawling-scheme.html ---------------------------------------------------------------------------------------------------- [11:29:36] codem4ster(@codem4ster):Nope, it still cannot parse ajax or websocket requests. If a component needs data from server to be rendered, then google cannot parse it :( ---------------------------------------------------------------------------------------------------- [11:31:07] codem4ster(@codem4ster):google is supporting only static javascript code ---------------------------------------------------------------------------------------------------- [11:31:49] Jamie Gaskins(@jgaskins):Ah, I see what you mean — requests made after the page loads ---------------------------------------------------------------------------------------------------- [11:31:55] codem4ster(@codem4ster):yep ---------------------------------------------------------------------------------------------------- ############################## [2017-07-06] ############################## [06:36:53] codem4ster(@codem4ster):it gave `wrong number of arguments (given 1, expected 0)` so I made some modifications to layout; ---------------------------------------------------------------------------------------------------- [06:37:16] codem4ster(@codem4ster):```ruby require 'clearwater/component' module Components module Layouts # Main Layout class Admin include Clearwater::Component attr_reader :child def initialize(child) @child = child end def render div([ Components::Partials::Header.new, h3('This is admin page'), child, Components::Partials::Footer.new ]) end end end end ``` ---------------------------------------------------------------------------------------------------- [06:38:06] codem4ster(@codem4ster):It worked with this, but I'm not sure this is the best way :/ ---------------------------------------------------------------------------------------------------- [11:22:48] Jamie Gaskins(@jgaskins):Yeah, sorry, I could've clarified that you'd need to take the child component as a parameter. :-) Including the mixin doesn't change `initialize` at all, so it still belongs to you. ---------------------------------------------------------------------------------------------------- [11:25:58] Jamie Gaskins(@jgaskins):I agree that your particular scenario doesn't feel like a great use case for Clearwater's built-in router. In general, it's fine. The RR4-style router (linked in a gist above) might be better for you, but it's still pretty experimental. ---------------------------------------------------------------------------------------------------- [13:11:48] codem4ster(@codem4ster):is there any way to use do blocks as in hyperloop, with this its a little bit hard to write html sides can we write this; ---------------------------------------------------------------------------------------------------- [13:12:54] codem4ster(@codem4ster):```ruby div(class: 'box') { 'some text' } ``` ---------------------------------------------------------------------------------------------------- [13:13:45] codem4ster(@codem4ster):instead of this; ```ruby div({ class: 'box' }, ['some text']) ``` ---------------------------------------------------------------------------------------------------- ############################## [2017-07-07] ############################## [07:56:04] codem4ster(@codem4ster):hi @jgaskins I wrote some code for last feature that I'm asked ---------------------------------------------------------------------------------------------------- [07:56:20] codem4ster(@codem4ster):```ruby require 'pp' class Component HTML_TAGS = %w[a div span h1 h2 h3 h4 h5 h6 head br] HTML_TAGS.each do |tag_name| define_method tag_name do |&content| tag(tag_name, &content) end end attr_writer :text def text @text ||= [] end def buffer @buffer ||= [] end def plain(text_data) text << text_data end def tag(tag_name, &content) text << "<#{tag_name}>" if block_given? result = instance_eval(&content) if text != result buffer << result if result.is_a? String buffer.concat result if result.is_a? Array text.concat buffer @buffer = [] end end text << "" text end end class Comp1 < Component def render h1 do div do a { 'exe' } plain('blah') br end div { 'another title' } a end end end pp Comp1.new.render ``` ---------------------------------------------------------------------------------------------------- [07:56:55] codem4ster(@codem4ster):this is just proof of concept, I will fork your repo and implement this ---------------------------------------------------------------------------------------------------- [07:57:30] codem4ster(@codem4ster):If you want I can open a pull request after work done ---------------------------------------------------------------------------------------------------- ############################## [2017-07-08] ############################## [05:16:06] Jamie Gaskins(@jgaskins):@codem4ster You don't need to fork Clearwater to do that, you can do that at the application level. :-) ---------------------------------------------------------------------------------------------------- [05:48:51] Jamie Gaskins(@jgaskins):Or you can publish a gem that offers that structure. I'm not a fan of the block syntax for DOM content, though. It's been proposed several times for Clearwater, and I think it's aesthetically quite nice, but has a few issues: - Ruby blocks are typically used for side effects or return values and this form uses them for something else entirely - DOM elements, when you boil them down, are just objects with a hash of properties and a list of child nodes. The hash and array arguments to the tag methods represent that. - Clearwater's tag methods are intended to be pure functions (takes arguments, returns a value, doesn't depend on or mutate any state outside of itself), but the block syntax has to maintain an accumulator between method calls, making it no longer a pure function. - Since you have to maintain an accumulator, you can't generate a `div` without a component instance. The benefit of the pure function is that you can call `Clearwater::Component.div({ id: 'foo' }, ['hello world'])`, for example, if you're in an object that isn't a component but generates UI content. If you enabled that for your example, `Component.div { 'foo' }` would store that virtual-DOM node on the `Component` class itself and it would never be GCed. It would accumulate these vdom nodes until the device ran out of memory, so it becomes impossible to do without extra boilerplate. - Having to call `text` for a raw text node or `component` for a child component should be unnecessary because components rendering text nodes and child components is so common. `Clearwater::Component` treats strings and component instances the way you expect without having to wrap them in another function call. ---------------------------------------------------------------------------------------------------- ############################## [2017-07-10] ############################## [06:07:10] codem4ster(@codem4ster):hmm I understand you ---------------------------------------------------------------------------------------------------- [06:07:29] codem4ster(@codem4ster):and you're 100% right ---------------------------------------------------------------------------------------------------- [06:10:43] codem4ster(@codem4ster):I get into troubles as you said in your last two clause ---------------------------------------------------------------------------------------------------- [06:11:43] codem4ster(@codem4ster):but it's very hard to write in array form ---------------------------------------------------------------------------------------------------- [06:11:58] codem4ster(@codem4ster):I will try my luck with slim again ---------------------------------------------------------------------------------------------------- [06:22:34] codem4ster(@codem4ster):But I think I firstly need to understand virtual-dom perfectly ---------------------------------------------------------------------------------------------------- [07:22:58] Colin Gunn(@balmoral):FWIW I completely agree with @jgaskins about not using block syntax for DOM content (like Paggio and Hyperloop). I love Clearwater’s straightforward low-magic approach, but I have struggled with the virtual dom and having to work around it too often (gettting my head around black boxes, cached components, etc). The Hyperloop guys are doing some great work, but I don’t want all the baggage (react, active record), and the DSL doesn’t really appeal. I don’t want to use Paggio which comes with opal-browser but I like that opal-browser is simply that - the browser. Influenced by Volt and React/Hyperloop, I want a simple way to ‘bind’ state to the view, por make the view ‘react’ to changes in state. So I’ve had a go at reinventing the wheel for an app I’m doing. Here's an example of the navbar: ``` class NavBar < Racs::Client::Component def render nav.css(:navbar, :navbar_default).style(margin_bottom: 0) << bind(user) do div.css(:collapse, :navbar_collapse)[ main_menu, user_menu ] end end def main_menu ul.css(:nav, :navbar_nav)[ if user.permitted?(:order_view) list_item_link('Orders', '/orders') end, if user.permitted?(:production_view) list_item_link('Production', '/production') end, if user.permitted?(:product_view) list_item_link('Products', '/products') end, if user.permitted?(:customer_view) list_item_link('Customers', '/customers') end, if user.permitted?(:database) list_item_link('Database', '/database') end, if user.permitted?(:users) list_item_link('Users', 'users') end ] end def user_menu ul.css(:nav, :navbar_nav, :navbar_right)[ li.css(:dropdown)[ link.css(:dropdown_toggle).data(toggle: :dropdown)[ span[user.id], span.css(:caret).style(margin_left: 0.5.em) ], li.css(:dropdown_menu).style(width: 2.em)[ list_item_link('Sign out') { app.sign_out } ] ] ] end # returns a list item (li) wrapping a link def list_item_link(label, href = nil, &block) args = [:link, { content: label }] args.last.merge!(href: href) if href args.last.merge!(on: { click: block }) if block tag(:li, tag(*args)) end end end end ``` ---------------------------------------------------------------------------------------------------- [07:26:09] Colin Gunn(@balmoral):The `bind` is the reactive binding between `user` state and the view. When `user` state mutates, the binding block is called and the view updated. Bindings can be on content or any element attribute. ---------------------------------------------------------------------------------------------------- [07:29:27] Colin Gunn(@balmoral):Instead of blocks to deliver component/element content you can use `.content(…)` or `[…]` or `<<`. And you can chain attributes simply using chainged method calls `div.css(…).on(…).stlye(…).data(…)…`. ---------------------------------------------------------------------------------------------------- [07:31:05] Colin Gunn(@balmoral):So many ways to skin the cat, but this is working for me so far. Just want to credit @jgaskins for inspiration and example. :smile: ---------------------------------------------------------------------------------------------------- [22:49:01] Jamie Gaskins(@jgaskins):@balmoral I really like the way that looks. ---------------------------------------------------------------------------------------------------- [22:53:32] Jamie Gaskins(@jgaskins):That's one of the reasons I'm really glad we ended up making components basically `render`-able objects, so people could design their own component superclass/mixins. I know how I like to use Clearwater, but I'm not silly enough to think how I use it will be how others do. ---------------------------------------------------------------------------------------------------- [22:55:16] Jamie Gaskins(@jgaskins):Not only that, but the larger (4-5 digit LOC) Clearwater apps I've written used vastly different patterns from the ones in my smaller apps. So we can't assume that everyone's going to use it the way we do and supporting a little fragmentation is a call I'm glad to have made. ---------------------------------------------------------------------------------------------------- [22:59:24] Jamie Gaskins(@jgaskins):@balmoral I'm with you that `BlackBoxNode` and `CachedRender` take some getting used to, though. I really want to finish up the docs site that I've been trying to build. I just hate writing documentation so much! :-D ---------------------------------------------------------------------------------------------------- [22:59:46] Jamie Gaskins(@jgaskins):Here's what I've got so far for BBN: https://clearwater-docs.herokuapp.com/api/black_box_node ---------------------------------------------------------------------------------------------------- [23:01:43] Jamie Gaskins(@jgaskins):Hilariously, the example code for `BlackBoxNode` is itself a `BlackBoxNode` (for the syntax highlighting): https://github.com/clearwater-rb/clearwater_docs/blob/master/assets/js/components/api/black_box_node.rb ---------------------------------------------------------------------------------------------------- [23:03:43] Jamie Gaskins(@jgaskins):Some other stuff I have planned for that site are executable examples, like the Ember site used to have, but that's future stuff. ---------------------------------------------------------------------------------------------------- ############################## [2017-07-11] ############################## [16:22:50] Mitch VanDuyn(@catmando):@jgaskins @balmoral re: `div.css(...).on(...)` etc... this is the way hyperloop attaches blocks as well (i.e. on handlers etc) it works quite nicely. However the attributes remain inside the call to the tag, for compatibility with react.js ---------------------------------------------------------------------------------------------------- ############################## [2017-07-12] ############################## [03:06:28] Jamie Gaskins(@jgaskins):@catmando Doesn't Hyperloop do it like `button { 'foo' }.on(:click) { bar }`, though? ---------------------------------------------------------------------------------------------------- [04:31:37] Colin Gunn(@balmoral):@catmando @jgaskins The main things I wanted (personal preference only :smile:) are conciseness, no blocks, no uppercase tags, minimal opacity, and minimal ambiguity. The [] operator to specify content has a block like syntax but avoids possible confusion/issues in an instance_eval block. There’s also a `.content(...)` clause if preferred. My binding mechanism is explicit and simple which suits me. I’m still trying to fathom how Hyperloop does its react magic. Or for that matter how react does its react magic. My stuff is currently running on top of `opal-browser` but could easily plugin to Clearwater as an alternate syntax. I think Clearwater and Hyperloop are fantastic examples of client/server Ruby platforms, as was Volt in its day. I’m pilfering all the best bits from each as fit my needs. I’ve learned so much from you guys and your frameworks. So no criticism intended - indeed, quite the opposite. My coding these days is mostly for pleasure, so I can indulge in some experimentation and reinventing of already working wheels. :smile: ---------------------------------------------------------------------------------------------------- ############################## [2017-07-22] ############################## [16:30:10] Billy.Zheng(@zw963):@/all opal community is so small, everywhere is familiar face. ---------------------------------------------------------------------------------------------------- [16:34:01] Billy.Zheng(@zw963):@jgaskins , I had quick review `hyperloop` and ` inesita`. former is based on `react`, latter is based on [opal-virtual-dom](https://github.com/fazibear/opal-virtual-dom), What `clearwater` is based on? manipulate DOM. thanks. ---------------------------------------------------------------------------------------------------- [19:02:00] Jamie Gaskins(@jgaskins):@zw963 It uses the [`virtual-dom`](https://github.com/Matt-Esch/virtual-dom/) library, just like `opal-virtual-dom` does, but Clearwater wraps it directly rather than requiring the application developer to know about it, which results in smaller JS payloads and faster load times due to more focused bindings. ---------------------------------------------------------------------------------------------------- [19:03:35] Jamie Gaskins(@jgaskins): Inesita's author used Clearwater for a lot of inspiration for Inesita, but wanted to have a Ruby API for all the things `virtual-dom` provides. In contrast, Clearwater's ruby bindings to `virtual-dom` are _very_ minimal and aren't really intended for general usage. ---------------------------------------------------------------------------------------------------- ############################## [2017-07-23] ############################## [02:07:02] Billy.Zheng(@zw963):@jgaskins , Thanks for awesome explain, maybe should mention `virtual-dom` in README, I thought clearwater rerender all DOM to refresh a page before ---------------------------------------------------------------------------------------------------- [02:40:23] Jamie Gaskins(@jgaskins):A couple years ago, that was true. It replaced HTML on the page (like jQuery used to), which blew away the old DOM and gave you a whole new one, but we moved to using a virtual DOM and it got faster, more memory-efficient, and provided a better UX out of the box. 😊 ---------------------------------------------------------------------------------------------------- [02:42:26] Jamie Gaskins(@jgaskins):I dont know if we want to advertise our use of `virtual-dom` specifically, since it's an implementation detail and I think integrating with it directly is a pretty advanced topic. ---------------------------------------------------------------------------------------------------- [02:44:02] Jamie Gaskins(@jgaskins):But Clearwater is the first Ruby front-end framework to use a virtual DOM of any kind, so I think pointing out that we do use one would be a good idea. 👍🏼 ---------------------------------------------------------------------------------------------------- ############################## [2017-07-24] ############################## [16:42:15] Billy.Zheng(@zw963):@jgaskins , Hi, https://github.com/zw963/clearwater_example is my first clearwater project, in this project, exists some special issue I could not figure out, followings is my explain. ```rb # app/assets/javascripts/application.rb require 'opal' require 'clearwater' require 'ostruct' require 'rails-ujs' require 'turbolinks' # require_tree '.' # Use this will cause browser log error, don't know why. require_tree './test' # this worked ``` ---------------------------------------------------------------------------------------------------- [16:45:11] Billy.Zheng(@zw963):The last two line is my question. if use `require_tree '.'`, will got following error in browser. http://i.imgur.com/DCpMOVg.png ---------------------------------------------------------------------------------------------------- [16:46:05] Billy.Zheng(@zw963):But, I think all code is worked even have those error logs. thanks. ---------------------------------------------------------------------------------------------------- [22:01:19] Jamie Gaskins(@jgaskins):If I understand correctly, that might be a bug in Opal. I assume your `require_tree '.'` line is intended to load `app/assets/javascripts/**/*`, but I'm not 100% sure if it just loads the files within that directory or if it will recurse into child directories, as well. I don't use `require_tree`, but I'd ask in https://gitter.im/opal/opal to see if that's the case. ---------------------------------------------------------------------------------------------------- ############################## [2017-07-25] ############################## [01:06:47] Billy.Zheng(@zw963):@jgaskins , thanks, I add this issue to opal, hope can help improve opal. https://github.com/opal/opal/issues/1680 ---------------------------------------------------------------------------------------------------- ############################## [2017-08-12] ############################## [18:55:18] Jamie Gaskins(@jgaskins):I just found several occurrences in Bowser where we used `obj.native` in JS. Turns out that doesn't work in some browsers (`native` is a reserved word maybe?), so I've replaced them with `obj['native']` and released a new version. ---------------------------------------------------------------------------------------------------- [18:57:12] Billy.Zheng(@zw963):Cool ---------------------------------------------------------------------------------------------------- ############################## [2017-08-23] ############################## [00:03:19] Forrest Chang(@fkchang):@jgaskins didn't you make an opal binding of GoogleMaps? I was about to start working on one but remembered that you did one ---------------------------------------------------------------------------------------------------- [22:56:11] Jamie Gaskins(@jgaskins):@fkchang I wrote it as part of an app but never extracted it. I should be able to do that this weekend. It should be compatible with either `bowser` or `opal-browser`. I think the API it uses for rendering into an element is the same. ---------------------------------------------------------------------------------------------------- ############################## [2017-08-24] ############################## [16:46:19] Forrest Chang(@fkchang):@jgaskins ok, cool, look forward to seeing it ---------------------------------------------------------------------------------------------------- ############################## [2017-08-29] ############################## [20:48:39] Jamie Gaskins(@jgaskins):@fkchang https://github.com/jgaskins/opal-google_maps ---------------------------------------------------------------------------------------------------- [20:51:08] Forrest Chang(@fkchang):@jgaskins coolio, I'll give it a gander ---------------------------------------------------------------------------------------------------- ############################## [2017-10-13] ############################## [19:37:13] Andy Maleh(@AndyObtiva):Hi, is Clearwater driven by a company's project, providing a guarantee for continued development of it (kinda like how Rails was driven by Basecamp)? ---------------------------------------------------------------------------------------------------- ############################## [2017-10-14] ############################## [17:46:12] Jamie Gaskins(@jgaskins):@AndyObtiva No companies are sponsoring Clearwater's development, no. However, I enjoy working on it and several companies have been using it in production for over a year now. I've got the 1.0 release planned, but I want to get the docs site finished and a few screencasts up so when it's released there'll be enough information for people to get started with as little friction as possible. ---------------------------------------------------------------------------------------------------- [17:48:24] Jamie Gaskins(@jgaskins):I'm also working on a Clearwater Playground app, which is itself built with Clearwater. ---------------------------------------------------------------------------------------------------- [17:56:25] Jamie Gaskins(@jgaskins):You can see an early prototype of it up at https://clearwater-playground.herokuapp.com, but the version I'm working on has rich text editing (although I'm quite proud of the fact that I was able to use plain Ruby code to get `