Building a JavaScript library, why use an IIFE this way? - javascript

I have noticed a lot of libraries use this style below to define their library. I also notice that the first self invoking function has something to do with Require.js or AMD systems, they always have factory as an argument, I will look more into Require.js, always been into Browserify.
Why is the main code passed into the end of the first self invoking function inside parentheses, is this is a closure, or just considered an anonymous function, I will dig deeper into both. What are the benefits to this? It looks like inside the closure the author passes a string, this, and a callback.
Will this give my library a clean safe way to globalize the main object in this example below Please?
(function( globalName, root, factory ) {
if ( typeof define === 'function' && define.amd ) {
define( [], factory );
}
else if ( typeof exports === 'object' ) {
module.exports = factory();
}
else{
root[globalName] = factory();
}
}('Please', this, function(){
I am trying to dig really deep into JavaScript and create my own small MVC architecture, I don't want to hear I am silly or its been done before, I want to challenge myself and learn.
If there are any great resources for creating a JavaScript library or even better an MVC library I would love to know.

This code pattern is called Universal Module Definition (UMD). It allows you to make your JavaScript library usable in different environments. It provides three ways of defining modules:
Asynchronous Module Definition (AMD), implemented by RequireJS and Dojo Toolkit.
define( [], factory );
CommonJS — NodeJS modules.
module.exports = factory();
Assigning module to the global object, for example window in browsers.
root[globalName] = factory();
The IIFE has three parameters: globalName, root and factory.
globalName is the name of your module. It applies only to the third way of defining a module, i.e. assigning your module object to the global variable. For example, if you set this parameter to "myAwesomeModule" and use the code in browser (without AMD), you can access your module using myAwesomeModule variable.
root is the name of global object. Obviously, it also applies only to the third way of defining a module. Usually this is passed as this parameter, because this is a reference to window in browser. However, this doesn't work in strict mode. If you want your code to work in strict mode, you can replace this with typeof window !== "undefined" ? window : undefined.
Finally, factory is an anonymous function, which should return your module as object.
See also:
What is the (function() { } )() construct in JavaScript?
What Is AMD, CommonJS, and UMD?

This is an example of Universal Module Definition (UMD). It is a technique to make a JS module compatible with the three popular JS module specs:
Asynchronous Module Definition (AMD, used by Require.js)
define('name', [ /* dependencies */ ], factory);
CommonJS (Node.js ecosystem)
module.exports = object;
Global exports (for example, on window in the browser)
global['name'] = object;
UMD wraps a factory function responsible for creating the object to be exported and passes it as an argument to an immediately invoked function expression (IIFE), as in the snippet you pasted. The IIFE is responsible for detecting the module environment, and exporting the object created by the factory in an appropriate way. The pattern is as follows:
(function (name, root, factory) {
// detect the module environment and
// export the result of factory()
})('name', this, function () {
// module code
// return the object to be exported
});
Many transpilers and build tools generate this wrapper automatically.

Related

This requireJS thing has me confused

Hi i am trying to understand this steganography tool https://github.com/petereigenschink/steganography.js.
I am using this in my react project. The bit about RequireJS has me already confused. Can i turn this to a normal, not so scary javascript?
;(function (name, context, factory) {
// Supports UMD. AMD, CommonJS/Node.js and browser context
if (typeof module !== "undefined" && module.exports) {
module.exports = factory();
} else if (typeof define === "function" && define.amd) {
define(factory);
} else {
context[name] = factory();
}
})("steg", this, function () {}
I need to be able to use this function or whatever it is in my App.js file. Any pointers please?
This is the error that react dev server throws:
Failed to compile.
./src/steganography.js
Line 12: 'define' is not defined no-undef
Line 13: 'define' is not defined no-undef
Since javascript didn't originally include any way of doing modules (ie, to link together code from multiple files), several different approaches have been invented for ways to do so. That block of code is just trying to conform to all of them, so that the codebase will work regardless of which module approach the consumer is using.
The outer part is an Immediately Invoked Function Expression. This is an anonymous function which gets created and then immediately called. In this code, its main purpose is to isolate any variables inside the expression, and thus make it impossible for them to accidentally become global variables.
Inside the IIFE, it has some checks to figure out what kind of module system is being used, so that it can produce the correct output to be imported.

Call of anonymous function (vanilla js, pure js, no jquery)

I want to grab browser version and OS from useragent via js - this is a practicing example (cause yes - I know - feature detection is how you do it properly ;).
I stumbled across a little library that does so and now I'm trying to understand whats going on.
See this Codepen: http://codepen.io/anon/pen/gPWZGE?editors=001
obviously by running bowser.version - you get the version extracted from the browsers useragent. However the function bowser itself is an anonymous function - even though I can access elements within this function which has to do with this part of the code
!function (name, definition) {
var module;
var define;
if (typeof module != 'undefined' && module.exports) module.exports = definition();
else if (typeof define == 'function' && define.amd) define(definition);
else this[name] = definition();
}
To be honest I have hardly any idea whats going on there - can someone please explain what those lines are doing?
Thanks a lot
Ok, so step by step ...
first you have an IIFE
!function( name, definition ) {
// some code
}( 'bowser', function(){
// your module code
});
this calls the first function immediately with two parameters: the name of the module (here "bowser") and the actual definition function. In that definition function you create the module: You define any objects, properties and whatever else it needs to work. Important point is: You interface (the view the "outside" has on your module, has to be returned by that defintion function (in your codepen this is line 282: return bowser;).
The outer function then determines, how to publish your module:
First it looks for a CommonJS environment:
typeof module != 'undefined' && module.exports
This would be used, e.g., inside NodeJS. If it found the respective objects, it will export your module as a CommonJS module: module.exports = definition().
If this was not a CommonJS environment, the script looks, if it is an AMD (for example, requireJS):
typeof define == 'function' && define.amd
Again, if that matches, the module is exported as a AMD module: define(definition).
Finally, if this is neither CommonJS nor AMD, the script assumes it is a (vanilla) browser or something similar and just attaches the module to the global namespace:
this[name] = definition();
Note, that each time the definition function is called and the return value is exported as a module. This is why your definition function has to return the module interface.

Javascript UMD - where/how are root, factory defined?

In a simple UMD setup like the following, where/how are root and factory defined?
(function (root, factory) {
// environment detection here
console.log(root);
console.log(factory);
}(this, function (b) {
// module definition here
}));
I'm arriving late to the UMD party, so please forgive me if this is a silly question... but if I run the above code, I see root returns the window object, and factory returns a function. So is the first argument (in this case, root) always defined as the window object? What about the second? Are they implemented the same cross browsers? I'm searching high and low for a spec or reference to back this up and can't find one... there are lots of blog posts about the wonders of UMD, but I can't find any explanation of how this magically works.
Does anybody have a simple explanation for how or why this works?
This is an IIFE (immediately-invoked function expression), which is nicely explained here.
To put it simply you are creating a function that is only called once and you are passing to it two arguments, this and function(b). These two arguments are named root and factory inside the IIFE body.
The benefit is that the body of IIFE works in isolation, in a "private scope". Variable names outside of it have no effect and you have no conflict problems.
Now, back to your question, you are passing this as an argument. This is the global object. In a browser it is window and in Node it is global. In both cases in the IIFE you are referring to it as root and in your module as b. What ever you call it, another advantage is that your minifier can pick it up and translate it to c or something else without breaking your code. This is in contrast with a normal situation, where window or document or any module names can't be minified.
You are also passing a function, which is named factory. This is your module. Without AMD or CommonJS, you would usually do:
(function (root, factory) {
root.myModuleName = factory(root);
}(this, function (b) {
// module definition here
}));
This will create your module and attach it to the global object, so that you can use it. With only one argument in factory method, you normally need to pass the global object. You can also use more arguments to pass any module dependencies:
(function (root, c, factory) {
root.myModuleName = factory(root, c);
}(this, jQuery, function (b, $) {
// module definition here
// You refer to jQuery as $ without having to call noConflict
}));
Not always. root could be global in Node or in the browser it could be window. It is passed by providing this. factory is the function that is after this with the argument b. That is where the application code ("business logic" or "meat") is.
UMD should work in any JavaScript environment, it just adapts the logic for what ever module loading system is present.

Should you use IIFE with RequireJS

It seems to be that if you are using RequireJS and you use define and require, then there is not point of using IIFE as well, since each module is already wrapped in a define/require. Is that the case?
In other words, does this code
define(['app'], function(app)
{
app.run();
});
has any difference/advantage to
(function() {
define(['app'], function(app)
{
app.run();
});
})();
Generally, you don't need to use an IIFE with RequireJS but sometimes you should.
If you use the usual define([... deps ...], function (...) {...}) format then you are only reading define from the global space and everything else you do is encapsulated inside the function you pass to define. With or without an IIFE, you can leak what you want to leak and keep private what you want to keep private.
The IIFE will typically be desirable if you are writing code that you want to be able to run with and without RequireJS. For instance, this:
(function () {
'use strict';
function factory () {
// Build our module...
return something;
}
if (typeof define === 'function' && define.amd)
define([], factory); // AMD environment: call define.
else
window.Foo = factory(); // Otherwise, leak into the global space.
})();
Popular libraries (e.g. jQuery) often have code like this that allows using them with RequireJS (or another AMD loader) and with script elements. This is extremely common. Using the IIFE allows to keep the factory function out of the global space.
The define() function is in Global scope anyway, so calling it inside an IIFE doesn't make a difference at all and it's kind of redundant.
It would be different if you put code outside of the define callback but you shouldn't do that because each file should represent an encapsulated module.
The only time I can think of using an IIFE with RequireJS might be when I'm configuring my application by calling require.config() before initialization; but even then if I'm just calling require.config() and don't have any code on the outside, I still wouldn't use an IIFE.
In this example here there wasn't a need to use an IIFE: https://github.com/vasilionjea/bower-requirejs-starter/blob/master/local/js/main.js
I hope that answers your question.

Why in Firefox Addon the imported objects can not access the importers' imported modules?

For clarification, please consider the following simplified example:
one.js
Components.utils.import('resource://gre/modules/Services.jsm');
let obj = {
init: function() {
Components.utils.import('chrome://myaddon/modules/two.jsm', this);
}
// code here has access to Services.jsm
}
two.js
this.EXPORTED_SYMBOLS = ['abc'];
this.abc = {
// abc is imported into obj()
// however as part of obj (), abc{} does not have access to Services.jsm
}
I know that this is how it works but the question is why?
Result is that for example Services.jsm has to be imparted in every module.
Although Firefox caches the modules and there isn't much of a performance difference, I would like to know if the repeated importation can be avoided?
Like #felix-kling already mentioned, that's due to module level isolation and it makes a lot of sense if you think about it. If it was otherwise not only Services would be seen by other modules, but also abc.
There is another important reason, though:
Since JS code modules are initiated once and cached after that, what would happen if you imported two.jsm twice, once from a module already having imported Services.jsm and once from another module not having done so? Now two.jsm "seeing" Services would depend on which of the other modules was imported first! Which would be extremely nasty.
In that context, your comment about "abc is imported into obj()" is wrong. Your code actually imports abc into the top-level scope. Cu.import will always import into the top-level scope, unless you explicitly specify another scope to import to.
"abc" in this; // false
"abc" in obj; // false
obj.init();
"abc" in this; // true
"abc" in obj; // false!
If you wanted to import two.jsm into obj, you'd need to call Cu.import with a second argument.
let obj = {
init: function() {
Components.utils.import('chrome://myaddon/modules/two.jsm', this);
}
};
"abc" in this; // false
"abc" in obj; // false
obj.init();
"abc" in this; // false
"abc" in obj; // true
But that does not affect the visibility of Services, of course.
It would be helpful I guess, if Cu.import just auto-imported some modules you'd import anyway, such as Services.jsm and XPCOMUtils.jsm. But this does not and likely will not ever happen due to legacy reasons and backward-compatibility constraints. (E.g. I had code break that imported const {Promise} = Cu.import(..., {}); because ES6 added a default Promise global...; that kind of backward-compatibility issues/constraints).
Alternatives?
Well, the obvious one is not to use Cu.import for your own stuff, but use something else. A bunch of add-ons, incl. all SDK add-ons of course, have their own CommonJS-style require() implementation.
You can actually re-use the SDK loader, without using the SDK, or with only using selected parts of the SDK if you like. See the loader documentation. I know that Erik creates a loader in the otherwse non-SDK Scriptish add-on.
You can write your own custom loader based on the subscript loader and maybe Sandbox. E.g. I did so in my extSDK boilerplate (all global symbols in loader.jsm == loader.jsm::exports will be visible to each required module).
But doing so may require a quite bit of extra work, extra knowledge, and effort to port existing JS code modules to require() based modules.

Categories

Resources