At LinkedIn, we are rapidly evolving our front-end architecture with a whole lot of JavaScript: dust.js for templating, node.js for mobile, and JsTestDriver for our CI. Keeping all this JavaScript modular and managing the dependencies has become a critical issue. Unable to find a good solution that worked in the browser, we decided to build one ourselves. We are pleased to announce the result of that effort: an open source library called Inject.
Check out inject on GitHub now!
Inject is a CommonJS Compliant loader that runs in the browser and makes dependency management ridiculously easy. Read on to find out how.
The dependency management problem
Imagine you had three JavaScript modules with simple inter-dependencies: program.js depends on hello.js, which, in turn, depends on name.js. Each developer that wants to use program.js has to dig through its code, figure out its dependencies, and manually include them:
Unfortunately, with a large JavaScript codebase, the dependency graphs are much more complicated, and it can be very difficult to figure out what you need to include for any given module. Worse yet, if a module's dependencies change, you have to update the script tags on every page that imports it. JSON manifests and "wrapper" build scripts help somewhat, but eventually become unmanageable themselves.
The Inject solution
With Inject, adding program.js is a no-brainer: you just load Inject on your page, specify the root path for your modules, and then call run.
And that's it! The dependency management downstream from program.js is totally transparent. This is because the modules themselves specify their dependencies using the require keyword. For example, program.js specifies its dependency on hello.js:
In turn, hello.js specifies its dependency on name.js:
Inject finds the dependencies automatically and loads them asynchronously. If a developer changes some downstream dependency - for example, changes hello.js to depend on new-name-module.js instead of name.js - your code will keep working because Inject will automatically find and download the new dependencies on the next page load.
Features
Inject is a young library, but it already supports a significant feature list:
- Simple interface
- Modular code that doesn't pollute the global namespace
- CommonJS compliant
- Supports the AMD API
- Supports "bundled" files (multiple files concatenated)
- Supports single-file retrieval during development
- Works cross-domain
- Takes advantage of modern browser features where possible (e.g. postMessage and localStorage)
Modularity and reusability were at the heart of our decision to create Inject. LinkedIn has several dozen front-facing "properties" (pages, sites, products, modules, etc), some with overlapping JavaScript needs and some with unique ones. Before Inject, we would create one "global" JS payload with resources common to all pages, plus a page-specific payload for each property. While this kept the total number of http requests down, it was difficult to manage the dependencies. Moreover, we couldn't load things on demand, which is increasing in importance as we move more logic to the client.
Using Inject, we have a much more maintainable solution and we're excited to share it with the open source community.
Try it out!
Here's everything you need to take Inject for a test drive:
Get involved
Our goal with Inject is to build a dependency management library that presents a very simple interface but can still support the variety of complex situations that we face with a site like LinkedIn. It's a balance we're going to strive to maintain as we continue to grow the project, and we'd love some help!
Feel free to fork Inject on Github and send us some pull requests. Or better yet, apply to join our Web Development Group, and get involved with projects like Inject from day one!