I am tinkering with this image storage application, and the last hurdle is to have the proper meta tags in the header so when someone sends the URL via iOS Messages it shows the proper thumbnail, but I am failing at injecting the proper <meta> tags on the server side, because
The machinery that creates link previews will not follow redirects, nor run JavaScript, so metadata must be available on the page without either occurring.Server - side redirects are followed, however, and are a good alternative.
so far I have experimented with WebApp.connectionHandlers, but whatever I inject never makes it to the client, the headers are always just what’s in the client.html
Has anybody figured out how to inject HTML headers on the server?
Im not sure if you are looking to inject a meta tag but we are doing it with server-rendersink, like the following.
import { onPageLoad } from 'meteor/server-render';
onPageLoad((sink) => {
// You can get the url data with: sink.request.url.path ...
sing.appendToHead(`<meta property="og:image" content="${YOUR_VALUE}"/>`);
});
We just went thru this exact issue and ended up using an alternate solution - if you’re interested, we used prerender.io (you can even self host it on the same server if you want). We set it up on it’s own small server so any other future app we build can just re-use it quite easily. It’s nice because it automatically takes care of checking if the request is coming from a crawler type bot (iOS, facebook, whatsapp, etc etc). Happy to post more info/example config (including with redis for caching) if wanted!
Thank you @adammoisa for reminding me of prerender.io. I used to have it setup for an older, much larger project and back then I didn’t understand neither Meteor, nor prerender well enough, so “some things that should not have been forgotten were lost. History became legend. Legend became myth…” you know the rest.
Since this topic started out with a misguided use of WebApp.connectionHandlers, I feel the need to re-habilitate this most awesome feature of the stack by linking to this post which explains how I used it to dynamically serve static files.
Quick question about the server-render package. In your example @jamgold, in onPageLoad() you do a
DBImages.findOne(id);
in order to check to inject meta tags. I want to do something similar, but I’m finding this to be duplicating what my client route is going to do. That is, it does a Meteor.call() to look up the same data to pass into the Blaze template. My data is a bit larger and more involved.
So doing the lookup in the onPageLoad() is doing the same server/Mongo work twice. Is there a way to have the data in onPageLoad() passed back to the client to prevent having to do the server call for data from the client?
None of the package methods seem to support this, unless hacking it into the DOM somehow.
As a quick aside, we switched off Galaxy where with the mdg:seo package it automatically ran prerender.io for you. The only reason we need prerender.io is to, like you, have links to our app display proper thumbnails and text when pasting into Facebook, Twitter, etc. We don’t need any of the SEO benefits, just the pre-rendering of the meta tags currently set in the client using packages like lookback:seo which don’t work without pre-rendering. So looking to switch to server-render.
Yes. Explicitly add the data together as a javascript variable inside a <script> tag that can be read in the client when the client initializes. Check if the variable doesn’t exist before querying.
At the very least, set a javascript nonce boolean variable in the head which you can check before querying in client.
@rjdavid Clever. That might just work for my method-based non-pub/sub use-case.
On the contrary, it wouldn’t probably solve the SEO use-case as it will still require JavaScript running to populate fields on the page (e.g. titles, subtitles, etc.) But SEO isn’t my use-case.
You already used that data for SSR to generate your HTML. That will not change. You are just adding javascript to easily check if you need to query or not to remove your redundant calls.