How can a Javascript module defined with AMD be extended? - javascript

First a bit of history, we have an engine which is made up of many javascript files which are essentially modules. These modules return a single class that are assigned to the global scope, although under a specified namespace.
The engine itself is used to display eLearning content, with each different eLearning course requiring slightly different needs, which is where we include javascript files into the page based on the necessary functionality. (There is only one entry page).
I've been trying to weigh up if it's worth changing to AMD, require.js and r.js or if it's better to stay with our current system which includes everything required on the page and minimises it into one script.
One of my biggest problems with going to AMD would be that it seems to be harder to extend a class easily. For example, sometimes we have to adjust the behaviour of the original class slightly. So we add another script include on the page that extends the original class by copying the original prototype, execute the original function that's being overridden with apply and then do whatever additional code is required.
Can you extend an AMD module without adapting the original file? Or am I missing the point and we're best staying with what we're doing at the moment?

I recently started a project using RequireJS, and the method I use to extend underscore boils down to something like this:
Relevant Directory Structure:
/scripts
/scripts/underscore.js
/scripts/base/underscore.js
The real underscore library goes to /scripts/base/underscore.js.
My extensions go in /scripts/underscore.js.
The code in /scripts/underscore.js looks like this:
define(['./base/underscore'], function (_) {
'use strict';
var exports = {};
// add new underscore methods to exports
_.mixin(exports); // underscore's method for adding methods to itself
return _; // return the same object as returned from the underscore module
});
For a normal extension, it could look more like this:
define(['underscore', './base/SomeClass'], function (_, SomeClass) {
'use strict';
_.extend(SomeClass.prototype, {
someMethod: function (someValue) {
return this.somethingOrOther(someValue * 5);
}
});
return SomeClass;
});
Note on underscore: Elsewhere I used the RequireJS shim-config to get underscore to load as an AMD module, but that should have no effect on this process with non-shimmed AMD modules.

You can have modules that contain your constructor functions. when these modules get included, they are ready for use. then you can create objects out of them afterwards.
example in require:
//construction.js
define(function(){
//expose a constructor function
return function(){
this....
}
});
//then in foo.js
define([construction],function(Construction){
var newObj = new Construction; //one object using constructor
});
//then in bar.js
define([construction],function(Construction){
//play with Construction's prototype here then use it
var newObj = new Construction;
});

Related

Building a Javascript utility library with AMD compatibility

My goal is to build a set of javascript tools for functional programming, to be used by our company's web developers. I've tried giving a look at the Underscore annotated source but I'm new with RequireJS and AMD, so it's a lot confusing for me.
To start I just want to have a variable that gets available when my library is imported.
In this case booleans is a module that has functions returning boolean values. For example: _myLib.booleans.isDefined(var) - returns true is var is a defined variable.
No I have RequireJS setup, but how do I make a variable available for usage?
My main.js:
requirejs(['app/booleans'], function (booleans) {
var _myLib = {};
_myLib.booleans = booleans;
return _myLib;
});
Of course _myLib is undefined, I suppose it's because it is not assigned to any scope.
Can anyone give me some lights on building this library?
Thanks in advance.
If you want to produce a proper AMD library, you need to set it so that it calls define to define itself as an AMD module.
define(['app/booleans'], function (booleans) {
var _myLib = {};
_myLib.booleans = booleans;
return _myLib;
});
If you called your file myLib.js and provided a good configuration to RequireJS for it to find it, then, when you want to use it, you can do:
require(["myLib"], function (myLib) {
myLib.booleans.isDefined("moo");
});
Or in another module:
define(["myLib"], function (myLib) {
myLib.booleans.isDefined("blah");
});

Javascript: dynamically assembling a module via recursive synchronous callbacks

Content
I have a large module that I am assembling in Javascript, which is problematic because JS currently has poor native module support.
Since my module is large, I personally do not like having one massive file with my module object e.g.
var my_module = {
func_1: function(param) {console.log(param)},
...,
func_n: function(param_1, param_2) {console.log(param_1 - param_2)}
}
where func_n ends around line number 3000. I would much rather store each of my functions (or several related functions) in separate files. I personally find this easier to manage.
This poses a problem, however, as although one could use synchronous calls to load the functions - the javascript will still be parsed asynchronously (to my understanding). Thus several independent synchronous calls to loading files is insufficient - as the mth file might call something related to the nth file (n < m) which has not yet been parsed causing an error.
Thus the solution a solution is apparent: recursively - synchronously - load files in the callback of the previous file.
Consider the code at the bottom of this post.
Now this isn't perfect. It has several assumptions e.g. that each file contains one function and that function is the same as the filename after striping the extension (a() is in a.js; do_something(a, b, c) is in do_something.js). It also doesn't encapsulate private variables. However, this could be worked around by adding a JSON file with these variables. Adding this JSON to the module as module.config and then passing the config object to each of the functions in the module.
In addition this still pollutes the namespace.
Question
My question is as follows:
what is a native JS way (nor do I not want a library that does this for me - jQuery included) to load functions stored across many files into a cohesive module without polluting the namespace, and ensuring that all the files are parsed before any function calls?
Code to consider (my solution)
Code directory structure:
- directory
---- index.html
---- bundle.js
---- test_module/
-------- a.js
-------- b.js
-------- log_num.js
-------- many_parameters.js
index.html
<head>
<script src="bundle.js"></script>
</head>
bundle.js
// Give JS arrays the .empty() function prototype
if (!Array.prototype.empty){
Array.prototype.empty = function(){
return this.length == 0;
};
};
function bundle(module_object, list_of_files, directory="") {
if (!list_of_files.empty()) {
var current_file = list_of_files.pop()
var [function_name, extension] = current_file.split(".")
var new_script = document.createElement("script")
document.head.appendChild(new_script)
new_script.src = directory + current_file
new_script.onload = function() {
module_object[function_name] = eval(function_name)
bundle(module_object, list_of_files, directory)
/*
nullify the function in the global namespace as - assumed - last
reference to this function garbage collection will remove it. Thus modules
assembled by this function - bundle(obj, files, dir) - must be called
FIRST, else one risks overwritting a funciton in the global namespace and
then deleting it
*/
eval(function_name + "= undefined")
}
}
}
var test_module = {}
bundle(test_module, ["a.js", "b.js", "log_num.js", "many_parameters.js"], "test_module/")
a.js
function a() {
console.log("a")
}
b.js
function b() {
console.log("b")
}
log_num.js
// it works with parameters too
function log_num(num) {
console.log(num)
}
many_parameters.js
function many_parameters(a, b, c) {
var calc = a - b * c
console.log(calc)
}
If we restrict our tools to the "native JS way", there is an import() proposal, currently at Stage 3 on the TC39 proposal process:
https://github.com/tc39/proposal-dynamic-import
System.js offers a similar approach to dynamically load modules.
Have you looked at RequireJS. From the home page:
RequireJS is a JavaScript file and module loader. It is optimized for in-browser use, but it can be used in other JavaScript environments, like Rhino and Node. Using a modular script loader like RequireJS will improve the speed and quality of your code.
It has support for Definition Functions with Dependencies
If the module has dependencies, the first argument should be an array of dependency names, and the second argument should be a definition function. The function will be called to define the module once all dependencies have loaded. The function should return an object that defines the module. The dependencies will be passed to the definition function as function arguments, listed in the same order as the order in the dependency array:
That would allow you to "split up" your module into what ever arbitrary pieces you decide and "assemble" them at load time.

NodeJS - How to reference function in one require() file from another require() file?

This is my second weekend playing with Node, so this is a bit newbie.
I have a js file full of common utilities that provide stuff that JavaScript doesn't. Severely clipped, it looks like this:
module.exports = {
Round: function(num, dec) {
return Math.round(num * Math.pow(10,dec)) / Math.pow(10,dec);
}
};
Many other custom code modules - also included via require() statements - need to call the utility functions. They make calls like this:
module.exports = {
Init: function(pie) {
// does lots of other stuff, but now needs to round a number
// using the custom rounding fn provided in the common util code
console.log(util.Round(pie, 2)); // ReferenceError: util is not defined
}
};
The node.js file that is actually run is very simple (well, for this example). It just require()'s in the code and kicks off the custom code's Init() fn, like this:
var util = require("./utilities.js");
var customCode = require("./programCode.js");
customCode.Init(Math.PI);
Well, this doesn't work, I get a "ReferenceError: util is not defined" coming from the customCode. I know everything in each required file is "private" and this is why the error is occuring, but I also know that the variable holding the utility code object has GOT to be stored somewhere, perhaps hanging off of global?
I searched through global but didn't see any reference to utils in there. I was thinking of using something like global.utils.Round in the custom code.
So the question is, given that the utility code could be referred to as anything really (var u, util, or utility), how in heck can I organize this so that other code modules can see these utilities?
There are at least two ways to solve this:
If you need something from another module in a file, just require it. That's the easy one.
Provide something which actually builds the module for you. I will explain this in a second.
However, your current approach won't work as the node.js module system doesn't provide globals as you might expect them from other languages. Except for the things exported with module.exports you get nothing from the required module, and the required module doesn't know anything of the requiree's environment.
Just require it
To avoid the gap mentioned above, you need to require the other module beforehand:
// -- file: ./programCode.js
var util = require(...);
module.exports = {
Init: function(pie) {
console.log(util.Round(pie, 2));
}
};
requires are cached, so don't think too much about performance at this point.
Keep it flexible
In this case you don't directly export the contents of your module. Instead, you provide a constructor that will create the actual content. This enables you to give some additional arguments, for example another version of your utility library:
// -- file: ./programCode.js
module.exports = {
create: function(util){
return {
Init: function(pie) {
console.log(util.Round(pie, 2));
}
}
}
};
// --- other file
var util = require(...);
var myModule = require('./module').create(util);
As you can see this will create a new object when you call create. As such it will consume more memory as the first approach. Thus I recommend you to just require() things.

Wrapper to allow a module to work with AMD/CommonJs or script tags?

I just took a shot at wrapping one of our modules that is meant to be included via a <script> tag in some boilerplate to allow optional AMD loading with requirejs.
It was quite painful and the best I could come up with is:
(function(){
var exports, jQuery;
if (typeof window.define === 'function' && typeof window.requirejs === 'function') {
exports = {};
define(['jquery'], function (jq) {
jQuery = jq;
return thisModule();
});
} else {
exports = window;
jQuery = window.jQuery;
thisModule();
}
function thisModule() {
}
})();
Notice that this is
A LOT of boilerplate
Requires you to declare dependencies in variables (only jQuery in this case thankfully) AND amd
Needs yet more code if I want to have CommonJs support.
I am primarily concerned about the second point as that one is going to be a doozy when I get beyond wrapping our core files. I'm sure there's some neat(er) wrapper implementations out there but I can't find any.
Anyone have any tips?
What you are trying to re-create something that already exists, I did exactly the same thing, coming up with a slightly different solution in my StackOverflow question.
To cut a long story short the name you need to know is "Universal Module Definition" and there's a GitHub located at https://github.com/umdjs/umd with a variety of different implementations.
Are you trying to do this for an internal module, or an external module?
If you're not require-ing in additional modules, would it be possible to build your modules assuming AMD, and then just shim out the define() function somewhere else in your code, if it's not there? Of course, you'll have to use named modules, but you'd have to basically do that anyway...
If your modules all return their exports from the define() function, it would be relatively simple, and your shimmed define function could look something like this:
//Whatever additional guards you want could be added, of course...
if (typeof(window.define) === undefined){
window.define = function(name, deps, callback){
window.myNamespace[name] = callback();
};
}
At least that way you wouldn't have to add the boilerplate to every module...
If you've got a larger library with lots of interdependent sub-modules, you're probably just going to have to commit to using Require all the way, or not, and then use your wrapper code around your whole library to handle AMD support, the way Jquery and Knockout JS do it.
After hacking on this I managed to come up with the following which seems significantly better and could even be included as a shim in a regular script tag:
A couple notes and drawbacks.
You have to replace any explicit setting on the window object with the exports object
It assumes that any dependency exists as a similarly named property on the window object (though it also makes sure to place that property there). This is generally safe enough in my case but you could easily hack in something like the requirejs paths configuration.
Actually I'm not convinced that the entire exports concept is particularly necessary, or at least not necessary in all cases.
(function () {
var define, exports = {};
if (window.define && window.define.amd) {
define = window.define;
} else {
exports = window;
define = function (name, dependencies, fn) {
var deps = [];
for (var i = 0; i < dependencies.length; i++)
deps.push(window[dependencies[i]]);
var module = fn.apply(undefined, deps);
if (!window[name]) window[name] = module;
};
}
define('mylib.interaction', ['jQuery', 'mylib.core', 'jQuery.UI'], function($, mylib) {
return /*....blah...*/;
})
})()

simple Constructor Pattern

I have worked with oop style scripting before and trying to get some kind of system with javascript. I wanted to try the most basic pattern, Constructor Pattern.
So I setup one js file called ImageView with a constructor matching the name of the js file.
function ImageView(){
alert( 'this is working');
}
Then I set up another js file called Main.js which will be the main instantiation class.
$(document).ready(function(){
var imageViewer = new ImageView();
//ImageView();
});
Now what I don't get is I can call this object ImageView without even the new constructor call. For example ImageView(). From what I gather this is just another global function and not a encapsulated class. I'm trying to get away from global crap and separate my methods and properties to their own class. What am I missing her.
Others have already answered what the difference is between using new and not using it, so I'll answer your entirely separate question: how do I avoid globals in JS?
The answer is that you can't entirely. You will always have at least one, in which you can stuff your other stuff. So for example if you wanted a "namespace" of xyz, you would do:
// global:
var xyz = {}; // or, window.xyz = {} if you are in a browser and want to be more explicit.
// "encapsulated" within the xyz "namespace":
xyz.ImageView = function () { alert("This is working"); };
There is a better solution: use the emerging concept of JavaScript modules. These are not language features (at least not in the current version of JavaScript), so they are really just hacks introduced by very clever libraries that overwrite a couple of global variables to let you avoid creating any more than the ones provided by those libraries. A good example is RequireJS, where you could do something like the following:
// In xyz.js, define the xyz module (name automatically derived from filename).
// Whatever is returned from the function you pass to define is "the xyz module"
define(function () {
return {
ImageView: function () { alert("This is working"); }
};
});
// In other code, in a different file, you can say "I require the xyz module
// to do my work," and pass require a function saying "once you've got the xyz module
// for me, here's the work I will do with it".
require(["xyz"], function (xyz) { // dependency array maps to callback arguments
// I got the xyz module, including the ImageView function it exported. Use it!
var imageViewer = new xyz.ImageView();
});
Here the clever globals RequireJS introduces are the functions define and require, but if you use them right, you can avoid ever introducing any further globals beside those two.
Inside of ImageView, the value of this will be different if you call it with new. Without, it's just another function. With new it will create a new ImageView instance and bind it to the variable this.
First off JavaScript doesn't have built in namespaces. It can only be simulated. You must also include each javascript file you plan on using.
Your right about just calling ImageView() that basically invokes the constructor on this which is next level of scope.
Using new ImageView() creates a new Object of constructor ImageView and this points to the new instance.
JavaScript is a prototype language with loose typing.

Categories