How to detect JS frameworks/libraries used in a page? - javascript

I'd like to be able to detect all the frameworks/libraries used by a page, to help understand when content is dynamically-generated etc.
I downloaded and unpacked the source for two Chrome extensions, Library Detector and Appspector. It looks like they simply call window.FUNCTION_NAME_HERE, for example:
'Backbone.js': function () {
return window.Backbone && typeof(window.Backbone.sync) === 'function';
},
'Underscore.js': function () {
return window._ && typeof(window._.identity) === 'function' &&
window._.identity('abc') === 'abc';
},
'Spine': function () {
return window.Spine;
},
'Angular': function () {
return window.angular;
},
'Ning': function () {
return window.ning;
},
'Zepto': function () {
return window.Zepto;
}
etc.
I have a few questions:
What are the identifiers for each framework (e.g. "Spine", "angular") called? Is there any way to retrieve this information via AJAX or otherwise, so I don't have to manually enter them?
I don't really understand what window.angular means, besides that it returns either the angular object or None. I know that AngularJS has loaded if the angular function is accessible through the window object, but I'm not really sure what it even means to be a member function of the window.
Why is the procedure for Backbone and Underscore different than all the others? How do you know which one to use?
I tried running both extensions on the Uber homepage, which uses React, and neither of them detected React. When I tried to console.log(window), there wasn't a React object listed either. Why is this, and how can I still detect the framework in these cases?

It looks like you have misunderstood how that code detecting libraries work, and of course that relates to understanding the window object.
In a browser javascript environment window is the global object. All variables are defined as properties of the global window object, unless they are defined within a function with the var keyword.
Let's say you visit a page that uses jQuery library, open the browser console and type jQuery. That should respond with a function, which jQuery is. Essentially jQuery is a variable defined in the global scope, and it is available as a variable by it's name, and as a property of the window object: window.jQuery.
What libraries do by default if you include them with <script> tag is define themselves as a global variable. So with Backbone.js you will have Backbone global variable defined for you, and it will be available as window.Backbone, because window is the global object.
Similarly, Angular will define angular global variable, Zepto will define Zepto, and so on.
For this reason you should be able to detect any library by the global variables it defines.
A caveat however, is that in modern javascript applications, libraries do not necessarily register a global variable. They may be defined within a scope (a function) of that application. For this reason checking window.Libraryname doesn't guarantee the page isn't using this library. And in fact it may be a very difficult task to detect a library in this case.
There are too many frameworks/libraries, so it is up on you to create the list, or find anyone who maintains one. Then you would look into what global variables that framework defines, so you could look for them as the identifier of that framework.
As I explained above, angular is the global variable, also available as window.angular. If you create a scoped angular variable, like function (){ var angular = "my angular"; }, you will still be able to get the global one with window.angular.
It is possible that the maintainers of that code became aware of two or more libraries that define Backbone global variable. And only the Backbone we know about, includes the sync function. That might be the reason they additionally check that Backbone.sync is a function. They can't just check for the Backbone.sync function without checking for Backbone first, because on non-backbone pages that would cause error.
Similarly, with Underscore, there might be many libraries that define global _ variable, so we can know for sure it is the Underscore library by checking one of it's methods in work.
As I mentioned above, libraries will not necessarily define a global variable, in which case you will not be able to detect them automatically. As an example, in a modern javascript application, you could use a library as a dependency with Browserify, or RequireJS, in which case the library most likely will not register any global variables.

Related

Modify javascript to expose a function-scoped variable

I would like to be able to expose a function-scoped variable that is part of a website's (not mine) javascript.
Here's a simplified example:
function addHooks(e, t, n, i) {
var props = { // Would like to expose this
update: function() { ... },
remove: function() { ... },
find: function() { ... },
};
...
}
In the above example, I would like to expose the props variable so that my webextension can then access this to modify the behavior of the website. Please note, that the website that serves this JS file isn't under my control and thus, I cannot simply modify the source file to export this variable. However, I'm fully open to modifying the final code that the browser runs (I just don't know how to). The javascript file containing the addHooks function appears to be added dynamically via XHR.
Although I have no idea on how to accomplish this programmatically, I have had some success setting a breakpoint and then issuing window.siteController = props in the browser's developer console. Unfortunately, manual user-intervention is not something I can package and distribute.
One method that I have been toying with is the idea of making an AJAX request for the JS file, modifying its script contents and appending it to the page.
Is there a canonical, programmatic way in which a function-scoped variable can be exposed?
if it's the props object variable that you want exposed, you could return he entire object from the functin, like in closures.
Or , you could, simple declare a the enclosing function as a constructor function, set props as this.props and then, invoke the same function elsewhere, using the new keyword.
Let me know if this helps
EDIT:
Thanks to Makyen who pointed out my error.
Apparently you might be able to do it if you re-define the function in a page script and insert it as a script element. (See the comment for two references).
Just be sure that your <script> element is inserted after the original definition and then you can either return props at the end of the function, or use this.props and use the function either as a constructor or using thecallfunction, passing an object that will get the props property added.
Old answer ( __ wrong__ apparently)
Short answer: you can't.
Full explanation: if you can't change the code of the function and you can only use the function (call it) you cannot alter its variable's scope (and good thing you can't, too. There's a reason why the variable was limited to its current scope).
And you can't change the website's JavaScript. As a Firefox or Chrome extension (and possibly the same fires to other browsers I'm not sure) you can't even access the function (let alone it's inner variables). I mean to say you can't even call it from the extension of it's in the website's code.
content scripts cannot see JavaScript variables defined by page scripts
More info and source
Firefox/Chrome runs your JavaScript code in a parallel environment, isolated from the website's environment. This is of course for security reasons. It also helps for you to be able to develop without knowing the exact inner workings of each website your code might be injected into, as you don't need to bother regarding naming conflicts (which would be impossible if it weren't for the separation environments).
The only thing you do have access to is the DOM, through which you can gather information, alter the website and even talk with the website in some cases (the website should follow a protocol you decide upon as well).

What is the correct way to wrap Angularjs code in a closure?

I have a simple application outlined in this question: Angular scope not affecting ng-show as expected
Which exposes my application via global variables, this is obviously not ideal.
I have tried wrapping the Angularjs code in a closure but I get errors in the browser telling me that the objects I am trying to access aren't accessable.
(function() {
// App code here
});
Is there a way to expose my app so with the current layout it functions correctly or do I need to change the whole struction of my app to achieve this.
I am ideally trying to reduce global variable pollution while keeping the app structure the same in both the html and js.
You are missing the call part.
Here is one format, there are a few others.
(function (a, b){
//Do stuff with `a` and `b`
})("a", "b");
Note the final pair of parens. Any parameter that you define, and later pass in are global within the scope.

Why do you need to pass in arguments to a self executing function in javascript if the variable is global?

I was looking at the code for the underscore.js library (jQuery does the same thing) and just wanted some clarification on why the window object is getting passed into the self executing function.
For example:
(function() { //Line 6
var root = this; //Line 12
//Bunch of code
}).call(this); //Very Bottom
Since this is global, why is it being passed into the function? Wouldn't the following work as well? What issues would arrise doing it this way?
(function() {
var root = this;
//Bunch of code
}).call();
I suspect the reason is ECMAScript 5 strict mode.
In non-strict mode, this IIFE
(function() {
console.log(this); // window or global
})();
logs the window object (or the global object, if you're on a node.js server), because the global object is supplied as this to functions that don't run as a method of an object.
Compare that result to
"use strict";
(function() {
console.log(this); // undefined
})();
In strict mode, the this of a bare-invoked function is undefined. Therefore, the Underscore authors use call to supply an explicit this to the anonymous function so that it is standardized across strict and non-strict mode. Simply invoking the function (as I did in my examples) or using .call() leads to an inconsistency that can be solved with .call(this).
jQuery does the same thing, and you can find several answers to your question on SO by searching along those lines.
There are two reasons to have an always-available global variable like window in local scope, both of which are for the sake of fairly minor optimizations:
Loading time. Looking up a local variable takes a tiny bit less time than looking up a global variable, because the interpreter doesn't have to look as far up the context tree. Over the length of a function the size of Underscore or jQuery, that can theoretically add up to a less-trivial amount of time on slower machines.
Filesize. Javascript minification relies on the fact that variables can be named anything as long as they're consistent. myLongVariableName becomes a in the minified version. The catch, of course, is that this can only apply to variables defined inside the script; anything it's pulling from outside has to keep the same name to work, because if you shrink window down to pr the interpreter won't know what the hell you're talking about. By shadowing it with a reference to itself, Minify can do things like:
(function(A){ B(A, {...}); A.doStuff(); //etc });})(window)
and every time you would otherwise have put window (6 characters) you now have A (1 character). Again, not major, but in a large file that needs to explicitly call window on a regular basis for scope management it can be important, and you've already got an advantage by a few characters if you use it twice. And in large, popular libraries that get served by limited servers and to people who might have lousy Internet plans, every byte counts.
Edit after reading comments on question:
If you look at what function.call() actually does, your second snippet wouldn't actually work - the this being passed in isn't an argument, it's an explicit calling context for the function, and you have to provide it to .call(). The line at the beginning of the file serves the two purposes above. The reason for setting the context explicitly with call is futureproofing - right now, anonymous functions get the global context, but theoretically that could change, be discouraged in a future ECMA specification, or behave oddly on a niche browser. For something that half the Internet uses, it's best to be more explicit and avoid the issue entirely. The this/window choice at the top level I think must have something to do with worrying about non-PC devices (i.e. mobile) potentially using a different name for their top-level object.

Why wrap every prototype "class" object with an anonymous function in JS?

Looking at this JS code by David Fowler he wraps every "class" with an anonymous self executing method where he sends in jQuery and window. I get that this is a way for ensuring that $ and window are actually the global jQuery and winndow variables you'd expect them to be.
But isn't this a bit over-protective? Should you protect yourself from someone else changing the $ and window variable - is there actually code that does that, and if so why? Also, are there other advantages to wrapping everything like this?
If I remember correctly there are some other libraries than jQuery using the $.
The concept of using function context to create local / function scopes is all about to protect your own code. This especially makes sense if you expect your Javascript code to run in an environment where multiple other (maybe even unknown) scripts may get loaded.
So, if some other Javascript code which got load before your own, assigns window.$ with some other value (it might load the prototype framework for instance), then your code is already screwed if you try to access jQuery specific things.
Another point there is the "a--hole"-effect. Someone creates a line like
window.undefined = true;
...
Now, all your checks against undefined will pretty much fail. But by explicitly creating those variables/parameters and filling them with the values you expect, you can avoid all those problems.
(function(win, doc, $, undef) {
}(window, window.document, jQuery));
Generally most top-level JavaScript code should be wrapped in an IIFE, whether they pass in particular variables or not. This prevents variables created with var from polluting the global scope.
Another small benefit is minification: if you minify your code, making window into a "local variable" by passing it in as a parameter allows the minifier to rename it. This benefit goes away if you gzip, however, so it's not a real win.
Mostly people just pick a pattern for their IIFEs and stick with it, so in his case he's decided this is they way he writes his .js files and he does so uniformly. Having a uniform standard is valuable in and of itself.
To clarify, the code can be written in slightly longer form with
(function () {
var $ = jQuery;
var window = window;
// ...
}());
The code inside the anonymous function is the the function scope, so it prevent confliction with the global variables.
Imaging that if every jQuery plugin is not wrapped in a anonymous function, then there will be a global variables hell.
It's just to preserver integrity.
$ can be Prototype, so sending jQuery as argument will save your code if someone else add a library/variable which overwrite $.
About the second argument "window", I see it as a module you want to write on.

Pass data to encapsulated javascript code

in my webapp I have a variable like this
var data = {
getItem: function(key){
...
}
}
In all of my scripts I can use
data.getItem("Test");
But how can I use it in jquery plugins? Plugins often have following structure
(function($, window, document) {
//....plugin-code
});
How do I call this kind of structure? Is it possible to use my global data variable in such plugins?
If your data variable is global, then yes you can use it anywhere, including inside jQuery plugins.
You'll need to make sure that data is defined before any self-executing functions that are going to use it.
Actually they tend to have structure
(function($) {
// plugin-code
})(jQuery);
the points being that
they can assume that $ in this scope will always be jQuery, regardless of anything else loaded that defines $ e.g. prototype
everything is defined inside this closure and so only what you choose to expose (by $.fn or $.extend) is leaked out to the outside world
Obviously if it's just your plugin in your environment where you can assume you're always running $ = jQuery then you don't need these. (Yours also has document and window: I've never seen these overridden and I'm not sure what you'd pass in as arguments here other than document and window themselves?)
Were you asking about defining data inside the plugin or pulling it in from outside the plugin scope? There's no restrictions of what you can write inside, so if you define and use it inside then your code will work exactly as befoer. If you need to access data defined inside from the outside then you'll need to leak it out somehow, e.g. adding an accessor method to one of $, document or window.
If you're pulling in data from outside the plugin scope then you can still access global variables from inside your closure, or you could pass it in as an extra argument - I don't think it'd make any difference.

Categories

Resources