…then we would love it if you started by contributing to Sideburns, now called “Blaze React.” Blaze React’s plans are bigger than you describe there. As one of the 2 main contributors, we have a plan which achieves more than just being a renderer for Blaze 1. The plan is:
- render current blaze perfectly
- render a components based blaze perfectly (Similar to @mitar 's “Blaze Components”)
- the choice to permanently transpile your code into the Components based version, thereby helping meteor developers with the upgrade path to a Components based architecture. This would mean the transpilation build step would now be turned off by the developer.
- the components based version can also be used with Blaze under the hood so you can continue to use your Blaze-oriented packages.
- the components based version with React as the renderer extends
React.Component
so that you can use either Blaze or React as the renderer without a build step. The way you do this is, for example, instead ofthis.state.foo
you dothis.state('foo')
. Under the hood a reactive Tracker function is used–it must be a function after all if you are using Blaze! However, the React version callsthis.state.foo
within thethis.state()
method.
So you’d be using a slightly modified version of React, but similar enough that it’s no big deal and you know exactly what the React version of the syntax would be anyway.
All in all, the point is we have a path forward. A path from transpilation of either Blaze 1 or a Components based blaze, which we basically already have in “Blaze Components.” An official more optimized one may be better, but there isn’t too much that needs to be changed in the interface. I didn’t create Blaze Components, but I happen to have built the version I’m talkin about with what I consider is a more suitable interface. But again, it’s only small changes. So anyway you have blaze code, Blaze 1 or “Blaze Components” that can be transpiled to React in a build step. THEN, you have the option to permanently transpile your code to the Components version. That doesn’t mean you are necessarily using the React renderer yet–it can still render with Blaze just as @mitar’s Blaze Components currently does. However, this new components-based architecture also has a version of the exact same interface that simply extends React (NOT TRANSPILES!), and under the hood it calls React style code (e.g. this.state.foo
instead of this.state('foo')
as mentioned above.
That offers a complete upgrade path going forward, no matter which way you wanna take:
-
USE TRANSPILE BUILD STEP TO GENEATE REACT CODE: you have old packages that
still use Blaze 1 + your own components based on the new Components
API, and you want it all rendered to React - CONTINUE TO USE BLAZE RENDERER BUT WITH BOTH BLAZE 1 CODE + BLAZE COMPONENTS API CODE: basically you are combining old blaze code and new blaze components again like in the above point, but for whatever reason you don’t want to transpile to React. This approach will likely be phased out, but in reality will be a very helpful approach in the beginning while stabilizing the React renderer for all use cases such as Animations and the plethora of features in the React ecosystem which haven’t been made compatible yet. You have to understand that just because we have the main renderer, does not mean we have all the core React addons and essentially core features of web development working yet, again e.g. animations.
-
PERMANENTLY TRANSPILE TO THE COMPONENTS API /W REACT RENDERER UNDER THE HOOD: so now everything you’re using is using the new
Components API (though package code built using Blaze 1.0 will still
work), but what you’re using under the hood is an Extension of React
that does things like usethis.state('foo')
instead of
this.state.foo
or here’s another obvious example:onCreated
really callscomponentWillMount
under the hood. There’s many more.
Check the discussions in the Blaze React Github issues for more such
discussions: https://github.com/timbrandin/blaze-react - **PERMANENTLY TRANSPILE TO COMPONENTS API /W BLAZE RENDERER: so since we can transpile to a components API that is shared by both renderers, we can also transpile your blaze 1.0 code to Blaze Components. Again, it wont just happen overnight that all the core React addons behave properly. And perhaps for many Meteor packages we can never just automatically transpile them, BUT you want to start using the Blaze 2.0 Components API. Here’s the arrangement you use.
So what I’ve outlined is a path that will accomplish 2 main aims:
- A. you can start truly taking advantage of React in a truly integrated way with Tracker/Meteor, etc, as well as a more extensible Components-based API.
- B. you don’t have your Meteor/Blaze developers in total panic that all their code from year’s past is now obsolete and will require a major refactoring to take advantage of all new tools coming down the pipeline.
They may have a a little work going forward, but it’s a lot less work than if you force the upgrade to a renderer that only works for the new Blaze Components. And part of that is achieved by making Blaze Components work with old Blaze. If you devise a plan to share a common API, that is totally possible.
NEXT: I’d like to point out some things. The challenges people see with React coming from Blaze/Meteor land is 2.5 fold:
- using JSX instead of spacebars (probably the most trivial of all the problems in terms of actually solving–its not that hard to transpile Spacebars to JSX, but that barely solves the problem involving context and much more.
- passing functions down and then assigning them to element attributes rather than using jQuery style css selectors. This can be easily solved too. There’s no reason why now in the React community–totally unrelated to Meteor–that selectors can’t be used to select elements in child components, and in turn pass down access to the state that parent “smart components” may have. Our current jQuery style selectors interface is a good thing! Because: A) obviously code separation concerns, B) it’s already something Meteor developers understand, C) IT’S A HELL OF A LOT EASIER! This needs to be more automated in React itself. We can do first in our
React.Components
extension. Again, pay a visit to the Blaze React (again, previously “Sideburns”) to participate in our exploration there.
2.5. State. And I say “2.5” because the Meteor community has already been moving this direction for a while with things such as Template.instance().foo = new ReactiveVar
and more recently with learning how to pass down such state unidirectionally even if seems easier at first to not have to deal with passing as many things down. There are some inherent challenges with Blaze 1.0 state because event handlers don’t have access to that state when they are triggered on an element in a child component, whereas that component may have received the state passed down as a property of that child component. Corrections need to be made to solve this. Options are: helpers exist in the context of child components, but with the state of the component where they are defined, and event handlers, which already can do that (i.e. act upon child components), maintain the original state of the component where they were defined! @mitar’s Blaze Components already goes partially the way, but not fully. Either way the result is the “smart component” “container/controller component” pattern where a component higher up the tree can manage the state of child components and without the need to pass every damn helper/event-handler down!! So anyway, this is labeled "2.5" because Meteor developers are already doing a good job wrapping their head down by the effectiveness of this pattern, but are crippled because they can’t fully actualize it in Blaze 1!.
We have a lot more to say about this one. My hope is that @gschmidt is serious about his perspective to ***“partner up and work together to make that happen”***. We at Blaze React already have something we are working towards. It’s going to happen regardless. We know you guys just got started seriously thinking about this problem. But the way Meteor usually develops is almost in Silence–a lot more than many other top Open Source projects. I love Meteor–because you run a tight shift in that way. But it can’t be denied that what’s gone on with Meteor vs. the exploding Node community at large has put it at major risk. If you guys didn’t start down this path you’re sharing today, it would basically send Meteor to an early grave. This time some things need to change, and the essence of it all is embracing the open source community more. So you can’t just build the new “ideas” anymore, but go it alone. You actually have to build them with the rest of us. In this instance, you actually have contributors already. It would be a major blunder to not take adantvantage of that. At least come chat with us IN OUR GITHUB ISSUES FORUMS before making all your decisions in private (+ a few forums.meteor.com announcements). There’s know doubt your engineering will be some of the best–there’s a lot of decisions to be made here. I have a grand vision here essentially, and I think if you hear it you will like it. I have done a lot of the work for you here already.
The final part–for now–is that React “Components” is only where the conversation should start. My vision includes Meteor becoming completely class-based. So many of our packages are procedural/imperative style coding, and as a result are not at the quality they could be. This isn’t a conversation of “Inheritance vs. Composition.” Compose all the way! But compose with “Components”–that’s why they are called “Components.” They just happen to look at lot like Classes, and in fact, in React you can use Classes.
…A side note: React is “functional” under the hood where it counts for the implementation, but “OOP” on the interface where Objects/Classes serve as a closer mirror to how Humans Think About Programming. Likely that conversation isn’t as big of a deal with MDG as it is with the hords of functional advocates who aren’t yet looking at the full picture…
So anyway, what I’m saying is publishers, subscriptions, models (most importantly), routers, etc, all should become classes. It will be that painfully obvious solution in front of our face to the supposed challenge you guys have had in leading Meteor developers to architecting extensible applications. The fact that you haven’t had that has been a major pain point for you. That said, it was absolute perfect as a “go to market” strategy to launch a more procedural/imperative approach. That time has passed now. Keep that API as your “Ruby” and now make your “Rails.” Then you won’t spend all this time writing a guide about how to cope with utilizing a sub-par system for major applications. NO offense–I’m Meteor all the way from day one. I’m just saying: as long as you’re choosing to frame this as a conversation surrounding React and not a bigger architectural OOP Class-system you’re missing the core of the problem.
So, your app shouldn’t contain a single line of code not wrapped in a class. Meteor should provide this API. It’s akin to “Rails” to “Ruby” like I just said. Now, I’m not saying it all needs to be done before the React stuff is handled–but the point is to build your new components architecture with that in mind. E.g. if you inherit, perform a mixin, whatever, in your components API it should look the same way in the soon-after-future where you will mixin to a model class that inherits from another model class. The real work won’t be in becoming OOP–that’s easy–but in making our own Relay/GraphQL style pattern for Mongo, and other such core use cases. On that note, Relay/GraphQL is great! …for the ecosystem as a whole, but (like React) is an unnecessarily complex interface for client code. In GraphQL’s case, that’s its whole purpose–to enable us developers to build adapters for our database languages. Relay seems more intent on being attached to every view Component in client code, but it too can get adapters that make it easier–easier to work with your database implementation. But perhaps all using Relay+GraphQL under the hood to take part in its ecosystem.
And also perhaps not. I think in the beginning we can build this components-attached-ORM purely for Mongo and our Components API. Down the line we can switch out direct connection to pure mongo and meteor subscriptions/publishers with a Relay/GraphQL middle layer–and not just to do it because the “cool kids are doing it,” but for practical business reasons: the growing ecosystems of these tools make a bunch more features/tasks easier and available to us. Right now that doesn’t exist with GraphQL and Relay. To take a back step and build mongo + meteor connectors to that stuff, AND THEN build our own ORM (and component methods to attach them) would be a waste of time. We should build how that interface will best look on Meteor today; and imagine how one day the middle layer could be swiped out with Relay/GraphQL, but not hold ourselves up over build it all ourselves. The point at the end of the day isn’t the tools, but the patterns:
- data-aware container components
- a Mongo ORM to simplify how we specify subscriptions and publishers. end of story.
Meteor needs that. Not the Relay/GraphQL rabbit hole–not yet. It solves the same problem. And again to circle back to the point i digressed from: it should be class based and share the same “Class-based Syntax as Blaze 2.0 React-interoperable Components”.
THE FUTURE I PROPOSE LOOKS LIKE THIS:
class Post extends Meteor.Model {
fullName() {
return ${this.firstName this.lastName};
}
subscriptions() {
return {
//description of models/collections you can describe to
}
}
}
class MyComponent extends Meteor.Component {
subscriptions() {
return {
//configuration code related to the model subscriptions
//you want this component automatically subscribed to
}
}
onCreated() {
this.state('foo', 'bar');
}
['click .some-element']: function() {
this.state('foo', 'bazzz');
},
someHelper() {
return this._plainMethod() + ' awesome!';
}
_plainMethod() {
return this.state('foo');
}
}
So there you go that’s my proposal for what “Meteor Relay” actually looks like. Relay + GraphQL code is unnecessarily complex. React itself is unnecessarily complex. We already are seeing various tools interop and transpile to React such as Om for clojurescript or Cycle.js (which based on my research is the purest form of functional view programming in javascript, i.e. without moving to other languages such as clojurescript or elm). But anyway, as long as we are deciding to stick to the Class-based approach–whose strengths lie in its initial frictionless ease of use, natural human readability, common usage, etc–my point is take a play from their playbook: see how we don’t have to get married to the plain React interface. It’s round 1 in this functional view thing in the javascript world. The interface can be improved upon. That’s probably the most important point I’d like heard by MDG: I don’t want to see you guys go make all this stuff, but settle for a lot of React’s baggage. I predict React will win as the renderer (i.e. its “ECOSYSTEM WILL WIN”), but many facade layers on top of it (that offer better interfaces) will reign supreme. At least a lot more mixins and classes that make the methods you’re using on your React Component look almost unrecognizeable. But we can go farther than that, such as not using JSX, and still having a separate HTML-like file (which is great for designers) that uses Spacebars or an enhanced Spacebars where you can do a bit more javascript math/logic in between your curly braces. That’s still the tip of the ice berg:
- we can use React contexts to achieve what’s already natural and more automated in Blaze: https://facebook.github.io/react/docs/context.html …See, what Blaze offers is the automation of a lot of things that you have to manually/explicitly do in React. E.g. passing down event handlers to child components to make the connection to parent state. We can automate this, while still keeping it “explicit.”
- we can pass down a reference to a parent components, which is one of the core things we are considering at Blaze React to allow access to operators such as
../../
in Spacebars andTemplate.parentData(level)
in template javascript code. We’ve done some initial tests and it seems to not violate any React principles in fact. Here’s what it looks like:
<MyComponent parent={this} />
var MyComponent = React.createClass({
parentData: function(level) {
var parentData = this.props;
for(var i = 0; i < level && parentData.parent; i++) {
parentData = parentData.parent.props;
}
return parentData;
},
render: function() {
return <div>{this.parentData(1).count}</div>;
}
});
http://jsfiddle.net/v755xkxx
http://jsfiddle.net/Ljpd0d0m
In short, I’d like to see a lot of work that React does automated in our React Extension. It would be a mistake to expend all this time, effort, and resources just to make our code look like React. We can do better.
Well the answer to that in its truest form–i.e. “TIGHT INTEGRATION WITH TRACKER”–involves modifying the typical React Component interface. this.state.props
doesn’t cut in the Blaze of the future. What are your thoughts on that?
Would love to continue that conversation with you over here: