Meteor-ssr with template events

Hey everyone,

I’m looking into using Meteor for a project. It looks really promising, but one requirement that I have is that I need to be able to render the initial page on the server and send it down to reduce initial pageload time, but also attach events to the template on the client. It looks like the meteorhacks:ssr does the rendering and meteorhacks:picker is a good choice for server side routing. My only issue with that solution is that it doesn’t look like any event handlers attached to a template would be attached on the client if a template was rendered on the server then sent down to the client. Is there any solution for server side rendering that can attach events to a template on the client after it’s been rendered on the server and sent to the client?

For instance, I’d like to have a template that has a ‘click’ event attached to a button within that template that toggles the visibility of a div within that template. I want to render the template initially on the server to save client load time, but still have the client attach that ‘click’ event on that pre-rendered template once the client receives it.

If nothing like that exists, could someone with a good understanding of how Blaze attaches events explain if it’s even possible?

Thanks!

…are bumps allowed on this forum?

I guess you can give a try for meteorhacks:fast-render

yeah I’ve seen that but from what I understand it sounds like it attaches the data for the view to the page in a script tag, then the client still has to load all the JavaScript, parse and execute it, then render the view using the data in the script tag. It’s an interesting approach to speeding up initial load time, but I’m looking to avoid that cpu load on the client by rendering on the server, then having the client see that it’s been rendered and attach the events for that template to that pre-rendered template’s html. This is something that React can do, but I’d love to see it happen in Blaze as well.

It sounds like there isn’t any community solution for this so far. I’m open to the idea of building it myself, but I’d like to hear from someone who has knowledge of the inner workings of Blaze’s render and event lifecycle to know if it’s even possible

I think @arunoda mentioned on cast that flow router SSR itself does not have problem with rendering blaze templates, but there is no known way atm how to access blaze templates on server side. Or something like that.

If you want to use react, check this out: https://github.com/arunoda/hello-react-meteor

that isn’t exactly what I was looking for but it is very helpful nonetheless, thanks

React does this out of the box so it may be worth exploring. I realize this isn’t everyone’s cup of tea but I just wanted to mention it’s built in support. It renders to a string on the server and the on the client will checksum the tree. If it’s different it will re-render but if it’s the same (and it should be) then it will re-attached all event listeners for you automatically. This could be used with Picker or Arunoda’s new SSR FlowRouter branch.

If Blaze is a requirement my best suggestion would be to use fast-render to bootstrap the page with the data so that the only time spent on the client is actually rendering. This makes it much much faster than a regular page because it doesn’t have to connect to DDP and start a transfer.

Here’s an example of the Blonk blog posts. Checkout the source to see the bootstrapped data that it’s sending down in the HTML. http://blonk.co/posts (it’s also not optimized for speed, like the bloated bootstrap CSS + JS).

As I understand - you want to render a plain html on the server and then on the client magicaly apply full Meteor logic for static html. Am I right? If so I cant imagine any way you could do this

I suppose anyone who doesn’t understand how some code works would call it “magic”, but yes that’s what I’m looking to achieve. React is capable of doing it “magically”. The way I imagine it could work is something like this

1 - I have a template on my homepage called “MyTemplate” that looks like this

<span class="someUniqueIdentifier"> Hello {{name}} </span>

Which uses a helper function to return “name” from some data source, let’s call it DataSourceA. And it has a “click” event attached to it, let’s call it TemplateEventA.

2 - A user visit my homepage, and the server sends down the full page to the client including MyTemplate in a pre-rendered state like so

<span class="ax8192mad2"> Hello John  </span>

3 - The client fetches all the necessary files for the page, including MyTemplate. The client is given some data to let it know that there will be a MyTemplate instance with identifier “ax8192mad2”

4 - The client finds the instance of MyTemplate via it’s unique identifier and binds TemplateEventA to that DOM element, applying the MyTemplate context to it.

5 - The client now knows where MyTemplate lives in the DOM, and fetches DataSourceA’s “name” property. The client compiles MyTemplate with the fetched data and creates this HTML output

<span class="ax8192mad2"> Hello John  </span>

Before inserting this HTML into the page, the client compares this to the HTML of the existing instance of MyTemplate’s DOM element that’s already on the page because it was pre-rendered on the server, which looks like this

<span class="ax8192mad2"> Hello John  </span>

The diff confirms that this instance of MyTemplate is rendered correctly, so it doesn’t re-render.


Now the template has been rendered on the server and sent down to the client. The client has applied the context of MyTemplate to the DOM element of MyTemplate that was pre-rendered on the server, and has attached TemplateEventA to that DOM element. Anytime DataSourceA updates the instance of MyTemplate on the page will re-render, since Blaze is now aware of it and has associated it with MyTemplate. We’ve saved the client the CPU effort of attaching the compiled MyTemplate to the DOM initially, since it saw that it was already rendered correctly and didn’t re-render.

This could make experiences on lower end computers or mobile phones achieve “time to initial interactivity” much faster. The compiling and diffing of the HTML string for MyTemplate is much less CPU-heavy that updating the DOM.

Idk if it’s perfect, but this is an approach that I believe may work. Can anyone with better knowledge of Blaze inform me if this is doable within its current API and event/render lifecycle?

Blaze and React (and I guess Angular too) can’t do it as you expect. Every render engine needs to bind to the DOM model and has a root entry point. You cannot just feed them with an HTML and ask to bind the logic.

Note:
I’ve checked the React-way. It can find the diff between server-rendered and current client DOM, but it can just simply re-render the whole page (root node)

1 Like

Blaze and React (and I guess Angular too) can’t do it as you expect. Every render engine needs to bind to the DOM model and has a root entry point. You cannot just feed them with an HTML and ask to bind the logic.
Note:
I’ve checked the React-way. It can find the diff between server-rendered and current client DOM, but it can just simply re-render the whole page (root node)

I just found this really great article by MeteorHacks on how Blaze works and the Blaze.View source. It looks like a Blaze parses the HTML of the page, finds the Body and Template tags, and generate the JS representation of each template as a View. Then it goes through instantiating and compiling all templates, then attaches the compiled HTML to the DOM body. Blaze.View has a pointer that points to its parentView which caused it to be rendered, and a DomRange object to specify its position and extent in the DOM.

Is it at all possible, with a bit of modification, to add a step in the parsing phase that recognizes that a template is already rendered from the server and sets “isInstantiated” to true and sets the parent pointer and DomRange appropriately so that it doesn’t touch that part of the DOM on pageload, but events still get attached? Or would the full body get rendered regardless?

React does this out of the box so it may be worth exploring. I realize this isn’t everyone’s cup of tea but I just wanted to mention it’s built in support. It renders to a string on the server and the on the client will checksum the tree. If it’s different it will re-render but if it’s the same (and it should be) then it will re-attached all event listeners for you automatically. This could be used with Picker or Arunoda’s new SSR FlowRouter branch.

The more I look into how Blaze works internally the more it’s looking like full SSR with client-side bound events may not be possible with the current state of Blaze. FastRender is a clever trick, but I’m worried more about the CPU cycles required for rendering on mobile devices than the time spent retrieving data (though both are obviously important). Kadira seems to have achieved very simple SSR using React so perhaps I’ll go that route. It’s a bit disappointing, I haven’t used Blaze yet but it looks really nice and I was hoping I could use it exclusively. This forum has been really helpful for someone who’s never used Meteor before tho :+1:

On a side note, if you had told me you were making “Tinder for job applications” I’d have laughed but that Blonk app actually looks pretty cool

2 Likes

As a start point you could ask @arunoda about his experiments with caching HTML blocks for navigation issues. As I know he has got a nice results with pasting a part of HTML into Blaze.View with attaching a logic. But it seems to work for a couple of DOMRanges, but may be it is possible to pay with whole page on the client.

Aww you gave up so easily, i thought we were going to get this thingy done. Considering the benefits it would be really useful. I have been a bit inside of the Blaze source code and i am willing to contribute to such an effort. Reason being i am not a big fan of react, i mean its good, but sometimes its just too much effort for a very simple thing, which is where Blaze takes the lead. I wouldn’t be too worried about modifying the blaze package code, as long as we can achieve this. We can always submit a PR to meteor or just keep it alive as a separate atmosphere package :wink:

Yeah I played around the Blaze code for a few days and realized that although it’s probably possible, it’d be a bit of effort. I ended up going the React route and haven’t looked back since.