Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 706
user386508 Avatar asked Jul 08 '10 10:07

user386508


People also ask

What is dependency in JavaScript?

A dependency is some third-party code that your application depends on. Just like a child depends on its parent, your application depends on other people's code. A piece of code becomes a true dependency when your own application cannot function without it.

What is dependency management in npm?

Most users of npm (or at least most package authors) eventually learn that, unlike other package managers, npm installs a tree of dependencies. That is, every package installed gets its own set of dependencies rather than forcing every package to share the same canonical set of packages.

Which is better Yarn or npm?

While NPM installs packages sequentially, Yarn performs parallel installation resulting in better speed and performance. NPM has tried to fix vulnerabilities, but still, Yarn is considered more secure than NPM. Yarn also comes with advanced features like Plug'n'Play and Zero-Install.


2 Answers

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.

like image 139
bobince Avatar answered Sep 28 '22 03:09

bobince


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.

like image 20
Chris Avatar answered Sep 28 '22 03:09

Chris