How can I introduce modules to a legacy javascript project? - javascript

I'm a developer on a very large, many-page web app. We're making a push to improve the sanity of our javascript, so I'd like to introduce a module loader. Currently everything is done the old-fashioned way of slapping a bunch of script tags on a page and hoping for the best. Some restrictions are:
Our html pages are templated, inherited, and composed, such that the final page sent to the client brings together pieces from many different source html files. Any of these given files may depend on javascript resources introduced higher up the chain.
This must be achievable piecemeal. The code base is far to large to convert everything at once, so I'm looking for a good solution for new pages, and for migrating over existing pages as needed.
This solution needs to coexist on the same page as existing, non-module javascript. Some things (like menus and analytics) exist on every page, and I can't remove global jquery, for instance, as it's used all over the place.
Basically I'd like a way to carve out safe spaces that use modules and modern dependency management. Most tutorials and articles I've read all target new projects.
Requirejs looks like a decent option, and I've played with it a bit. Its fully async nature is a hindrance in some cases though - I'd like to use requirejs to package up global resources but I can't do that if I can't control the execution order. Also, it sucks to have the main function of a page (say, rendering a table) happen after secondary things like analytics calls.
Any suggestions?

That's a lot to ask for. :-) So here are my thoughts on this:
Usually, when you load a web page - everything that was being displayed is wiped so that the new incoming information does not interfere with what was already there so you really have only a couple of options (that I know of) where you can keep everything in memory in the browser and yet load new pages as needed.
The first (and easiest) way is to use FRAMES. These are not used much anymore from what I've seen but each FRAME allows you to display a different web page. So what you do is to make one frame use 100% and the second one use "*" so it isn't seen. You can then use the unseen frame to control what is going on in the 100% frame.
The second way is to use Javascript to control everything. In this scenario you create a namespace area and then use jQuery's getscript() function to load in each page as you need it. I did this once by generating the HTML, converting it to hex via bin2hex(), send it back as a javascript function and then unhexing it in the browser and applying it to the web page. If it was to completely replace the web page you do that and if it was an update to a web page you just inserted it into the HTML already on the web page. Any new javascript function always attaches itself to the namespace. If a function is no longer needed, it can be removed from the namespace to free up memory.
Why convert the HTML to hex and then send it? Because then you can use whatever characters you want to us (like single and double quotes) and it doesn't affect Javascript at all. There are fairly fast hex routines available on GitHub (see my toHex and fromHex routines).
One of the extra benefits of using getScript() is that it can sometimes also make it almost impossible for anyone to see your code then. A fluke in how getScript() works which is documented.

Related

when building a website, should I refer to javascript libraries in specific user controls or in the master page?

which of following cases is strongest with regard to client side (JavaScript) library referencing and loading.
Please note that I assume the web solution is well designed so that the components are well encapsulated
Also, just to be clear, the master page I am talking about could be a user control or anything that holds all library references and loaded at the site-load regardless of the content of the site at the moment
1 - include references (link href) for all custom (e.g. 3rd party) libraries in the master page.
it's arguable this is easy to maintain because all references are in one place.
it's also arguable that it's easy to perform library upgrades so you don't need to hunt within the solution where the library is referred to update it's reference.
2 - include reference to libraries in their specific user controls
shouldn't this improve performance as the website only loads libraries when required.
e.g. one can refer to the JavaScript libraries that works for maps within the user control that deals with maps with contrast to loading maps libraries even when there's no map on the current view.
This encapsulates components well. for example, a developer who tries to fix a bug in the map component will see all the libraries it refers to when he opens the map user control. This stops the need to go through the master page and see which libraries are used.
I don't think this is the right way to think about it.
The only reason not to load all libraries is performance. The debug reason you give is too minor to consider.
You can increase performance in many different ways. By far the easiest, most straightforward and attainable is to minify all your JavaScript into one file. You can additionally use a compiler like Google's Closure Compiler or Yahoo YUI Compressor to get a smaller filesize and faster execution.
If at this point you still have performance issues (that can be attributed to network latency) then maybe look into lazy loading your libraries.
This doesn't mean you should forgo the guidelines of dependency injection. Any good framework will offer you a mechanism for dependency injection. This should make switching to solution 2 at a later point fairly trivial.

HTML/Javascript system for many different popups and widgets in the same page

I'm making a HTML5 page (game) which uses lot of popups and all kind of widgets appearing and dissapearing in the same page.
To implement this I could
Have all the popups and widgets listed in the page, invisible (like lot of examples I saw), and keep toggling only visibility.
Add and remove dynamically, using Javascript. I could put each popup as HTML fragment in a separate file (?).
The seconds is "modular" and I like the fact that I have no elements in the page which I'm not acutally using. But I don't know about performance (load HTML each time, DOM insertiong, etc.).
Is there a prefered/standard way to do this?
If we are talking about loading HTML from server, then obviously this won't be efficient.
I don't know what kind of game you are writing but I don't think there will be any visible difference in performance (except for loading data from server) unless you create like thousands popups per second (I doubt it). Let's be honest - your game isn't using like 4GB of memory. :) And if it is, then you're probably doing something wrong. And I do not think there is any standard way. It's more like how you feel it. :)
For example I always try to load every possible data from server with one request and store it on client-side, because most problems with performance is actually related to client-server communication. I also like the DOM to be clean, so in most cases I hold the (hidden) data in JavaScript, except for forms' hidden fields.
On the other hand, if I have for example blog with discussion and I load some additional data (for example user data, which is supposed to appear as a popup after click on the user's name) I tend to store it in DOM elements because it is easier (at least for me) to control it (I'm talking about jQuery and jQuery UI).
Note that it is possible that recreating popups may lead to memory leaks, but it is highly unlikely if you use some popular library like (for example) jQuery UI.

Why doesn't javascript have a better way to include files?

I've seen a few ways that you can make a javascript file include other javascript files, but they all seem pretty hacky - mostly they involve tacking the javascript file onto the end of the current document and then loading it in some way.
Why doesn't javascript just include a simple "load this file and execute the script in it" include directive? It's not like this is a new concept. I know that everyone is excited about doing everything in HTML5 with javascript etc, but isn't it going to be hard if you have to hack around omission of basic functionality like this?
I can't see how it would be a security concern, since a web page can include as many javascript files as it likes, and they all get executed anyway.
The main problems with the current inclusion system (ie, add additional script tags) involve latency. Since a script tag can insert code at the point of inclusion, as soon as a script tag is encountered, further parsing has to more-or-less stop until the JS downloads and is executed (although the browser can continue to fetch resources in parallel). If the JS decides to run an inclusion, you've just added more latency on top of this - now you can't even fetch your scripts in parallel.
Basically, it's trying to solve a problem that doesn't exist (since JS can already tack on additional script tags to do an inclusion), while making the latency problem worse. There are javascript minifiers out there that can merge JS files; you should look into using those instead, as they will help improve latency issues as well.
Actually, YUI 3 solves this problem beautifully. Feel free to check out the documentation: http://developer.yahoo.com/yui/3/yui/#use (that's the specific Use function which does this magic). Basically it works like this:
You define modules
When you create the core YUI object with YUI(), you specify which modules your code needs
Behind the scenes, YUI checks if those modules are loaded. If not, it asynchronously loads them on the page.
I've also read that the jQuery team's working on something similar (someone back me up here).
As to the philosophical argument that it'd be nice if this was built in, I think that may be a good feature. On the other hand, the simplicity of javascript is nice too. It allows a much lower point of entry for beginning programmers to do their thing. And for those of us that need it, great libraries like YUI are getting better every day.
the requirejs project attempts to solve this problem, please see for example
http://requirejs.org/docs/why.html
(I don't use it yet, though)

Whats a good argument for/against using inline javascript within the html body tag?

One of my co-workers is thinking that it is simpler to just include the document.ready() calls (MULTIPLE) for jquery anywhere in an html document, rather than trying to have them all in the head, foot or in an external js file. Can you give me your thoughts about this?
The document.ready stuff is loaded by modules that are included in a main template. I think this is messy. But I need a good argument point.
There are a number of problems with your coworker's approach:
It's not DRY. You must repeat the code each time you want to invoke it.
No ability to cache the same Javascript; it must be loaded with each new page.
If you decide to do it a different way later, N files are now different instead of one.
It will not be immediately obvious to a maintainer that this code is repeated across N different files.
Your coworker's approach is actually quite reasonable and pragmatic.
For the sake of completeness I'll point out that putting too much in ready() in the external JS file is a mistake. I started doing this once and ended up with a page load time of 500-1000ms with all this unnecessary JS code that was being executed. The external JS file(s) should be for declaring functions. The page itself should declare which of those things to actually run. This combines the best of minimal code execution and maximises caching (since the JS file is the same for all your pages).
At the top of the page you don't know what modules/components will be included in the document unless you declare it there as well, which (imho) is a worse case of repeating yourself.
The ideal approach would be some sort of multi-pass templating process that would allow included modules/components to trigger code that needs to be run and your template processor will combine all that and put it at the top of the page. I've actually written systems like this and it is quite doable but it's also more tedious.
You say it's messy but the other side of that coin is that when you look at a page it's easy to determine what code belongs to which module/component because they're adjacent. If you had a big blob of JS at the top of the page, how do you know what relates to what?
As long as you don't end up with dozens of script blocks I think your cowowrker's approach is fine. Any alternative needs to be just as clear and not execute more code than necessary.
If it's not single page specific, I wouldn't recommend it because maintenance is going to be a pain. If it is page specific, it can be better to place it as low in the document as possible, especially if it loads external scripts. Check out Cuzillion, a tool that helps you find the best combination for loading times.
If they're in the document itself, you can use server-side variables in the javascript itself, if your page is dynamic (php, asp.net). This can be very handy, but it prevents the javascript from being usable outside the page as a standalone. But if you're sure you're never going to need that javascript outside the page, that's definitely an advantage.
It depends.
One motivating factor for putting Javascript in the body is for progressive loading. If the Javascript is just before the </body> then it'll be downloaded last. In fact, even Google Analytics recommends this approach when including their tracking snippet.
However, most of the time even if you're worried about progressive loading you should use an external js file. External js files can be cached aggressively to save bandwidth so they're generally preferred. The only exceptions to that are when it's a small piece of Javascript that only one page uses, or if the Javascript itself needs to be created dynamically with a server-side language and writing it inline is just plain easier to do in that case.
EDIT:
There are multiple ways to do whatever you're doing, I'm sure. And I don't know what you're doing exactly. But since you mentioned Javascript next to every module, that gave me an idea. You could create unique id's for a div around each module. And then you could have a js file which performs operations on each module by those div id's (via a jQuery selector). That'd be a very jQuery-able solution.

What are advantages of using google.load('jQuery', ...) vs direct inclusion of hosted script URL?

Google hosts some popular JavaScript libraries at:
http://code.google.com/apis/ajaxlibs/
According to google:
The most powerful way to load the libraries is by using google.load() ...
What are the real advantages of using
google.load("jquery", "1.2.6")
vs.
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
?
Aside from the benefit of Google being able to bundle multiple files together on the request, there is no perk to using google.load. In fact, if you know all libraries that you want to use (say just jQuery 1.2.6), you're possibly making the user's browser perform one unneeded HTTP connection. Since the whole point of using Google's hosting is to reduce bandwidth consumption and response time, the best decision - if you're just using 1 library - is to call that library directly.
Also, if your site will be using any SSL certificates, you want to plan for this by calling the script via Google's HTTPS connection. There's no downside to calling a https script from an http page, but calling an http script from an https page will causing more obscure debugging problems than you would want to think about.
It allows you to dynamically load the libraries in your code, wherever you want.
Because it lets you switch directly to a new version of the library in the javascript, without forcing you to rebuild/change templates all across your site.
It lets Google change the URL (but they can't since the URL method is already established)
In theory, if you do several google.load()s, Google can bundle then into one file, but I don't think that is implemented.
I find it's very useful for testing different libraries and different methods, particularly if you're not used to them and want to see their differences side by side, without having to download them. It appears that one of the primary reason to do it, would be that it is asynchronous versus the synchronous script call. You also get some neat stuff that is directly included in the google loader, like client location. You can get their latitude and longitude from it. Not necessarily useful, but it may be helpful if you're planning to have targeted advertising or something of the like.
Not to mention that dynamic loading is always useful. Particularly to smooth out the initial site load. Keeping the initial "site load time" down to as little as possible is something every web designer is fighting an uphill battle on.
You might want to load a library only under special conditions.
Additionally the google.load method would speed up the initial page display. Otherwise the page rendering will freeze until the file has been loaded if you include script tags in your html code.
Personally, I'm interested in whether there's a caching benefit for browsers that will already have loaded that library as well. Seems like if someone browses to google and loads the right jQuery lib and then browses to my site and loads the right jQuery lib... ...both might well use the same cached jQuery. That's just a speculative possibility, though.
Edit: Yep, at very least when using the direct script tags to the location, the javascript library will be cached if someone has already called for the library from google (e.g. if it were included by another site somewhere).
If you were to write a boatload of JavaScript that only used the library when a particular event happens, you could wait until the event happens to download the library, which avoids unnecessary HTTP requests for those who don't actually end up triggering the event. However, in the case of libraries like Prototype + Scriptaculous, which downloads over 300kb of JavaScript code, this isn't practical.

Categories