C3PO: Common 3rd-party objects

February 18th, 2013. Tagged: facebook, JavaScript, performance

Problem: too much JavaScript in your page to handle 3rd party widgets (e.g. Like buttons)
Possible solution: a common piece of JavaScript to handle all third parties' needs

3t1jsi

What JavaScript?

If you've read the previous post, you see that the most features in a third party widget are possible only if you inject JavaScript from the third party provider into your page. Having "a secret agent" on your page, the provider can take care of problems such as appropriately resizing the widget.

Why is this a problem?

Third party scripts can be a SPOF (an outage), unless you load them asynchronously. They can block onload, unless the provider lets you load it in an iframe (and most don't). There can be security implications because you're hosting the script in your page with all permissions associated with that. And in any case, it's just too much JavaScript for the browser to parse and execute (think of mobile devices)

If you include the most common Like, Tweet and +1 buttons and throw in Disqus comments, you're looking at well over 100K (minified, gzipped) worth of JavaScript (wpt for this jsbin)

This is more than the whole of jQuery, which previous experiments show can take the noticeable 200ms just to parse and evaluate (assuming it's cached) on an iPhone or Android.

What does all of this JS do?

The JavaScript used by third parties is not always all about social widgets. The JS also provides API call utilities, other dialogs and so on. But the tasks related to social widgets are:

  1. Find html tags that say "there be widget here!" and insert an iframe at that location, pointing to a URL hosted by the third party
  2. Listen to requests from the new iframes fulfill these requests. The most common request is "resize me, please"

Now, creating an iframe and resizing it doesn't sound like much, right? But every provider has to do it over and over again. It's just a wasted code duplication that the browser has to deal with.

Can't we just not duplicate this JavaScript? Can we have a common library that can take care of all widgets there are?

C3PO draft

Here's a demo page of what I have in mind. The page is loading third party widgets: like, tweet, +1 and another one I created just for illustration of the messaging part.

It has a possible solution I drafted as the c3po object. View source, the JS is inline.

What does c3po do?

The idea is that the developer should not have to make any changes to existing sites, other than remove FB, G, Tw, etc JS files and replace with the single c3po library. In other words, only the JS loading part should be changed, not the individual widgets code.

c3po is a small utility which can be packaged together with the rest of your application code, so there will be no additional HTTP requests.

Parsing and inserting iframes

The first task for c3po is to insert iframes. It looks for HTML tags such as

<div class="fb-like" data-href="http://phpied.com"></div>

Similar tags are generated by each provider's "wizard" configuration tools.

In place of this tag, there should be an iframe, so the result (generated html) after c3po's parsing should roughly be like:

<div class="fb-like" data-href="http://phpied.com">
  <iframe 
    src="http://facebook.com/plugins/like.php?href=http://phpied.com">
  </iframe>
</div>

The way to do this across providers is to just have every data- attribute passed as a parameter to the 3rd party URL.

Third parties can be setup using a register() method:

// FB
c3po.register({
  'fb-like': 
    'https://www.facebook.com/plugins/like.php?',
  'fb-send':
    'https://www.facebook.com/plugins/send.php?',
});
 
// Tw
c3po.register({
  'twitter-share-button':
    'https://platform.twitter.com/widgets/tweet_button.html#'
});
 
// ...

The only additional parameter passed to the third party URL is cpo-guid=..., a unique ID so that the iframe can identify itself when requesting services.

The parsing and inserting frames works today, as the demo shows. The only problem is you don't know how big the iframes should be. You can guess, but you'll be wrong, given i18n labels and different layouts for the widgets. It's best if the widget tells you (tells c3po) how big it should be by sending a message to it.

X-domain messaging

What we need here is the iframe hosted on the provider's domain to communicate with the page (and c3po script) hosted on your page. X-domain messaging is hard, it requires different methods for browsers and I'm not even going to pretend I know how it works. But, if the browser supports postMessage, it becomes pretty easy. At the time of writing 94.42% of the browsers support it. Should we let the other 5% drag us down? I'd say No!

c3po is meant to only work in the browsers that support postMessage, which means for IE7 and below, the implementers can resort to the old way of including all providers' JS. Or just have less-than-ideally-resized widgets with reasonable defaults.

When the widget wants something, it should send a message, e.g.

var msg = JSON.stringify({
  type: 'resize',
  guid: '2c23263549d648000',
  width: 200, 
  height: 300
});
parent && parent.postMessage(msg, '*');

See the example widget for some working code.

The c3po code that handles the message will check the GUID and the origin of the message and if all checks out it will do something with the iframe, e.g. resize it.

Again, take a look at the demo code to see how it all clicks together

Next?

As you see in the demo, only the example widget is resized properly. This is because it's the only one that sends messages that make sense to c3po.

Next step will be to have all widget providers agree on the messages and we're good to go! The ultimate benefit: one JS for all your widget-y needs. One JS you can package with your own code and have virtually 0 cost during initial load. And when you're ready: c3po.parse() and voila! - widgets appear.

Of course, this is just a draft for c3po, I'm surely missing a lot of things, but the idea is to have soemthing to start the dialogue and have this developed in the open. Here's the github repo for your forking pleasure.

Make sense? Let's talk.

Tell your friends about this post: Facebook, Twitter, Google+

8 Responses

  1. Wow, excellent idea! It would be nice if every widget provider support this standard postMessage API!

    And what about removing the parsing and iframe insertion too? I could put the widget iframe tag directly in my HTML and only mark it with a special class (or data attr) so the script can resize it accordingly.

  2. A couple of notes:

    Semantically, DIV elements with classes are not going to be your best bet.
    Thankfully, HTML has an element for you. And it makes a lot of sense

    EMBED. Yeah, I’m going there. (Hopefully your comment system isn’t going to eat this next part) It makes a lot of sense, because any attribute is “passed as parameters” to the plugin (the +1 or like button).

    Smaller footprint, more semantic, etc. I might fork your code tonight, and see what I can mockup with that, because I really believe that the conversation you’re starting is absolutely the right one.

  3. What I meant to write in was:

    <embed href=”facebooklikebuttonplacehurr” data-c3po=”true” size=”small” />

  4. Is this not something that products like Ensighten (http://www.ensighten.com) does? Are am I missing something?

  5. Merci pour l’actu je ne savais pas ça ^^
    Jme coucherais moins bête grâce à l’article “”

    Tanks en tout cas ça fait plaisir de lire du bon contenu

    Go like FB + favoris

  6. Thanks for the post and information! I think education is important for us so we must prepare the best education for our generation by sharing such great information with each other!
    website designers los angeles

  7. Is there a reason why the W3C can’t just get off their collective arses and sort this out without developers having to do it for them? What is wrong with a <widget> tag? Is there already something in the pipeworks? Is it web activities or something? Come on, this is supposed to be the web beyond IE’s laggard influence: Mozilla, Google innovate, Microsoft follows or continues to lose market share. Hmmm, oh wait, am I sleep-typing ? Is this just a dream? Does Microsoft still have over 50% and worse: all of it fragmented into up to 5 variations? Ouch, ok, so I felt the pinch. Back to the bloated web: AddThis, ShareThat, BloatEverywhere.

    Thanks for making an effort to solve the problem in the shortest possible timeframe though!

  8. […] can end up requesting many JS files doing something very similar. I recommend you to have a look at C3PO which explains a common loader for this kind of […]

Leave a Reply