Tips building an embeddable Javascript widget (like Disqus, or social buttons) using RequireJS.
RequireJS makes building embeddable application a breeze, it also bundled with an optimizer tool (r.js
) that take care of everything (dependency handling, uglifying...).
You must remember that you don't own the DOM, you can't do anything like updating global style, or altering the page. You should also avoid conflict with current script, and global variables.
RequireJS crash course
Assuming you already have RequireJS and Bower installed.
If you don't use Bower yet to manage dependency, you should take a look at it.
$ bower install jquery
We need to create few files to get started, create config.js
:
var requirejs = {
paths: {
jquery: "bower_components/jquery/dist/jquery"
}
};
Create embed.build.js
:
({
baseUrl: ".",
mainConfigFile: "config.js",
name: "bower_components/almond/almond", // assumes a production build using almond
include: ['embed'],
out: "embed.min.js"
})
Create embed.js
:
require(["jquery"], function($) {
"use strict";
$(function() {
console.log('ok');
});
});
Now we can try to build embed.min.js
to make sure everything works as expected.
$ r.js -o embed.build.js
Handling CSS
Cleanslate seems to be a good solution to prevent overlapping with current style.
The RequireJS optimizer will automatically inline CSS files referenced by @import.
Also, don't forget to prefix your CSS class so you don't mess up with the actual CSS of the page and to use !important
.
$ wget https://raw.github.com/premasagar/cleanslate/master/cleanslate.css
@import cleanslate.css
#my-widget a {
color:orange !important;
}
Embedding CSS
To embed/bundle text (template) inside the final JS file, take a look at requirejs-text.
$ bower install requirejs-text
Ànd in your config.js
:
var requirejs = {
paths: {
jquery: "bower_components/jquery/dist/jquery",
text : "components/requirejs-text/text"
}
};
To optimize CSS, you need to run this additional command:
$ r.js -o cssIn=my-widget.css out=my-widget_embed.css
Now, you can require your CSS stylesheet within your app:
require(["text!module_embed.css"],
function(css) {
var $style = $("<style></style>", {type: "text/css"});
$style.text(css);
$("head").append($style);
}
);
Handling configuration
Configuration can easily be managed using data-*
attributes and retrieve it using $.data:
var configTheme = $('#my-widget').data('my-widget-theme');
if (configTheme == undefined) {
doSomething();
};
Communicating with external server
Two evident ways: CORS or JSON-P, but since CORS is only supported by IE8+, you may want to stick with JSON-P. Hopefully jQuery ($.ajax and deferred) handles everything for us.
$.ajax({
url: "http://date.jsontest.com/",
dataType: "jsonp"
}).then(function(resp) {
console.log(resp);
}, function(resp) {
console.log("Something bad happened:");
console.log(resp);
});
Loading the code
I found this article very interesting, here is the final snippet of this article (you should read it):
(function (window, document) {
var loader = function () {
var script = document.createElement("script"), tag = document.getElementsByTagName("script")[0];
script.src = "http://errorception.com/projects/" + _errs[0] + "/beacon.js";
tag.parentNode.insertBefore(script, tag);
};
// Wait until window.onload before downloading any more code.
window.addEventListener ? window.addEventListener("load", loader, false) : window.attachEvent("onload", loader);
})(window, document);
A basic widget
I built a demo widget using Ractive.js, I think it's a good fit for building a widget, it comes with templating, data binding, event handling, and it integrate with RequireJS.
I won't make a tutorial for the widget, just check the source code on GitHub.
<div id="myWidget"></div>
<script>
(function (window, document) {
var loader = function () {
var script = document.createElement("script"), tag = document.getElementsByTagName("script")[0];
script.src = "http://thomassileo.demo.s3.amazonaws.com/embed.min.js";
tag.parentNode.insertBefore(script, tag);
};
window.addEventListener ? window.addEventListener("load", loader, false) : window.attachEvent("onload", loader);
})(window, document);
</script>
Here is the result:
Interesting links/projects
- Loading jQuery plugins from third-party scripts, by Alex Marandon.
- Writing Quality Third-Party JS, by errorception, a JS error tracking service.
- Ractive.js, a small AngularJS-like framework worth trying for building widget. It works well with RequireJS.
- Isso, an open source Disqus alternative with a widget that uses RequireJS too.
- Developing an embeddable Javascript widget, by a Shootitlive, a video publishing service.
Tip with Bitcoin
Tip me with Bitcoin and vote for this post!
Leave a comment