Creating a javascript widget for other sites - javascript

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?

I would try to:
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.
Provide a wizard for generating a snippet of code to include on the page
Ensures that even moderately technical users can utilize your widget
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
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);
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.
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

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.

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!

Related

How to use javascript without appending it to DOM

I am developing an Single Page Application (SPA) from scratch. I am doing it from scratch using only HTML, CSS and vanilla JavaScript and not using any external frameworks.
My application will initially load Web page but upon navigating to some other page say page2, it will only load required data and functions about other page2 from page2.js and not reload the entire Web page.
To use the JavaScript I will append it to body. But the problem is that when I navigate same page again it will append the same JavaScript again. The more pages I visit the more scripts are attached.
I have tried removing existing script tag in favour or upcoming script and it works good, but is there a way that I don't have to append script to DOM in the first place?
So my question is, is there a way we can parse (not just plain read) or execute JavaScript file without using any physical medium (DOM)
Although I am expecting pure JavaScript, libraries would also work, just need a logical explaination
So my question is, is there a way we can parse (not just plain read) or execute JavaScript file without using any physical medium (DOM)
Yes, you can. How you do it depends on how cutting-edge the environment you're going to support is (either natively, or via tools that can emulate some things in older environments).
In a modern environment...
...you could solve this with dynamic import, which is new in ES2020 (but already supported by up-to-date browsers, and emulated by tools like Webpack and Rollup.js). With dynamic import, you'd do something like this:
async function loadPage(moduleUrl) {
const mod = await import(moduleUrl);
mod.main();
}
No matter how many times it's requested, within a realm a module is only loaded once. (Your SPA will be within a realm, so that works.) So the code above will dynamically load the module's code the first time, but just give you back a reference to the already-loaded module the second, third, etc. times. main would be a function you export from the module that tells it you've come (back) to the "page". Your modules might look like this:
// ...code here that only runs once...
// ...perhaps it loads the markup via ajax...
export function main() {
// ...this function gets called very time the user go (back) to our "page"
}
Live example on CodeSandbox.
In older environments...
...two answers for you:
You could use eval...
You can read your code from your server as text using ajax, then evaluate it with eval. You will hear that "eval is evil" and that's not a bad high-level understanding for it. :-) The arguments against it are:
It requires parsing code; some people claim firing up a code parser is "slow" (for some definition of "slow).
It parses and evaluates arbitrary code from strings.
You can see why #2 in particular could be problematic: You have to trust the string you're evaluating. So never use eval on user-supplied content, for instance, in another user's session (User A could be trying to do something malicious with code you run in User B's session).
But in your case, you want and need both of those things, and you trust the source of the string (your server), so it's fine.
But you probably don't need to
I don't think you need that, though, even in older environments. Your code already knows what JavaScript file it needs to load for "page" X, right? So just see whether that code has already been loaded and don't load it again if it is. For instance:
function loadPage(scriptUrl, markupUrl) {
// ...
if (!document.querySelector(`script[src="${scriptUrl}"]`)) {
// ...not found, add a `script` tag for it...
} else {
// ...perhaps call a well-known function to run code that should run
// when you return to the "page"
}
// ...
}
Or if you don't want to use the DOM for it, have an object or Map or Set that you use to keep track of what you've already loaded.
Go back to old-school -- web 1.0, DOM level 1.0, has your back. Something like this would do the trick:
<html><head>
<script>
if (!document.getElementById('myScriptId')) {
document.write('<script id="myScriptId" src="/path/to/myscript"></scri' + 'pt>');
}
</script>
This technique gets everybody upset, but it works great to avoid the problems associated with doing dynamic loading via DOM script tag injection. The key is that this causes the document parser to block until the script has loaded, so you don't need to worry about onload/onready events, etc, etc.
One caveat, pull this trick near the start of your document, because you're going to cause the engine to do a partial DOM reparse and mess up speculative loading.

Page-level execution of JavaScript when serving concatenated files

Scenario:
A web site with x number of pages is being served with a single, concatenated JavaScript file. Some of the individual JavaScript files pertain to a page, others to plugins/extensions etc.
When a page is served, the entire set of JavaScript is executed (as execution is performed when loaded). Unfortunately, only a sub-section of the JavaScript pertains directly to the page. The rest is relevant to other pages on the site, and may have potential side-effects on the current page if written poorly.
Question:
What is the best strategy to only execute JavaScript that relates directly to the page, while maintaining a single concatenated file?
Current solution that doesn't feel right:
JavaScript related to a specific page is wrapped in a "namespaced" init function for that page. Each page is rendered with an inline script calling the init function for that page. It works hunky-dory, but I would rather not have any inline scripts.
Does anyone have any clever suggestions? Should I just use an inline script and be done with it? I'm surprised this isn't more of an issue for most developers out there.
Just use an inline script. If it's one or two lines to initialize the JavaScript you need that's fine. It's actually a good design practice because then it allows re-use of your JavaScript across multiple pages.
The advantages of a single (or at least few) concatenated js files are clear (less connections in the page mean lower loading time, you can minify it all at once, ...).
We use such a solution, but: we allow different pages to get different set of concatenated files - though I'm sure there exists different patterns.
In our case we have split javascript files in a few groups by functionality; each page can specify which ones they need. The framework will then deliver the concatenated file with consistent naming and versioning, so that caching works very well on the browser level.
We use django and a home-baked solution - but that's just because we started already a few years ago, when only django-compress was available, and django compress isn't available any more. The django-pipeline successor seems good, but you can find alternatives on djangopackages/asset-managers.
On different frameworks of course you'll find some equivalent packages. Without a framework, this solution is probably unachievable ;-)
By the way, using these patterns you can also compress your js files (statically, or even dynamically if you have a good caching policy)
I don't think your solution is that bad although it is a good thing that you distrust inline scripts. But you have to find out on what page you are somehow so calling the appropriate init function on each page makes sense. You can also call the init function based on some other factors:
The page URL
The page title
A class set in the document body
A parameter appended to your script URL and parsed by the global document ready function.
I simply call a bunch of init functions when the document is ready. Each checks to see if it's needed on the page, if not, simply RETURN.
You could do something as simple as:
var locationPath = window.location.pathname;
var locationPage = locationPath.substring(locationPath.lastIndexOf('/') + 1);
switch(locationPage) {
case 'index.html':
// do stuff
break;
case 'contact.html':
// do stuff
break;
}
I'm really confused exactly why it doesn't feel right to call javascript from the page? There is a connection between the page and the javascript, and making that explicit should make your code easier to understand, debug, and more organized. I'm sure you could try and use some auto wiring convention but I don't think it really would help you solve the problem. Just call the name spaced function from your page and be done with it..

jquery and script speed?

Quick question, I have some scripts that only need to be run on some pages and some only on a certain page, would it be best to include the script at the bottom of the actual page with script tags or do something like in my js inlcude;
var pageURL = window.location.href;
if (pageURL == 'http://example.com') {
// run code
}
Which would be better and faster?
The best is to include the script only on pages that need it. Also in terms of maintenance your script is more independant from the pages that are using it. Putting those ifs in your script makes it tightly coupled to the structure of your site and if you decide to rename some page it will no longer work.
I can recommend you to use an asynchrounous resource loader, LAB.js for example. Then you could build a dependencies list, for instance:
var MYAPP = MYAPP || {};
/*
* Bunches of scripts
* to load together
*/
MYAPP.bunches = {
defaults: ["libs/jquery-1.6.2.min.js"],
cart: ["plugins/jquery.tmpl.min.js",
"libs/knockout-1.2.1.min.js",
"scripts/shopping-cart.js"],
signup: ["libs/knockout-1.2.1.min.js",
"scripts/validator.js"]
/*
... etc
*/
};
/*
* Loading default libraries
*/
$LAB.script(MYAPP.defaults);
if (typeof MYAPP.require !== 'undefined') {
$LAB.script(MYAPP.dependencies[MYAPP.require]);
}
and in the end of your page you could write:
<script type="text/javascript">
var MYAPP = MYAPP || {};
MYAPP.require = "cart";
</script>
<script type="text/javascript" src='js/libs/LAB.min.js'></script>
<script type="text/javascript" src='js/dependencies.js'></script>
By the way, a question to everyone, is it a good idea to do so?
In so far as possible only include the scripts on the pages that requirement. That said, if you're delivering content via AJAX that can be hard to do, since the script might already be loaded and reloading could cause problems. Of course you can deliver code in a script block (as opposed to referencing an external js file), in code delivered via AJAX.
In cases where you need to load scripts (say via a master page) for all pages, but that only apply to certain pages, take advantage of the fact that jQuery understands and deals well with selectors that don't match any elements. You can also use live handlers along with very specific selectors to allow scripts loaded at page load time to work with elements added dynamically later.
Note: if you use scripts loaded via content distribution network, you'll find that they are often cached locally in the browser anyway and don't really hurt your page load time. The same is true with scripts on your own site, if they've already been loaded once.
You have two competing things to optimize for, page load time over the network and page initialization time.
You can minimize your page load time over the network by taking maximum advantage of browser caching so that JS files don't have to be loaded over the network. To do this, you want as much javascript code for your site in on or two larger and fully minimized JS files. To do this, you should put JS for multiple different pages in one common JS file. It will vary from site to site whether the JS for all pages should be ine one or two larger JS files or whether you group it into a small number of common JS files that are each targeted at part of your site. But, the general idea is that you want to combine the JS code from different pages into a common JS file that can be most effectively cached.
You can minimize your page initialization time by only calling initialization code that actually needs to execute on the particular page that is being displayed. There are several different ways to approach this. I agree with the other callers that you do not want to be looking at URLs to decide which code to execute because this ties your code to the URL structure which is better to avoid. If your code has a manageable number of different types of pages, then I'd recommend identifying each of those page types with a unique class name on the body tag. You can then have your initialization code look for the appropriate class on the body tag and branch to the appropriate initialization code based on that. I've even seen it done where you find a class name with a particular common prefix, parse out the non-common part of the name and call an initialization function by that name. This allows you to give a page a specific set of behaviors by only adding a classname to the body tag. The code remains very separate from the actual page.
the less general purpose way of doing this is to keep all the code in the one or two common JS files, but to add the appropriate initialization call to each specific page's HTML. So, the JS code that does the initialization code lives in the common JS files and thus is maximally cached, but the calling of the appropriate initialization code for that page is embedded inline in each specific page. This minimizes the execution time of the initialization, but still lets you use maximal caching. It's slightly less generic than the class name technique mentioned earlier, but some may like the more direct calling technique.
Include scripts at bottom of pages that need it only.
The YSlow add-on is the best solution to know why your website is slow.
There are many issues which could be the reason for slowness.
Combining many jQuery to one could help you increasing your performance.
Also you can put the script at the bottom of your page and CSS at top.
Its basically up to you and depends on what the code is.
Generally with small things I will slip it into the bottom of the page. (I'm talking minor ui things that relate only to that page).
If you're doing the location ref testing for more than a couple pages it probably means you're doing something wrong.
You might want to take a look at one of these:
http://en.wikipedia.org/wiki/Unobtrusive_JavaScript
http://2tbsp.com/node/91
And as for which is faster it's wildly negligible, pick what is easier for you to maintain.

Can I make a custom colour definitions that I can share between CSS, JS and HTML?

I have a blue-ish colour that I want to use in many places in my app and at the moment I am copying and pasting it between styles in my CSS. Is there a way of defining a constant like the standard colours, 'blue', 'red' etc. that I could share between my CSS, my HTML and my JS?
I'd like to be able to say (somewhere, preferably CSS)
myblue = #33CC99
in CSS say...
background-color:myblue;
in HTML say...
<td color="myblue"/>
and in JavaScript
tag.style.backgroundColor = myblue;
I'm guessing this is impossible and google turned nothing up, so has anyone got any ideas? I doubt I am the only person to come across this.
A very promising product that "compiles" higher-level expressions like variables into CSS is LESS. It needs Ruby. I haven't used it yet but it's definitely worth a look.
A more primitive way to do this would be using a server-side scripting language like PHP.
You would define constants in PHP like so:
define ("MYBLUE", "#33CC99");
and then outputting the value where needed using <?=MYBLUE;?>
Big downside: To do this in external css and js files, you would obviously have to have them parsed by the PHP interpreter, which is not good performance wise if you have a lot of visitors. For a low-traffic site, it probably doesn't matter.
Yes, this is impossible. You could, however, write your own CSS preprocessor (or use one of the existing ones out there), for instance with PHP. The big downside is that you would have to output the colorcode on your whole site with PHP and your scripts would look like
tag.style.backgroundColor = <? echo $myblue; ?>
and likewise in CSS
.someClass {
background-color: <? echo $myblue ?>
}
or something similar. And that isn't really nice either. Of course you could use any server sided script language of your choice. As far as I can judge, this is the only possibility to use a color-constant throughout a whole website.
You could have a look at some processors:
http://cssp.codeplex.com/
http://www.shauninman.com/archive/2007/06/27/css_server_side_pre_processor
http://icant.co.uk/articles/cssconstants/
You may look at HAML+SASS. Though you cannot define variables for all three languages at once, these two can make writing HTML+CSS much easier.
How I would approach this is to make a class in my CSS.
.color_class {color: #33CC99;}
Then call it in my HTML
<td class="color_class" />
You can assign multiple classes to an HTML element.
In the JS, just name the class
document.getElementById('id').className = 'color_class';
Of course you can play with how you want to select your element. A JS library probably has even easier methods for assigning CSS classes.
To achieve this with out using any dynamic CSS (e.g. serving a PHP file with content-type text/css), your best bet is to separate out the places where you define the 'theme'.
<script type="text/javascript">
var theme = '#003366';
</script>
Then you can use a JavaScript file to write out styles based on the themes.
However, if you are able to use a CSS pre-processor, go with that. You'll have much more flexibility and the code will be easier to maintain. I almost always use a PHP or JSP page for CSS.
As other users have noted you can't do this in straight HTML, JS or CSS unless you pass all HTML, JS and CSS content via a CGI/PHP/ASP script - which isn't actually a bad approach as it's easy to maintain.
If you use a query string in the reference to included CSS / JS files - e.g. '/css/stylesheet.php?timestamp=2010-01-01+00:00:00', then almost all clients will aggressively cache your CSS/JS files, negating any impact on load parsing them in a scripting language may have (though unless the site is likely to be particularly busy I wouldn't be too connected about that).
If you are using Apache (which is likely), an alternative approach would be do use something like mod_set to re-write all HTML, JS and CSS files on the fly for you. This may be more difficult to support if you are not familiar with configuring Apache (or are using another web server).
With regard to tag naming:
With either approach I strong suggest using a clear tagging system to denote your dynamic variables (e.g. %MyBlue%) and to consider having variables names be representative (e.g. %HeadingBackgroundColor%, %FontColor%, even if both are set to %MyBlue%), as that can prevent things getting hairy later on (when you discover that changing one value has intended consequences).
Using more representative names may seem unnecessarily verbose at first glance, but it causes problems in many cases because colours end up clash in unintended ways when they are significantly different from the original scheme (this is true of a lot of mainstream software which is skinnable - because the author made the assumption that %value1% and %value2% would always go together and so would %value1% and %value3% - meaning in effect the options for themeing are severely limited by an unintended dependancy).
I do this at build time by running my CSS files through Freemarker.
I am not sure of your end goal. If it is to allow selection of one of several themes for a web page, you could simply have multiple CSS files, and a cookie/session variable/database store of the user's prefered style sheet. Then you could just do
<link rel=<? echo stylepref; ?> type='text/css'>
or something along those lines
If you want to be able to completely customize the site, then one of the above answers would be needed.
There's no concept of 'variables' in CSS, but I'd strongly recommend not doing what you're doing. there's no good reason that you can't define all your style information in your CSS sheet as CSS classes. If you do that, and then just apply said classes in html and javascript, that's one major load off in terms of copying and pasting.
Second, remember that you can define more than one CSS class for an element, e.g.
<div class='blue-text white-background'>my content</div>
You can then define those independantly in CSS, a la:
.blue-text { color : Blue; }
.white-background { background-color: white;}
and you can even create rules that only take effect when both are applyed:
.blue-text.white-background { color : AliceBlue; }
If you want to have the color choices dynamically generated, the only real way to do that is as others have suggested, which is either preprocess your files before deployment, or have the CSS dynamically generated and served by your language of choice.
In pure client side CSS grouping selectors allows you to put the same color on many different elements:
p, .red, #sub, div a:link { color: #f00; }

Commonly accepted best practices around code organization in JavaScript [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
As JavaScript frameworks like jQuery make client side web applications richer and more functional, I've started to notice one problem...
How in the world do you keep this organized?
Put all your handlers in one spot and write functions for all the events?
Create function/classes to wrap all your functionality?
Write like crazy and just hope it works out for the best?
Give up and get a new career?
I mention jQuery, but it's really any JavaScript code in general. I'm finding that as lines upon lines begin to pile up, it gets harder to manage the script files or find what you are looking for. Quite possibly the biggest propblems I've found is there are so many ways to do the same thing, it's hard to know which one is the current commonly accepted best practice.
Are there any general recommendations on the best way to keep your .js files as nice and neat as the rest of your application? Or is this just a matter of IDE? Is there a better option out there?
EDIT
This question was intended to be more about code organization and not file organization. There has been some really good examples of merging files or splitting content around.
My question is: what is the current commonly accepted best practice way to organize your actual code? What is your way, or even a recommended way to interact with page elements and create reuseable code that doesn't conflict with each other?
Some people have listed namespaces which is a good idea. What are some other ways, more specifically dealing with elements on the page and keeping the code organized and neat?
It would be a lot nicer if javascript had namespaces built in, but I find that organizing things like Dustin Diaz describes here helps me a lot.
var DED = (function() {
var private_var;
function private_method()
{
// do stuff here
}
return {
method_1 : function()
{
// do stuff here
},
method_2 : function()
{
// do stuff here
}
};
})();
I put different "namespaces" and sometimes individual classes in separate files. Usually I start with one file and as a class or namespace gets big enough to warrant it, I separate it out into its own file. Using a tool to combine all you files for production is an excellent idea as well.
I try to avoid including any javascript with the HTML. All the code is encapsulated into classes and each class is in its own file. For development, I have separate <script> tags to include each js file, but they get merged into a single larger package for production to reduce the overhead of the HTTP requests.
Typically, I'll have a single 'main' js file for each application. So, if I was writing a "survey" application, i would have a js file called "survey.js". This would contain the entry point into the jQuery code. I create jQuery references during instantiation and then pass them into my objects as parameters. This means that the javascript classes are 'pure' and don't contain any references to CSS ids or classnames.
// file: survey.js
$(document).ready(function() {
var jS = $('#surveycontainer');
var jB = $('#dimscreencontainer');
var d = new DimScreen({container: jB});
var s = new Survey({container: jS, DimScreen: d});
s.show();
});
I also find naming convention to be important for readability. For example: I prepend 'j' to all jQuery instances.
In the above example, there is a class called DimScreen. (Assume this dims the screen and pops up an alert box.) It needs a div element that it can enlarge to cover the screen, and then add an alert box, so I pass in a jQuery object. jQuery has a plug-in concept, but it seemed limiting (e.g. instances are not persistent and cannot be accessed) with no real upside. So the DimScreen class would be a standard javascript class that just happens to use jQuery.
// file: dimscreen.js
function DimScreen(opts) {
this.jB = opts.container;
// ...
}; // need the semi-colon for minimizing!
DimScreen.prototype.draw = function(msg) {
var me = this;
me.jB.addClass('fullscreen').append('<div>'+msg+'</div>');
//...
};
I've built some fairly complex appliations using this approach.
You can break up your scripts into separate files for development, then create a "release" version where you cram them all together and run YUI Compressor or something similar on it.
Inspired by earlier posts I made a copy of Rakefile and vendor directories distributed with WysiHat (a RTE mentioned by changelog) and made a few modifications to include code-checking with JSLint and minification with YUI Compressor.
The idea is to use Sprockets (from WysiHat) to merge multiple JavaScripts into one file, check syntax of the merged file with JSLint and minify it with YUI Compressor before distribution.
Prerequisites
Java Runtime
ruby and rake gem
You should know how to put a JAR into Classpath
Now do
Download Rhino and put the JAR ("js.jar") to your classpath
Download YUI Compressor and put the JAR (build/yuicompressor-xyz.jar) to your classpath
Download WysiHat and copy "vendor" directory to the root of your JavaScript project
Download JSLint for Rhino and put it inside the "vendor" directory
Now create a file named "Rakefile" in the root directory of the JavaScript project and add the following content to it:
require 'rake'
ROOT = File.expand_path(File.dirname(__FILE__))
OUTPUT_MERGED = "final.js"
OUTPUT_MINIFIED = "final.min.js"
task :default => :check
desc "Merges the JavaScript sources."
task :merge do
require File.join(ROOT, "vendor", "sprockets")
environment = Sprockets::Environment.new(".")
preprocessor = Sprockets::Preprocessor.new(environment)
%w(main.js).each do |filename|
pathname = environment.find(filename)
preprocessor.require(pathname.source_file)
end
output = preprocessor.output_file
File.open(File.join(ROOT, OUTPUT_MERGED), 'w') { |f| f.write(output) }
end
desc "Check the JavaScript source with JSLint."
task :check => [:merge] do
jslint_path = File.join(ROOT, "vendor", "jslint.js")
sh 'java', 'org.mozilla.javascript.tools.shell.Main',
jslint_path, OUTPUT_MERGED
end
desc "Minifies the JavaScript source."
task :minify => [:merge] do
sh 'java', 'com.yahoo.platform.yui.compressor.Bootstrap', '-v',
OUTPUT_MERGED, '-o', OUTPUT_MINIFIED
end
If you done everything correctly, you should be able to use the following commands in your console:
rake merge -- to merge different JavaScript files into one
rake check -- to check the syntax of your code (this is the default task, so you can simply type rake)
rake minify -- to prepare minified version of your JS code
On source merging
Using Sprockets, the JavaScript pre-processor you can include (or require) other JavaScript files. Use the following syntax to include other scripts from the initial file (named "main.js", but you can change that in the Rakefile):
(function() {
//= require "subdir/jsfile.js"
//= require "anotherfile.js"
// some code that depends on included files
// note that all included files can be in the same private scope
})();
And then...
Take a look at Rakefile provided with WysiHat to set the automated unit testing up. Nice stuff :)
And now for the answer
This does not answer the original question very well. I know and I'm sorry about that, but I've posted it here because I hope it may be useful to someone else to organize their mess.
My approach to the problem is to do as much object-oriented modelling I can and separate implementations into different files. Then the handlers should be as short as possible. The example with List singleton is also nice one.
And namespaces... well they can be imitated by deeper object structure.
if (typeof org === 'undefined') {
var org = {};
}
if (!org.hasOwnProperty('example')) {
org.example = {};
}
org.example.AnotherObject = function () {
// constructor body
};
I'm not big fan of imitations, but this can be helpful if you have many objects that you would like to move out of the global scope.
The code organization requires adoption of conventions and documentation standards:
1. Namespace code for a physical file;
Exc = {};
2. Group classes in these namespaces javascript;
3. Set Prototypes or related functions or classes for representing real-world objects;
Exc = {};
Exc.ui = {};
Exc.ui.maskedInput = function (mask) {
this.mask = mask;
...
};
Exc.ui.domTips = function (dom, tips) {
this.dom = gift;
this.tips = tips;
...
};
4. Set conventions to improve the code. For example, group all of its internal functions or methods in its class attribute of an object type.
Exc.ui.domTips = function (dom, tips) {
this.dom = gift;
this.tips = tips;
this.internal = {
widthEstimates: function (tips) {
...
}
formatTips: function () {
...
}
};
...
};
5. Make documentation of namespaces, classes, methods and variables. Where necessary also discuss some of the code (some FIs and Fors, they usually implement important logic of the code).
/**
* Namespace <i> Example </i> created to group other namespaces of the "Example".
*/
Exc = {};
/**
* Namespace <i> ui </i> created with the aim of grouping namespaces user interface.
*/
Exc.ui = {};
/**
* Class <i> maskdInput </i> used to add an input HTML formatting capabilities and validation of data and information.
* # Param {String} mask - mask validation of input data.
*/
Exc.ui.maskedInput = function (mask) {
this.mask = mask;
...
};
/**
* Class <i> domTips </i> used to add an HTML element the ability to present tips and information about its function or rule input etc..
* # Param {String} id - id of the HTML element.
* # Param {String} tips - tips on the element that will appear when the mouse is over the element whose identifier is id <i> </i>.
*/
Exc.ui.domTips = function (id, tips) {
this.domID = id;
this.tips = tips;
...
};
These are just some tips, but that has greatly helped in organizing the code. Remember you must have discipline to succeed!
Following good OO design principals and design patterns goes a long way to making your code easy to maintain and understand.
But one of the best things I've discovered recently are signals and slots aka publish/subscribe.
Have a look at http://markdotmeyer.blogspot.com/2008/09/jquery-publish-subscribe.html
for a simple jQuery implementation.
The idea is well used in other languages for GUI development. When something significant happens somewhere in your code you publish a global synthetic event which other methods in other objects may subscribe to.
This gives excellent separation of objects.
I think Dojo (and Prototype?) have a built in version of this technique.
see also What are signals and slots?
I was able to successfully apply the Javascript Module Pattern to an Ext JS application at my previous job. It provided a simple way to create nicely encapsulated code.
Dojo had the module system from the day one. In fact it is considered to be a cornerstone of Dojo, the glue that holds it all together:
dojo.require — the official doc.
Understanding dojo.declare, dojo.require, and dojo.provide.
Introducing Dojo.
Using modules Dojo achieves following objectives:
Namespaces for Dojo code and custom code (dojo.declare()) — do not pollute the global space, coexist with other libraries, and user's non-Dojo-aware code.
Loading modules synchronously or asynchronously by name (dojo.require()).
Custom builds by analyzing module dependencies to create a single file or a group of interdependent files (so-called layers) to include only what your web application needs. Custom builds can include Dojo modules and customer-supplied modules as well.
Transparent CDN-based access to Dojo and user's code. Both AOL and Google carry Dojo in this fashion, but some customers do that for their custom web applications as well.
Check out JavasciptMVC.
You can :
split up your code into model, view and controller layers.
compress all code into a single production file
auto-generate code
create and run unit tests
and lots more...
Best of all, it uses jQuery, so you can take advantage of other jQuery plugins too.
My boss still speaks of the times when they wrote modular code (C language), and complains about how crappy the code is nowadays! It is said that programmers can write assembly in any framework. There is always a strategy to overcome code organisation. The basic problem is with guys who treat java script as a toy and never try to learn it.
In my case, I write js files on a UI theme or application screen basis, with a proper init_screen(). Using proper id naming convention, I make sure that there are no name space conflicts at the root element level. In the unobstrusive window.load(), I tie the things up based on the top level id.
I strictly use java script closures and patterns to hide all private methods. After doing this, never faced a problem of conflicting properties/function definitions/variable definitions. However, when working with a team it is often difficult to enforce the same rigour.
I'm surprised no one mentioned MVC frameworks. I've been using Backbone.js to modularize and decouple my code, and it's been invaluable.
There are quite a few of these kinds of frameworks out there, and most of them are pretty tiny too. My personal opinion is that if you're going to be writing more than just a couple lines of jQuery for flashy UI stuff, or want a rich Ajax application, an MVC framework will make your life much easier.
"Write like crazy and just hope it works out for the best?", I've seen a project like this which was developed and maintained by just 2 developers, a huge application with lots of javascript code. On top of that there were different shortcuts for every possible jquery function you can think of. I suggested they organize the code as plugins, as that is the jquery equivalent of class, module, namespace... and the whole universe. But things got much worse, now they started writing plugins replacing every combination of 3 lines of code used in the project.
Personaly I think jQuery is the devil and it shouldn't be used on projects with lots of javascript because it encourages you to be lazy and not think of organizing code in any way. I'd rather read 100 lines of javascript than one line with 40 chained jQuery functions (I'm not kidding).
Contrary to popular belief it's very easy to organize javascript code in equivalents to namespaces and classes. That's what YUI and Dojo do. You can easily roll your own if you like. I find YUI's approach much better and efficient. But you usualy need a nice editor with support for snippets to compensate for YUI naming conventions if you want to write anything useful.
I create singletons for every thing I really do not need to instantiate several times on screen, a classes for everything else. And all of them are put in the same namespace in the same file. Everything is commented, and designed with UML , state diagrams. The javascript code is clear of html so no inline javascript and I tend to use jquery to minimize cross browser issues.
In my last project -Viajeros.com- I've used a combination of several techniques. I wouldn't know how to organize a web app -- Viajeros is a social networking site for travellers with well-defined sections, so it's kind of easy to separate the code for each area.
I use namespace simulation and lazy loading of modules according to the site section. On each page load I declare a "vjr" object, and always load a set of common functions to it (vjr.base.js). Then each HTML page decides which modules need with a simple:
vjr.Required = ["vjr.gallery", "vjr.comments", "vjr.favorites"];
Vjr.base.js gets each one gzipped from the server and executes them.
vjr.include(vjr.Required);
vjr.include = function(moduleList) {
if (!moduleList) return false;
for (var i = 0; i < moduleList.length; i++) {
if (moduleList[i]) {
$.ajax({
type: "GET", url: vjr.module2fileName(moduleList[i]), dataType: "script"
});
}
}
};
Every "module" has this structure:
vjr.comments = {}
vjr.comments.submitComment = function() { // do stuff }
vjr.comments.validateComment = function() { // do stuff }
// Handlers
vjr.comments.setUpUI = function() {
// Assign handlers to screen elements
}
vjr.comments.init = function () {
// initialize stuff
vjr.comments.setUpUI();
}
$(document).ready(vjr.comments.init);
Given my limited Javascript knowledge, I know there must be better ways to manage this, but until now it's working great for us.
Organising your code in a Jquery centric NameSpace way may look as follows... and will not clash with other Javascript API's like Prototype, Ext either.
<script src="jquery/1.3.2/jquery.js" type="text/javascript"></script>
<script type="text/javascript">
var AcmeJQ = jQuery.noConflict(true);
var Acme = {fn: function(){}};
(function($){
Acme.sayHi = function()
{
console.log('Hello');
};
Acme.sayBye = function()
{
console.log('Good Bye');
};
})(AcmeJQ);
// Usage
// Acme.sayHi();
// or
// Say Hello
</script>
Hope this helps.
Good principal of OO + MVC would definitely go a long way for managing a complex javascript app.
Basically I am organizing my app and javascript to the following familiar design (which exists all the way back from my desktop programming days to Web 2.0)
Description for the numeric values on the image:
Widgets representing the views of my application. This should be extensible and separated out neatly resulting good separation that MVC tries to achieve rather than turning my widget into a spaghetti code (equivalent in web app of putting a large block of Javascript directly in HTML). Each widget communicate via others by listening to the event generated by other widgets thus reducing the strong coupling between widgets that could lead to unmanageable code (remember the day of adding onclick everywhere pointing to a global functions in the script tag? Urgh...)
Object models representing the data that I want to populate in the widgets and passing back and forth to the server. By encapsulating the data to its model, the application becomes data format agnostics. For example: while Naturally in Javascript these object models are mostly serialized and deserialized into JSON, if somehow the server is using XML for communication, all I need to change is changing the serialization/deserialization layer and not necessarily needs to change all the widget classes.
Controller classes that manage the business logic and communication to the server + occasionally caching layer. This layer control the communication protocol to the server and put the necessary data into the object models
Classes are wrapped neatly in their corresponding namespaces. I am sure we all know how nasty global namespace could be in Javascript.
In the past, I would separate the files into its own js and use common practice to create OO principles in Javascript. The problem that I soon found that there are multiple ways to write JS OO and it's not necessarily that all team members have the same approach. As the team got larger (in my case more than 15 people), this gets complicated as there is no standard approach for Object Oriented Javascript. At the same time I don't want to write my own framework and repeat some of the work that I am sure smarter people than I have solved.
jQuery is incredibly nice as Javascript Framework and I love it, however as project gets bigger, I clearly need additional structure for my web app especially to facilitate standardize OO practice. For myself, after several experiments, I find that YUI3 Base and Widget (http://yuilibrary.com/yui/docs/widget/ and http://yuilibrary.com/yui/docs/base/index.html) infrastructure provides exactly what I need. Few reasons why I use them.
It provides Namespace support. A real need for OO and neat organization of your code
It support notion of classes and objects
It gives a standardize means to add instance variables to your class
It supports class extension neatly
It provides constructor and destructor
It provides render and event binding
It has base widget framework
Each widget now able to communicate to each other using standard event based model
Most importantly, it gives all the engineers an OO Standard for Javascript development
Contrary to many views, I don't necessarily have to choose between jQuery and YUI3. These two can peacefully co-exist. While YUI3 provides the necessary OO template for my complex web app, jQuery still provides my team with easy to use JS Abstraction that we all come to love and familiar with.
Using YUI3, I have managed to create MVC pattern by separating classes that extend the Base as the Model, classes that extends Widget as a View and off course you have Controller classes that are making necessary logic and server side calls.
Widget can communicate with each other using event based model and listening to the event and doing the necessary task based on predefined interface. Simply put, putting OO + MVC structure to JS is a joy for me.
Just a disclaimer, I don't work for Yahoo! and simply an architect that is trying to cope with the same issue that is posed by the original question. I think if anyone finds equivalent OO framework, this would work as well. Principally, this question applies to other technologies as well. Thank God for all the people who came up with OO Principles + MVC to make our programming days more manageable.
I use Dojo's package management (dojo.require and dojo.provide) and class system (dojo.declare which also allows for simple multiple inheritance) to modularize all of my classes/widgets into separate files. Not only dose this keep your code organized, but it also lets you do lazy/just in time loading of classes/widgets.
A few days ago, the guys at 37Signals released a RTE control, with a twist. They made a library that bundles javascript files using a sort of pre-processor commands.
I've been using it since to separate my JS files and then in the end merge them as one. That way I can separate concerns and, in the end, have only one file that goes through the pipe (gzipped, no less).
In your templates, check if you're in development mode, and include the separate files, and if in production, include the final one (which you'll have to "build" yourself).
Create fake classes, and make sure that anything that can be thrown into a separate function that makes sense is done so. Also make sure to comment a lot, and not to write spagghetti code, rather keeping it all in sections. For example, some nonsense code depicting my ideals. Obviously in real life I also write many libraries that basically encompass their functionality.
$(function(){
//Preload header images
$('a.rollover').preload();
//Create new datagrid
var dGrid = datagrid.init({width: 5, url: 'datalist.txt', style: 'aero'});
});
var datagrid = {
init: function(w, url, style){
//Rendering code goes here for style / width
//code etc
//Fetch data in
$.get(url, {}, function(data){
data = data.split('\n');
for(var i=0; i < data.length; i++){
//fetching data
}
})
},
refresh: function(deep){
//more functions etc.
}
};
Use inheritance patterns to organize large jQuery applications.
I think this ties into, perhaps, DDD (Domain-Driven Design). The application I'm working on, although lacking a formal API, does give hints of such by way of the server-side code (class/file names, etc). Armed with that, I created a top-level object as a container for the entire problem domain; then, I added namespaces in where needed:
var App;
(function()
{
App = new Domain( 'test' );
function Domain( id )
{
this.id = id;
this.echo = function echo( s )
{
alert( s );
}
return this;
}
})();
// separate file
(function(Domain)
{
Domain.Console = new Console();
function Console()
{
this.Log = function Log( s )
{
console.log( s );
}
return this;
}
})(App);
// implementation
App.Console.Log('foo');
For JavaScript organization been using the following
Folder for all your javascript
Page level javascript gets its' own file with the same name of the page. ProductDetail.aspx would be ProductDetail.js
Inside the javascript folder for library files I have a lib folder
Put related library functions in a lib folder that you want to use throughout your application.
Ajax is the only javascript that I move outside of the javascript folder and gets it's own folder. Then I add two sub folders client and server
Client folder gets all the .js files while server folder gets all the server side files.
I'm using this little thing. It gives you 'include' directive for both JS and HTML templates. It eleminates the mess completely.
https://github.com/gaperton/include.js/
$.include({
html: "my_template.html" // include template from file...
})
.define( function( _ ){ // define module...
_.exports = function widget( $this, a_data, a_events ){ // exporting function...
_.html.renderTo( $this, a_data ); // which expands template inside of $this.
$this.find( "#ok").click( a_events.on_click ); // throw event up to the caller...
$this.find( "#refresh").click( function(){
widget( $this, a_data, a_events ); // ...and update ourself. Yep, in that easy way.
});
}
});
You can use jquery mx (used in javascriptMVC) which is a set of scripts that allows you to use models, views, and controllers. I've used it in a project and helped me create structured javascript, with minimal script sizes because of compression. This is a controller example:
$.Controller.extend('Todos',{
".todo mouseover" : function( el, ev ) {
el.css("backgroundColor","red")
},
".todo mouseout" : function( el, ev ) {
el.css("backgroundColor","")
},
".create click" : function() {
this.find("ol").append("<li class='todo'>New Todo</li>");
}
})
new Todos($('#todos'));
You can also use only the controller side of jquerymx if you aren't interested in the view and model parts.
Your question is one that plagued me late last year. The difference - handing the code off to new developers who had never heard of private and public methods. I had to build something simple.
The end result was a small (around 1KB) framework that translates object literals into jQuery. The syntax is visually easier to scan, and if your js grows really large you can write reusable queries to find things like selectors used, loaded files, dependent functions, etc.
Posting a small framework here is impractical, so I wrote a blog post with examples (My first. That was an adventure!). You're welcome to take a look.
For any others here with a few minutes to check it out, I'd greatly appreciate feedback!
FireFox recommended since it supports toSource() for the object query example.
Cheers!
Adam
I use a custom script inspired by Ben Nolan's behaviour (I can't find a current link to this anymore, sadly) to store most of my event handlers. These event handlers are triggered by the elements className or Id, for example.
Example:
Behaviour.register({
'a.delete-post': function(element) {
element.observe('click', function(event) { ... });
},
'a.anotherlink': function(element) {
element.observe('click', function(event) { ... });
}
});
I like to include most of my Javascript libraries on the fly, except the ones that contain global behaviour. I use Zend Framework's headScript() placeholder helper for this, but you can also use javascript to load other scripts on the fly with Ajile for example.
You don't mention what your server-side language is. Or, more pertinently, what framework you are using -- if any -- on the server-side.
IME, I organise things on the server-side and let it all shake out onto the web page. The framework is given the task of organising not only JS that every page has to load, but also JS fragments that work with generated markup. Such fragments you don't usually want emitted more than once - which is why they are abstracted into the framework for that code to look after that problem. :-)
For end-pages that have to emit their own JS, I usually find that there is a logical structure in the generated markup. Such localised JS can often be assembled at the start and/or end of such a structure.
Note that none of this absolves you from writing efficient JavaScript! :-)
Lazy Load the code you need on demand. Google does something like this with their google.loader

Categories