I'm building my first major project with AMD modules - it's a client-side project, and I'm using require.js to load modules on-the-fly.
I'm very happy with the idea of having to explicitly import the dependencies of each module, never reaching out for global variables, no need to worry about the order in which things get loaded.
So far so good.
But what about dependencies on DOM globals such window, document, Node, etc.?
Is it cool to access these globally? I feel dirty every time I depend on document.createElement() for example, without having declared the dependency.
I want to eventually write automated tests for this stuff, I'm assuming I'll have to substitute all of these dependencies with global mocks e.g. under node.js to make the tests pass? Seems like this could turn into a dependency snafu pretty quickly.
What if I were to do the following? e.g. immediately after loading require.js:
define("window", function () { return window; });
And then explicitly import window as a module whenever it's needed:
define(["window"], function (window) { .... });
Now I should be able to substitute it quite easily.
Of course, I understand this doesn't help with third-party modules the depend on the globals.
Is there any "right" way or best practices to avoid global dependencies in my modules?
Related
I often use prototypes such as these:
requiring the same or similar functions over and over in different files.
Would it be better to require Element inside the scope or outside the scope as done so below?
I guess it's should be outside, otherwise I will be creating lots of copies of Element all over my code, No?
var Element = require("./Element.js")
var _ = function(){
this.element = new Element();
this.stuff;
}
_.prototype.setStuff = function(stuff){
this.stuff = stuff
}
_.prototype.doStuff = function(){
this.stuff();
}
module.exports = _;
Thanks.
Since this is a node.js module, there are several considerations here:
require() is synchronous. Thus you don't ever want to use it inside of live server requests because that blocks the scalability of your server. You will generally want to use require() once when a module is initialized and your server is being initialized.
Variables declared within a node.js module are scoped only to the module. Technically the module scope is inside a module function so any variables declared there are already local variables and thus don't need any extra scope protection.
Modules are cached. So, it is very fast if you do require() multiple times on the same path. After the first time when the module is actually loaded and initialized, all subsequent calls just return the same cached module handle. So, don't try to mess with the structure of your code to reduce the number of places you call require(). Write clean code and if that necessitates calling require() a few times on the same module, that's no big deal.
requiring the same or similar functions over and over in different
files. Would it be better to require Element inside the scope or
outside the scope as done so below?
You usually want to put require() statements at the highest level in your node.js modules because you want to initialize them once when the module is first initialized and you want to share that module handle with all the code in the module. If your code is complex enough that you feel like calling require() for the same module in several different places to keep your code more partitioned, then you probably should be breaking your code into separate modules anyway and let each module require() in whatever it needs itself.
I guess it's should be outside, otherwise I will be creating lots of
copies of Element all over my code,
Outside at the highest scope in your module. There's really little reason not to just load the module once and share the module handle with all the code in the module that might want to use it.
There are a few special cases where you might want to dynamically load modules only in some specific conditions at run-time only when a module is needed. This is rare and has performance consequences when doing so because of the synchronous nature of loading modules so it is rarely done. So, I didn't want to be absolute in my earlier recommendation, but also wanted to explain that loading something only on-demand is rare and has consequences.
Here Element should be defined inside the _ function scope unless it is defined inside a IIFE.
If it is defined inside IIFE then there won't be any issue else Element will be exposed into window scope and using console we can override the Element function.
Hope this helps you.
For reasons that aren't relevant to the question, my coworker needs to load a script that uses the Universal Module Definition pattern. Our environment usually has an AMD tool loaded, but for more irrelevant reasons, my coworker needs the script to define a global rather than registering a module through AMD. The approach that is currently checked in on their branch is something along the lines of this:
<script>
var backupDefine = define;
define = null;
</script>
<script src="../path/to/some/script/using/UMD.js"></script>
<script>
define = backupDefine;
backupDefine = null;
</script>
My question is: Is this a horrible idea? Is there a guarantee in the way browsers load scripts from script tags that will ensure nothing other than loading the UMD-based script will happen between undefining define and restoring define? We have a very large, very heavily async asset load primarily based around AMD modules, so what I am concerned with is an AMD module attempting to define itself in that intermittent state where define is currently not defined.
So long as UMD.js in no way modifies the scripts in the DOM, those scripts are guaranteed to execute in the order that they're authored in before any asynchronous callbacks that may have been queued before the first script executes.
I see this as a bad idea and spec breaking even if the case where define is always necessary is rare or even non-existent due to <script> load order considering your case. In an AMD environment, define, require and the like should basically be treated as first class keywords since their goal is to help you to remove globals.
Realistically, you're treading into undefined behavior as far as I can tell and writing code that is hard to maintain. You're relying on a tricky case with a spec where you have to undefine something and them immediately redefine it hoping that nothing tried to use it in the mean time. I'd say that that's "unsafe".
If you really need this to happen, I'd comment and document it heavily to make sure a future developer doesn't misunderstand what you're doing. However, I would say the better course of action is to rewrite the UMD.js file so that you export your global your own way. Rhetorically, why are you trying to use UMD if you don't want it to UMD things?
You're writing this module to support AMD through UMD but then you say that you don't want it to be used by AMD. Rewrite the file to just export to the global and avoid messing with define before you accidentally conflict with an additional library that does something tricky with define.
I am looking for a way to dispatch events globally and inside requireJS modules using javascript or jquery.
I would like to be able to say within my js files:
dispatchEvent(myCustomEventWithSomeData);
and then in some other part of the application add a listener like so:
addEventListener(“type Of Event”, executeThisFunction);
is this possible using jquery? Or any other means? And will a potential solution work within requireJS modules which are not global javascript objects?
Also, How can I create an event that bubbles. So that if I want an event to execute only in a specific section of the code it is not dispatched globally?
Yes, this is something I typically setup very early within my own applications. Now, how you deal with your events is going to be very dependent on what library or techniques you decide to use, but the core concepts will remain the same.
Personally, I think PostalJS is the cock of the walk, so I'm going to use that as an example here. I'm not going to include too much code because it would be mostly ceremony and boilerplate, but I hope you'll get the idea.
One, you'll want to create something like a global App object for your events to rest on. Overall this is a good practice when modularizing your JS code - you'll want something which acts as a broker between modules. It can be very plain and basic:
define(function() {
var App = {};
return App;
});
Now, this module should be loaded into something which begins to populate it. You can get away with not doing this, for a while, but I find eventually circular dependencies tend you bite you in the ass. So I recommend including this in something akin to your "main" module. From there, include your event system and add it to App.
define(['app', 'events'], function(App, Events) {
App.events = new Events();
});
Now you have a nice, lightweight object you can include in other modules which shares the same Events object. So lets say you have a sidebar:
define(['app'], function(App) {
// User has clicked the sidebar
App.events.publish('sidebar.clicked'); //
});
And, oh I don't know, perhaps clicking the sidebar makes a dinosaur appear, so in your dinosaur module, you'd listen/subscribe by doing the following:
define(['app'], function(App) {
App.events.subscribe('sidebar.clicked', showDinosaur);
});
Having a lightweight object you can share between modules I've found is key to a successful modularized JS architecture. I use this in my own projects as a global object store, a container for my WebSocket messaging layer, and other things I don't want to need to explicitly include individually in each module.
I have 3000+ lines of javascript that I need to get into a sensible/maintainable structure. I have chosen to use requireJS as it has been recommend to me by a few people. I have a bunch of variables that are used throughout the application and need to be available everywhere. I also have a bunch of functions that need to be available everywhere. Apart from these two dependencies most of the code can be divided off into their own modules.
I am having trouble understanding how to manage my main variables so that if one module of code makes changes to the variables the rest of the JS modules will see that change. I think I need to see a few examples that demonstrate how requireJS is intended to work on a larger scale that the examples in the documentation.
If anyone is an experienced requireJS user I would love the hear your tips!
The whole point of RequireJS is to avoid the need for these global variables and global functions.
Can't you wrap those globals into a module, then depend on it in your other modules?
For example, a RequireJS modularized Dojo may be something like:
dojo/cache module
dojo/string module (requires dojo/cache)
dojo/date module (requires dojo/string)
dojo/cookie module (requires dojo/string)
:
:
dojo module (requires everything above, make them all into sub-objects, say, e.g. dojo.cache, dojo.string, dojo.date etc.)
user module #1 (requires dojo)
user module #2 (maybe only requiring dojo/string)
RequireJS gives you better options for encapsulating modules, but it doesn't change Javascript itself at all. As a transition strategy, you can still define your globals inside the function block. Depending on the module that contains these definitions will ensure that it has run before the dependent modules.
Next step would be to assign those methods to an object other than window, and then use that object through the variable received from RequireJS module dependency.
Hopefully by the time you've done this, you might have some insight into a cleaner solution. I refactored (and still am) a single-file project into several files, including optional plug-ins, although I did most of it before adding RequireJS to the mix.
See the RequireJS documentation:
Defining a module
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 dependencies will be passed to the definition function as function arguments
define(["./cart", "./inventory"], function(cart, inventory) {
// ...
return { ... };
}
);
So I think you can define() your main module like all other modules and make the submodules depend on that main module. Then the module object is passed as an argument to the definition function of a submodule. You don't have to use global variables.
If you want to share information between modules, attach the information to the module object, and have the other modules rely on that module, and check its property.
If you have existing code, you can assign to window.x to provide a global x while you are cleaning it up.
I know that global variables are bad.
But if I am using node's module "util" in 40 files in my framework, isn't it better to just declare it as a global variable like:
util = require('util');
in the index.js file instead of writing that line in 40 files?
Cause I often use the same 5-10 modules in each file, that would save a lot of time instead of copy paste all the time.
Isn't DRY good in this case?
You could just have a common module.
common.js:
Common = {
util: require('util'),
fs: require('fs'),
path: require('path')
};
module.exports = Common;
app.js:
var Common = require('./common.js');
console.log(Common.util.inspect(Common));
Each module is supposed to be independent. The require doesn't cost anything anyways after the first one for each module.
What if you wanted to test one module alone? You'd be having a lot of issues because it wouldn't recognize some "global" requires that you have in your app.
Yes, globals are bad, even in this case. Globals almost always ruin: testability, encapsulation and ease of maintenance.
Updated answer Jan. 2012
The global object is now a global inside each module. So every time you assign to a global variable (no scope) inside a module, that becomes part of the global object of that module.
The global object is therefore still not global, and cannot be used as such.
Updated Dec. 2012
The global object now has the global scope within the application and can be used to store any data/functions that need to be accessed from all modules.
global.util = require('util');
There's a section about global objects in the node documentation.
However, globals should be used with care. By adding modules to the global space you reduce testability and encapsulation. But there are cases where using this method is acceptable. For example, I add functions and objects to the global namespace to use within my unit test scripts.
I'm confused by the answers in this thread.
I am able to do this...
File: test.js
global.mytest = {
x: 3,
y: function() { console.log('Works.'); }
};
File: test2.js
console.log('Does this work?');
mytest.y();
File: server.js
require('test.js');
require('test2.js');
And it seems to work as the question needed. The first require places the mytest object into the global scope, then the second require can access that object without any other qualifiers.
I was trying to figure this out (which brought me to this thread from a Google search) and I wanted to post what seems to work for me now. Maybe things have changed since the original answers.
I have successfully been using the process object for passing around my configuration object. While in theory suffering from the exact same issues as mentioned above (encapsulation, testability and so forth) it works fine when using only non-state modifying properties (a hash table with primitives, basically).
If you wrap your modules in blocks (e.g. anon functions) you can bind to a local name (via parameter or 'var') and then have any arbitrary long (perhaps "package" labeled) name you want (if you even need a global at this point).
For instance, my modules often look similar to:
;(function ($, $exp, other) {
$(...)
other.xyz()
$exp.MyExportedObject = ...;
})(jQuery, window, some_module.other_expression) // end module
I use jQuery with noConflict, this the former, and the latter show you can do this for any expression -- global, require, computed, in-line, whatever... this same "wrapping" approach can be used to eliminate all (or almost all) "special named" globals -- globals must exist at some level, however, removing potentially conflicts is a very big win.