Creating a javascript widget for other sites

I am looking to create a javascript "widget" that can be hosted on other sites. For example. I want to host the javascript code on my site:

http://scripts.mysite.com/mywidget.js

(Think of it like Google Analytics).

Basically I want to distribute data via this javascript. But what I am unsure of is:

  • Are the rules different for development when creating a javascript for another site (cross site)
  • Are there any websites that explain these differences?

Solution 1:

I would try to:

  1. Make it configurable

    • Load external stylesheets?
    • Where do I find resources I need? (images, stylesheets)
    • What layout/size should I have?

    By doing this you let the user decide if he wants your widget to automatically load the stylesheet, or if he wants to host it himself. If he does, he can also update the styles to better fit the page the widget resides on.

  2. Provide a wizard for generating a snippet of code to include on the page
    • Ensures that even moderately technical users can utilize your widget
  3. Make it light-weight
    • Serve everything minified and compressed
    • Serve with cache-headers, e-tags, last-modified and all other useful headers you can think of. This will both reduce the load on your servers as well as make your widget more responsive.
    • Try to avoid dependencies on libraries, or check if they are loaded on the page where the widget is used before loading them
  4. Be wary of conflicts
    • Prototype uses $, and so does jQuery. If your widget depends on Prototype, and the page it is hosted on uses jQuery without noConflict-mode, problems WILL arise
    • Do not clobber the global namespace!
      • If you don't want anyone to interact with your widget, put it in a self-executing function in a closure and don't create any global variables at all
      • If you want users to be able to interact with your widget, say for adding event listeners and such, claim a single global variable, let's say ExampleComWidget as an object literal and put your methods there. User's could then interact like: ExampleComWidget.addListener('update', callback);
  5. Use clever markup

    • Be sure to use scoping on your classes and ids, to avoid conflicts as much as possible

      I.e. if your company's name is example.com, you could use classes like: com-ex-widget-newsItem

    • Validate your markup! You do not want to break a user's site
    • Semantic markup is fine, but you might want to avoid <h1>-tags, since they have especially high ranking in SEO. You could probably get by with using <h4> and less. This bullet might be a bit off. When in doubt, it's much better to use semantic markup than not.
  6. Fetch data from your site by inserting script elements
    • This is a fool-proof way to ensure that you get around the same-origin restrictions.
    • Attach an onload-listener to the script element to know when the data is ready, or use jsonp

Solution 2:

Your script should not interfere with the rest of the page.

  • Keep the number of globals to a minimum (one namespace object should be enough)
  • Don't add properties to the built-in objects for no reason
  • Don't expect to be the only script that listen for events such as window.onload
  • If you're using for..in loops keep in mind that other scripts may have added stuff to Array.prototype
  • Take style-sheets into consideration. The default style of HTML elements may have been changed.
  • Don't update your script without reason as you risk breaking a lot of sites.

Solution 3:

What PatrikAkerstrand said, is totally, 100% right.

What I want to add here, is a framework in vanilla JS that can save you a lot of time and effort to implement it, as everything is thought of, polished, and tested. All is left is to define your own widgets, and use them.

Here's an example of what it looks like.

A widget code
// inside a js file of a widget class
(function () {
    var Module_Path = ["WidgetsLib", "a1", "Button"];
    var curr = this;
    Module_Path.forEach(function(i){if (curr[i] == null) {addChildToTree(curr, i, {})} curr = curr[i]});

    specialize_with(curr, {
        CSS_Literal: `
            .{{WIDGET_CLASS_ID}}_Something {
                color: hsl(0, 0%, 20%);
            }
        `,
        HTML_Literal: `
            <div onclick="{{WIDGET_INSTANCE}}.onclick(event)"
                class="{{WIDGET_CLASS_ID}}_Something"
            >
            SOME SUPER COOL WIDGET
            </div>
        `,
        new: typical_widget_new,
    });
})();
An HTML:
<div id="w1" style="background-color: hsl(200, 50%, 50%);"></div>

<script src="WidgetsLib/a1/Button/js"></script>
A user JavaScript code:
var b1 = WidgetsLib.a1.Button.new("w1", {
    onclick: function(ev) {
        ev.target.style.color = "#ffff00";
        console.log("====== HERE");
    }
});

Please download, and open the Widget_v2.md.html in a browser, it's https://github.com/latitov/JS_HTML_Widgets .

What you'll get:

  • very interesting article about this;
  • snippets of code and examples;
  • ready to use... framework in vanilla JS, to create widgets of your own;

And enjoy creating re-usable widgets of your own, of arbitrary complexity, easily!