assets pipeline control coffee script's closures - javascript

I have 2 simple coffee scripts and assets pipeline. I obtained:
(function() {
window.App.Test_widget = {...}
}).call(this);
(function() {
$.widget("ui.Test_widget", window.App.Test_widget);
$(document).ready(function() {...});
}).call(this);
but I want 1) merge closures 2) add closure parameter
(function($) {
var App;
App.Test_widget = {...}
$.widget("ui.Test_widget", App.Test_widget);
$(document).ready(function() {...});
})(jQuery);
I cant google a way of implementing this
UPD:
1) I dont want to place each file in different closures. I want to control this
2) I dont want to put anything in window if it is possible
ANSWER is simply: "use bare option. for sprockets see commit"

If you want that level of fine-grained control over output, you'll have to write your JavaScript yourself rather than allowing CoffeeScript to do it for you. I say that as an advocate of CoffeeScript: If you use it, you have to accept certain conventions that go along with it, such as the wrapper that gives each file its own scope. You lose the freedom to concatenate files however you want in order to share variables across files.
It's worth mentioning, however, that
In CoffeeScript 1.2.0+, the wrapper is added only when necessary. At least in your first file, that's not the case. (Edit: I was mistaken about this; this feature existed in 1.1.3 but disappeared before 1.2.0)
Writing $ = jQuery at the top of a function is semantically equivalent to having an argument named $ and passing in jQuery as the value of that argument. So you need only put $ = jQuery at the top of each of your CoffeeScript files in order to use jQuery in noConflict mode.

I think what you're describing is a deferred...you want to do something after your two closures finish? If so then look into jQuery 1.5 deferred infrastructure.

Related

Easy optional dependency on jQuery for RequireJS between Node.JS and browser

I'm using RequireJS, and trying to pack up a jQuery widget for easy usage into one file. Inside the widget's JavaScript code are a certain number of non-UI functions that don't call $-anything, that I'd like to export and be able to use on the server side.
(The shared routines that don't depend on jQuery used to be in a separate module called client-server-common.js. But like I said, I'm looking to reduce the number of files...and there's no real reason to be hung up on including the dead code for the widget on the server. So the widget can just subsume the common code.)
I'd like my only dependencies for the widget to be jQuery and underscore, with jQuery optional (and it degrades into what was client-server-common.js in that case). So the interface I'm looking for would be like:
require(['jquery', 'underscore'], function ($, _) {
var exports = {...};
if ($) {
// Do the stuff that only makes sense in the client
// Totally fine if there is no jquery; in that case
// all we probably care about are the exports
...
}
// Do the stuff for both client and server
...
// Return the exported functions
return exports;
}
Reading up on what others have asked, I notice this answer to this question from January says "You cannot really set it optional":
requireJS optional dependency
That's not what I want. Is that the last word? :-/
It seems that I can get around this by installing the jquery NPM package, which apparently does stuff with the DOM somehow:
Can I use jQuery with Node.js?
My understanding would be that if I added this dependency and just ignored it, I'd be okay. I might even find that there was some good reason to do DOM manipulation on the server (I haven't thought enough to figure out why or how that would be useful, is it?)
So should I add the dependency for simplicity's sake, and just not use it? Or can I rig it up so that I just give a jQuery of null on the server configuration, through some magic that doesn't involve waiting for timeouts and errors and hacks? Could someone make a "jquery-null" package that somehow just came back and gave you a {} or null for jQuery to smooth over situations like this?
Advice appreciated! :-/
The answer you mention says "You cannot really set it optional" and then gives a solution to operate even in the absence of modules. You can use an errback that will do nothing if running server-side.
The following code assumes that RequireJS' require call is available as requirejs. When loading RequireJS in a browser, this is the default (that is, after loading RequireJS requirejs === require is true.) Server-side, you would have to make it available with something like:
if (typeof window === "undefined")
var requirejs = require('requirejs');
(The above code would obviously fail if there is something in Node that sets window globally. I've never run into this problem.)
Once the above is taken care of we can do:
requirejs(['underscore'], function (_) {
var exports = {...};
requirejs(['jquery'], function ($) {
// This will execute only if jquery is present.
// Do the stuff that only makes sense in the client
// Totally fine if there is no jquery; in that case
// all we probably care about are the exports
...
}, function (err) {
// This will execute if there is an error.
// If server-side, do nothing. If client-side, scream!
});
// Do the stuff for both client and server
...
// Return the exported functions
return exports;
});
The answer you mentioned and RequireJS' documentation (which I linked above) mention checking the id of the failed module and undefining it. I'm quite certain that you would not need to undefine it since you won't try to load it again from a different place. Checking the module id would be a way to future-proof your code if someday jQuery depends on some other thing. Right now, loading jQuery just loads jQuery so if there is a failure it cannot be any other module than jQuery.
I would not include the actual code of jQuery server-side unless I'd have an actual substantial reason for it. What I would do if I wanted to get rid of the errback, for whatever reason, would be to have a build of my code for server-side use that includes a fake jQuery module. Something like:
define(function() {
return "I'm totally fake";
});
And then test it:
requirejs(['jquery'], function ($) {
if ($ !== "I'm totally fake") {
// Do the real deal.
}
});
If you do eventually need jQuery server-side, you'll have to also install something like jsdom. It used to be that installing jQuery with npm install jquery would include jsdom in the installation but I think this has changed recently.
I'm using RequireJS, and trying to pack up a jQuery widget for easy usage into one file. [..] I'd like my only dependencies for the widget to be jQuery and underscore, with jQuery optional [..] Reading up on what others have asked, I notice this answer to this question from January says "You cannot really set it optional" [..] That's not what I want. Is that the last word? :-/
No it's not the last word
This can be done elegantly and simple actually. I've described how to use an AMD module only when it's loaded in my answer to that question, but I'll repeat the gist of it here:
define(['require'], function(require){
if (require.defined('jquery') {
var $ = require('jquery');
$.fn.something = function(){};
}
});
We don't add the dependency directly, but instead manually require it only when it's already defined so we don't trigger any requests.
This form in which we declare a dependency on require, then use that inside our module is actually recommended by the RequireJS author, but my experimentation indicates that this actually also works:
define(require.defined('jquery') ? ['jquery'] : [], function($){
if ($) {
// Yippee, all jQuery awesomeness is available
}
});

"Can't find variable" error with Rails 3.1 and Coffeescript

I have views in my application that reference my application.js file which contains functions I use throughout my application.
I just installed the Rails 3.1 release candidate after having used the edge version of 3.1. Until I installed the RC I wasn't having any problems but now I'm getting this error:
ReferenceError: Can't find variable: indicator_tag
indicator_tag is a function I defined in application.js.
The only difference I notice in the javascript file is that now all my functions are wrapped in:
(function() { ... }).call(this);
I understand this is for variable scoping? But could it be preventing my pages from using those variables? And before anyone asks, I've made sure the javascript paths are correct in my include tags.
By default, every CoffeeScript file is compiled down into a closure. You cannot interact with functions from a different file, unless you export them to a global variable. I'd recommend doing something like this:
On top of every coffeescript file, add a line like
window.Application ||= {}
This will ensure that there's a global named Application present at all times.
Now, for every function that you'll have the need to call from another file, define them as
Application.indicator_tag = (el) ->
...
and call them using
Application.indicator_tag(params)
Dogbert's solution is a great way to go if you have a very sophisticated JS back-end. However, there's a much simpler solution if you only have a handful of functions you're working with. Just add them directly to the window object, like this:
window.indicator_tag = (el) ->
...
Then you can use your functions from anywhere without having to wrap them up in another object.

JavaScript dependency management

I am currently maintaining a large number of JS files and the dependency issue is growing over my head. Right now I have each function in a separate file and I manually maintain a database to work out the dependencies between functions.
This I would like to automate. For instance if I have the function f
Array.prototype.f = function() {};
which is referenced in another function g
MyObject.g = function() {
var a = new Array();
a.f();
};
I want to be able to detect that g is referencing f.
How do I go about this? Where do I start? Do I need to actually write a compiler or can I tweak Spidermonkey for instance? Did anyone else already do this?
Any pointers to get me started is very much appreciated
Thanks
Dok
Whilst you could theoretically write a static analysis tool that detected use of globals defined in other files, such as use of MyObject, you couldn't realistically track usage of prototype extension methods.
JavaScript is a dynamically-typed language so there's no practical way for any tool to know that a, if passed out of the g function, is an Array, and so if f() is called on it there's a dependency. It only gets determined what variables hold what types at run-time, so to find out you'd need an interpreter and you've made yourself a Turing-complete problem.
Not to mention the other dynamic aspects of JavaScript that completely defy static analysis, such as fetching properties by square bracket notation, the dreaded eval, or strings in timeouts or event handler attributes.
I think it's a bit of a non-starter really. You're probably better of tracking dependencies manually, but simplifying it by grouping related functions into modules which will be your basic unit of dependency tracking. OK, you'll pull in a few more functions that you technically need, but hopefully not too much.
It's also a good idea to namespace each module, so it's very clear where each call is going, making it easy to keep the dependencies in control manually (eg. by a // uses: ThisModule, ThatModule comment at the top).
Since extensions of the built-in prototypes are trickier to keep track of, keep them down to a bare minimum. Extending eg. Array to include the ECMAScript Fifth Edition methods (like indexOf) on browsers that don't already have them is a good thing to do as a basic fixup that all scripts will use. Adding completely new arbitrary functionality to existing prototypes is questionable.
Have you tried using a dependency manager like RequireJS or LabJS? I noticed no one's mentioned them in this thread.
From http://requirejs.org/docs/start.html:
Inside of main.js, you can use require() to load any other scripts you
need to run:
require(["helper/util"], function(util) {
//This function is called when scripts/helper/util.js is loaded.
//If util.js calls define(), then this function is not fired until
//util's dependencies have loaded, and the util argument will hold
//the module value for "helper/util".
});
You can nest those dependencies as well, so helper/util can require some other files within itself.
As #bobince already suggested, doing static analysis on a JavaScript program is a close to impossible problem to crack. Google Closure compiler does it to some extent but then it also relies on external help from JSDoc comments.
I had a similar problem of finding the order in which JS files should be concatenated in a previous project, and since there were loads of JS files, manually updating the inclusion order seemed too tedious. Instead, I stuck with certain conventions of what constitutes a dependency for my purposes, and based upon that and using simple regexp :) I was able to generated the correct inclusion order.
The solution used a topological sort algorithm to generate a dependency graph which then listed the files in the order in which they should be included to satisfy all dependencies. Since each file was basically a pseudo-class using MooTools syntax, there were only 3 ways dependencies could be created for my situation.
When a class Extended some other class.
When a class Implemented some other class.
When a class instantiated an object of some other class using the new keyword.
It was a simple, and definitely a broken solution for general purpose usage but it served me well. If you're interested in the solution, you can see the code here - it's in Ruby.
If your dependencies are more complex, then perhaps you could manually list the dependencies in each JS file itself using comments and some homegrown syntax such as:
// requires: Array
// requires: view/TabPanel
// requires: view/TabBar
Then read each JS file, parse out the requires comments, and construct a dependency graph which will give you the inclusion order you need.
It would be nice to have a tool that can automatically detect those dependencies for you and choose how they are loaded. The best solutions today are a bit cruder though. I created a dependency manager for my particular needs that I want to add to the list (Pyramid Dependency Manager). It has some key features which solve some unique use cases.
Handles other files (including inserting html for views...yes, you can separate your views during development)
Combines the files for you in javascript when you are ready for release (no need to install external tools)
Has a generic include for all html pages. You only have to update one file when a dependency gets added, removed, renamed, etc
Some sample code to show how it works during development.
File: dependencyLoader.js
//Set up file dependencies
Pyramid.newDependency({
name: 'standard',
files: [
'standardResources/jquery.1.6.1.min.js'
]
});
Pyramid.newDependency({
name:'lookAndFeel',
files: [
'styles.css',
'customStyles.css',
'applyStyles.js'
]
});
Pyramid.newDependency({
name:'main',
files: [
'createNamespace.js',
'views/buttonView.view', //contains just html code for a jquery.tmpl template
'models/person.js',
'init.js'
],
dependencies: ['standard','lookAndFeel']
});
Html Files
<head>
<script src="standardResources/pyramid-1.0.1.js"></script>
<script src="dependencyLoader.js"></script>
<script type="text/javascript">
Pyramid.load('main');
</script>
</head>
It does require you to maintain a single file to manage dependencies. I am thinking about creating a program that can automatically generate the loader file for you based on includes in the header but since it handles many different types of dependencies, maintaining them in one file might actually be better.
JSAnalyse uses static code analysis to detect dependencies between javascript files:
http://jsanalyse.codeplex.com/
It also allows you to define the allowed dependencies and to ensure it during the build, for instance. Of course, it cannot detect all dependencies because javascript is dynamic interpretet language which is not type-safe, like already mentioned. But it at least makes you aware of your javascript dependency graph and helps you to keep it under control.
I have written a tool to do something like this: http://github.com/damonsmith/js-class-loader
It's most useful if you have a java webapp and you structure your JS code in the java style. If you do that, it can detect all of your code dependencies and bundle them up, with support for both runtime and parse-time dependencies.

proper sequence of functions when coding in js

I am using jquery and am really frustrated at how I write my code. I started coding in JS and Jquery a few months ago and my code looked like this:
$(document).ready(function(){
$(function(){// a function that applies a plugin to an element});
$(function(){// another function that applies a plugin to an element});
$(function(){// and another function that applies a plugin to an element});
$(function(){// yet another function that applies a plugin to an element});
});
$(function(){//functions applied to certain elements that does not require to be initially loaded})
basically what I did before was put everything inside the $(document).ready
and here's how I am coding now
function a(){//a function that applies plugin to an element}
function b() {// another function}
$(document.ready(function(){a(); b();});
$(function(){//functions applied to certain elements that does not require to be initially loaded})
a little improvement, yet I am not satisfied. What if I want to call certain functions for a certain page only? are there ways to accomplish this? and I am really disgusted at how my $(document) gets really huge when I am using a lot of plugins.
How do you go about writing your functions in jquery?
I'd suggest at least namespacing things to ensure you don't pollute the global namespace. For example:
var myNameSpace = {
a: function(){//a function that applies plugin to an element},
b: function() {// another function}
};
$(document).ready(function() {
myNameSpace.a();
});
The main benefit is that you're able to compartmentalize your code into logical units of work which focus on specific tasks. It'll make code organization substantially easier.
Rebecca Murphey did a wonderful write-up on this topic which you can read here: http://bit.ly/6og36U
You can also separate your JS into their own unique files and write a routine to leverage jQuery's getScript() method to load the necessary files on-demand (http://docs.jquery.com/Ajax/jQuery.getScript). The key would be to determine the dependencies in your script and load the .js file at the appropriate time.
I recommend having one Javascript file for the whole site. That file should only contain functions:
function a() { ... }
function b() { ... }
The reason is that with one file it gets cached once (if done right) and that's it. And then using inline JS on each page I put:
$(function() {
a();
b();
});
I haven't really found a need to have multiple ready() calls.
The reason for this is efficiency. You don't want to be executing unnecessary Javascript and what's why the external JS file actually does nothing but include functions that you can call. Then each page only calls what it needs. Plus you can easily find it by just looking at one place (the page).
You might try to split your functions into multiple files and include just those which are needed for each page. In each file would be separate $(document).ready(function(){ ... });
I think there are two ways of achieving this:
A: split JavaScript into several files. (One library file and each with the side - specific code which also call the ready function.)
B: make one file with all the JavaScript and then some inline JavaScript file like this:
var tasksToRun = [ function_a, function_b,...]
In your library JavaScript you check for the global var and execute each function referenced in the array.
In my apps I tend to write all the functions for a given section of the app in within a closure to avoid namespace issues.
Something like this:
(function($) {
function a() {
// stuff
}
function b() {
// stuff
}
// ...
$(function() {
// invoke dom ready setup methods here
});
})(jQuery);
This has a bonus of letting my code be usable in other pages that may be using prototype or other js libraries (in large webapp with many devs like the one i work on, it's important to keep the namespace clean).
I generally only have one ready call per file. That call is responsible for setting up all the related things in that file. This allows each file to sort've act as a "library": developers that want to use the functionality just have to include it on the page and add the appropriate markup and the functionality will set itself up.
I admit I copied this layout from the way several jQuery plugins are built.
I like cletus' suggestion of a single file, but only when the app isn't too large. It starts to be difficult to maintain if you have too many things within a single file.

How do you take advantage of prototypal inheritance without needing to include files in a specific order?

When developing JavaScript, I tend to separate JavaScript code out into different files and then run a script to concatenate the files and compress or pack the resulting file. In the end, I have one file that I need to include on my production site.
This approach has usually worked, but I've started to run into a problems with prototypal inheritance. Specifically, if one class inherits from another class, the file for the parent class needs to be included already for the inheritance to work. If the concatenation script I'm using is simply concatenating a directory full of files, the child class might occur in the code before the parent class. Like this:
parent_class.js
var Namespace = Namespace || {};
Namespace.Parent = function () { };
Namespace.Parent.prototype.doStuff = function () { ... };
child_class.js
var NameSpace = Namespace || {};
Namespace.Child = function () { ... };
Namespace.Child.prototype = new Namespace.Parent();
The only way this works is if parent_class.js is included before child_class.js, which might not happen if the concatenation script places the child code before the parent code.
Is there a way to write this code so that the functionality is the same, but the order in which the code is written no longer matters?
Edit: I forgot that I'm using namespaces as well, so I added that to the code as well, which might change things a little bit.
When I've worked on large apps, I've use requireJS to divide my code into modules, and make sure those modules are loaded in the correct order. Then I just mark my derived class as depending on the parent class.
RequireJS comes with a tool that will combine and minify all your modules for production deployment as well.
If the concatenation script I'm using is simply concatenating a directory full of files, the child class might occur in the code before the parent class.
Is it too simple a solution to prepend a sort order value to each filename, and sort by name before performing the operation?
eg:
01_parent.js
02_child.js
Otherwise, perhaps maintaining a preordered list of files in a separate file. Maybe even go one step further and provide a hierarchical dependancy structure in xml to parse? This might be over-engineering the solution a bit :-D
Some options for ways to deal with the problem if you had no way of determining how the javascript files are written.
I suppose you could do something really hackish like this:
setTimeout(function() {
if(typeof(Parent) != "undefined" && typeof(Child) != "undefined") {
Child.prototype = new Parent();
} else {
setTimeout(arguments.callee, 50);
}
}, 50);
That code could also be anywhere, and would continually run until both the Parent and the Child were loaded...But I wouldn't do that.
Personally, I would just make sure your files are combined in the correct order.
If the objects are "namespaced" then you either have to switch to a build solution that incorporates in-order concatenation or use something like dojo.require (but obviously not dojo specific). Basically you want a framework that will provide you with the ability to check if a given identifier is available and pause execution and include it (via evaled ajax or an inserted script tag) if it isn't.

Categories

Resources