I know this is an old topic, and most people might not even care anymore because they moved on to React or VueJS …
But I am dogged and like to tinker, so here is an approach I got to work and want to share with the community.
On the server I have this
import { onPageLoad } from 'meteor/server-render'
const Hydrated = new Meteor.Collection('hydrated')
onPageLoad(sink => {
const pathname = sink.request.url.pathname
const hydrated = Hydrated.findOne({url: pathname})
if(hydrated) {
sink.appendToBody(`<div class='meteor-blaze-hydrated'>${hydrated.html}</div>`)
}
});
and on the client in the onRendered callback of my layout Template I have
const hydrated = document.querySelectorAll(`.meteor-blaze-hydrated`)
if (hydrated) {
hydrated.forEach((elem) => {
// check if we have video and pause it
elem.querySelectorAll('video').forEach((video) => {
video.pause()
})
elem.remove()
})
}
Now you might wonder how is the collection Hydrated
is getting populated. Together with FlowRouter I came up with this
export const getHydrated = function() {
const body = document.getElementsByTagName('body')[0]
const clone = body.cloneNode(true)
clone.querySelectorAll('script').forEach((s) => { s.remove() })
return clone.innerHTML.replace(/\s{2,}/g,' ').replace(/autoplay/g,'')
}
Tracker.autorun(function serverRenderPathChange(){
const userId = Meteor.userId()
FlowRouter.watchPathChange()
const current = FlowRouter.current()
//
// only save page as anon user
//
if (!userId) {
// is the route defined
if (current.route != undefined) {
// get the path
const path = current.route.path
// unless the route explicitly prevents server_render
if(! current.route.options.server_render === false){
//
// allow time for the page to be rendered
//
Meteor.setTimeout(function () {
const html = getHydrated()
Meteor.call('saveHydrated', path, html, current.queryParams, (err, res) => {
if (err) console.error(err); else if (config.debug && res.saved) console.log(`saveHydrated ${res.id} ${res.created}`)
})
}, 1000)
} else {
if(current.queryParams && current.queryParams['server-render-delete'] == "true") {
Meteor.call('saveHydrated', path, null, current.queryParams, (err, res) => {
if (err) console.error(err); else if (config.debug && res.saved) console.log(`saveHydrated ${res.id} ${res.created}`)
})
}
}
}
}
})
Clearly this attempt has severe limitations (security for one), second some flickering (because I can’t get the timing right of when to remove the hydrated div), not to mention some really weird behavior with autoplaying video components (ghost playback).
Still, I wonder what you guys think?